diff --git a/CHANGELOG.md b/CHANGELOG.md index 9560551333..9748fea95f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -28,6 +28,7 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm ### Fixes - Fix `toggle` changing width during animation in Teams theme @mnajdova ([#2189](https://github.com/microsoft/fluent-ui-react/pull/2189)) +- Update `SplitButton` styles in Teams theme [redlines] @notandrew ([#2108](https://github.com/microsoft/fluent-ui-react/pull/2108)) - Fix `Popup` positioning in multiple cases @layershifter ([#2187](https://github.com/microsoft/fluent-ui-react/pull/2187)) - Fix click outside in `Popup` when `trigger` is not defined @layershifter ([#2202](https://github.com/microsoft/fluent-ui-react/pull/2202)) diff --git a/docs/src/examples/components/SplitButton/Slots/SplitButtonToggleButtonExample.shorthand.tsx b/docs/src/examples/components/SplitButton/Slots/SplitButtonToggleButtonExample.shorthand.tsx index 08ac8dd7be..2b74639249 100644 --- a/docs/src/examples/components/SplitButton/Slots/SplitButtonToggleButtonExample.shorthand.tsx +++ b/docs/src/examples/components/SplitButton/Slots/SplitButtonToggleButtonExample.shorthand.tsx @@ -18,7 +18,10 @@ const SplitButtonExampleToggleButtonShorthand = () => { 'aria-describedby': 'instruction-message-icon', }} toggleButton={{ - icon: open ? 'triangle-up' : 'triangle-down', + icon: { + name: 'icon-menu-arrow-down', + style: open ? { transform: 'rotate(180deg)' } : null, + }, 'aria-label': 'more options', }} onOpenChange={(e, { open }) => setOpen(open)} diff --git a/docs/src/examples/components/SplitButton/Types/SplitButtonExampleSmall.shorthand.tsx b/docs/src/examples/components/SplitButton/Types/SplitButtonExampleSmall.shorthand.tsx new file mode 100644 index 0000000000..8a6de91b3a --- /dev/null +++ b/docs/src/examples/components/SplitButton/Types/SplitButtonExampleSmall.shorthand.tsx @@ -0,0 +1,26 @@ +import * as React from 'react' +import { SplitButton } from '@fluentui/react' + +const SplitButtonExampleSmallShorthand = () => ( + <> + alert('button was clicked')} + /> + + +) + +export default SplitButtonExampleSmallShorthand diff --git a/docs/src/examples/components/SplitButton/Types/index.tsx b/docs/src/examples/components/SplitButton/Types/index.tsx index ed770049b6..4b8483b071 100644 --- a/docs/src/examples/components/SplitButton/Types/index.tsx +++ b/docs/src/examples/components/SplitButton/Types/index.tsx @@ -14,6 +14,11 @@ const SplitButton = () => ( description="A SplitButton can be formatted to show primary level of emphasis." examplePath="components/SplitButton/Types/SplitButtonExamplePrimary" /> + ) diff --git a/packages/react/src/components/SplitButton/SplitButton.tsx b/packages/react/src/components/SplitButton/SplitButton.tsx index b8f54fcaf6..5aadd8f334 100644 --- a/packages/react/src/components/SplitButton/SplitButton.tsx +++ b/packages/react/src/components/SplitButton/SplitButton.tsx @@ -20,6 +20,7 @@ import { AutoControlledComponent, RenderResultConfig, ShorthandFactory, + SizeValue, } from '../../utils' import Button, { ButtonProps } from '../Button/Button' import MenuButton, { MenuButtonProps } from '../MenuButton/MenuButton' @@ -29,6 +30,7 @@ import { PopupProps } from '../Popup/Popup' export interface SplitButtonSlotClassNames { toggleButton: string + size?: SizeValue } export interface SplitButtonProps @@ -84,6 +86,9 @@ export interface SplitButtonProps /** A split button can be formatted to show different levels of emphasis. */ secondary?: boolean + /** A split button can be sized */ + size?: SizeValue + /** Shorthand for the toggle button. */ toggleButton?: ShorthandValue } @@ -118,6 +123,7 @@ class SplitButton extends AutoControlledComponent, onMenuItemClick: PropTypes.func, onOpenChange: PropTypes.func, open: PropTypes.bool, + size: customPropTypes.size, primary: customPropTypes.every([customPropTypes.disallow(['secondary']), PropTypes.bool]), secondary: customPropTypes.every([customPropTypes.disallow(['primary']), PropTypes.bool]), toggleButton: customPropTypes.itemShorthand, @@ -125,7 +131,7 @@ class SplitButton extends AutoControlledComponent, static defaultProps = { accessibility: splitButtonBehavior, - as: 'span', + as: 'div', toggleButton: {}, } @@ -174,7 +180,7 @@ class SplitButton extends AutoControlledComponent, const { button, disabled, menu, primary, secondary, toggleButton } = this.props const trigger = Button.create(button, { defaultProps: () => ({ - styles: styles.button, + styles: styles.menuButton, primary, secondary, disabled, @@ -202,9 +208,10 @@ class SplitButton extends AutoControlledComponent, )} {Button.create(toggleButton, { defaultProps: () => ({ + styles: styles.toggleButton, className: SplitButton.slotClassNames.toggleButton, disabled, - icon: 'icon-arrow-down', + icon: 'icon-menu-arrow-down', iconOnly: true, primary, secondary, diff --git a/packages/react/src/themes/teams/components/SplitButton/splitButtonStyles.ts b/packages/react/src/themes/teams/components/SplitButton/splitButtonStyles.ts index 6c97cf2472..0b49754197 100644 --- a/packages/react/src/themes/teams/components/SplitButton/splitButtonStyles.ts +++ b/packages/react/src/themes/teams/components/SplitButton/splitButtonStyles.ts @@ -1,51 +1,95 @@ import { ICSSInJSStyle } from '../../../types' import getBorderFocusStyles from '../../getBorderFocusStyles' -import SplitButton from '../../../../components/SplitButton/SplitButton' +import getIconFillOrOutlineStyles from '../../getIconFillOrOutlineStyles' const splitButtonStyles = { - button: ({ variables: v }): ICSSInJSStyle => ({ - border: 0, + menuButton: ({ props: p, variables: v }): ICSSInJSStyle => ({ + borderTopRightRadius: 0, + borderBottomRightRadius: 0, + borderRightWidth: 0, padding: v.padding, + ...(p.size === 'small' && { + height: v.smallDimension, + padding: v.smallPadding, + minWidth: v.smallMinWidth, + boxShadow: v.smallBoxShadow, + }), + ':focus-visible': { - '::before': { border: 0 }, - '::after': { border: 0 }, + borderRightWidth: 0, + + ':before': { + borderRightWidth: 0, + }, + + ':after': { + borderRightWidth: 0, + }, + }, + + ':active': { + animationName: 'unset', + animationDuration: 'unset', }, - ':active': { backgroundColor: v.backgroundColorActive }, }), + + toggleButton: ({ props: p, variables: v, theme: { siteVariables } }): ICSSInJSStyle => ({ + borderTopLeftRadius: 0, + borderBottomLeftRadius: 0, + borderColor: v.borderColor, + ...getIconFillOrOutlineStyles({ outline: true }), + + ...(p.primary && { + borderWidth: `0 0 0 ${siteVariables.borderWidth}`, + borderColor: v.borderColorPrimary, + }), + + ...(p.disabled && { + borderWidth: `0 0 0 ${siteVariables.borderWidth}`, + borderColor: v.borderColorDisabled, + }), + + ...(p.size === 'small' && { + height: v.smallDimension, + width: v.smallDimension, + minWidth: v.smallMinWidth, + boxShadow: v.smallBoxShadow, + }), + + ':focus-visible': { + ':before': { + borderLeftWidth: 0, + }, + + ':after': { + borderLeftWidth: 0, + }, + }, + + ':active': { + animationName: 'unset', + animationDuration: 'unset', + }, + }), + root: ({ props: p, variables: v, theme: { siteVariables } }): ICSSInJSStyle => { - const { borderWidth } = siteVariables const borderFocusStyles = getBorderFocusStyles({ siteVariables, }) return { - border: `${borderWidth} solid ${v.borderColor}`, borderRadius: v.borderRadius, position: 'relative', display: 'inline-block', - [`& .${SplitButton.slotClassNames.toggleButton}`]: { - borderRight: 0, - borderTop: 0, - borderBottom: 0, - }, - ':focus-within': { boxShadow: 'none', - ...(p.isFromKeyboard - ? { - [`& .${SplitButton.slotClassNames.toggleButton}`]: { - color: p.primary ? v.primaryColorFocus : v.colorFocus, - backgroundColor: p.primary ? v.primaryBackgroundColorFocus : v.backgroundColorFocus, - borderColor: siteVariables.colors.white, - }, - - color: v.colorFocus, - backgroundColor: v.backgroundColorFocus, - ...borderFocusStyles[':focus-visible'], - } - : { ':active': { backgroundColor: v.backgroundColorActive } }), + ...(p.isFromKeyboard && { + // make sure focus is coming from keyboard before applying the focus styles + // otherwise focus state is applied only to the button and not the toggle + ...borderFocusStyles[':focus-visible'], + }), }, } }, diff --git a/packages/react/src/themes/teams/components/SplitButton/splitButtonVariables.ts b/packages/react/src/themes/teams/components/SplitButton/splitButtonVariables.ts index 98880ef726..3b7730a7cf 100644 --- a/packages/react/src/themes/teams/components/SplitButton/splitButtonVariables.ts +++ b/packages/react/src/themes/teams/components/SplitButton/splitButtonVariables.ts @@ -1,29 +1,28 @@ import { SiteVariablesPrepared } from '../../../types' - import { pxToRem } from '../../../../utils' export interface SplitButtonVariables { borderRadius: string - backgroundColorFocus: string - boxShadow: string + borderColorPrimary: string borderColor: string - colorFocus: string - primaryBackgroundColorFocus: string - primaryColorFocus: string + borderColorDisabled: string + smallDimension: string + smallPadding: string + smallMinWidth: string + smallBoxShadow: string padding: string - iconMargin: string } export default (siteVars: SiteVariablesPrepared): SplitButtonVariables => { return { borderRadius: siteVars.borderRadius, - backgroundColorFocus: siteVars.colors.grey[200], - boxShadow: siteVars.shadowLevel1, - borderColor: siteVars.colors.grey[200], - colorFocus: siteVars.colors.grey[750], - primaryBackgroundColorFocus: siteVars.colors.brand[800], - primaryColorFocus: siteVars.colors.white, + borderColor: siteVars.colorScheme.default.border, + borderColorPrimary: siteVars.colors.brand[500], + borderColorDisabled: siteVars.colorScheme.brand.foregroundDisabled, + smallDimension: pxToRem(24), + smallPadding: `0 ${pxToRem(8)}`, + smallMinWidth: '0', + smallBoxShadow: 'none', padding: `0 ${pxToRem(16)}`, - iconMargin: `0 0 ${pxToRem(8)} 0`, } }