diff --git a/change/@fluentui-react-button-d331f16a-d205-4660-bec8-f39b700877cc.json b/change/@fluentui-react-button-d331f16a-d205-4660-bec8-f39b700877cc.json new file mode 100644 index 00000000000000..180016873d22ee --- /dev/null +++ b/change/@fluentui-react-button-d331f16a-d205-4660-bec8-f39b700877cc.json @@ -0,0 +1,7 @@ +{ + "type": "prerelease", + "comment": "Button: Exporting classNames of individual slots.", + "packageName": "@fluentui/react-button", + "email": "Humberto.Morimoto@microsoft.com", + "dependentChangeType": "patch" +} diff --git a/packages/react-button/etc/react-button.api.md b/packages/react-button/etc/react-button.api.md index 0c8f403eb0b693..4de468a00f3ece 100644 --- a/packages/react-button/etc/react-button.api.md +++ b/packages/react-button/etc/react-button.api.md @@ -10,12 +10,16 @@ import type { ComponentState } from '@fluentui/react-utilities'; import { ForwardRefComponent } from '@fluentui/react-utilities'; import * as React_2 from 'react'; import type { Slot } from '@fluentui/react-utilities'; +import type { SlotClassNames } from '@fluentui/react-utilities'; // @public export const Button: ForwardRefComponent; // @public (undocumented) -export const buttonClassName = "fui-Button"; +export const buttonClassName: string; + +// @public (undocumented) +export const buttonClassNames: SlotClassNames; // Warning: (ae-forgotten-export) The symbol "ButtonCommons" needs to be exported by the entry point index.d.ts // @@ -37,7 +41,10 @@ export type ButtonState = ComponentState & ButtonCommons & { export const CompoundButton: ForwardRefComponent; // @public (undocumented) -export const compoundButtonClassName = "fui-CompoundButton"; +export const compoundButtonClassName: string; + +// @public (undocumented) +export const compoundButtonClassNames: SlotClassNames; // @public (undocumented) export type CompoundButtonProps = ComponentProps> & Partial; @@ -55,7 +62,10 @@ export type CompoundButtonState = ComponentState & Omit; // @public (undocumented) -export const menuButtonClassName = "fui-MenuButton"; +export const menuButtonClassName: string; + +// @public (undocumented) +export const menuButtonClassNames: SlotClassNames; // @public (undocumented) export type MenuButtonProps = ComponentProps & Partial>; @@ -86,7 +96,10 @@ export const renderSplitButton_unstable: (state: SplitButtonState) => JSX.Elemen export const SplitButton: ForwardRefComponent; // @public (undocumented) -export const splitButtonClassName = "fui-SplitButton"; +export const splitButtonClassName: string; + +// @public (undocumented) +export const splitButtonClassNames: SlotClassNames; // @public (undocumented) export type SplitButtonProps = ComponentProps & Omit & Omit; @@ -105,7 +118,10 @@ export type SplitButtonState = ComponentState & Omit; // @public (undocumented) -export const toggleButtonClassName = "fui-ToggleButton"; +export const toggleButtonClassName: string; + +// @public (undocumented) +export const toggleButtonClassNames: SlotClassNames; // Warning: (ae-forgotten-export) The symbol "ToggleButtonCommons" needs to be exported by the entry point index.d.ts // diff --git a/packages/react-button/src/components/Button/index.ts b/packages/react-button/src/components/Button/index.ts index 6e488aa343f9b4..65bdfd3b13998b 100644 --- a/packages/react-button/src/components/Button/index.ts +++ b/packages/react-button/src/components/Button/index.ts @@ -3,4 +3,4 @@ export * from './Button'; export type { ButtonProps, ButtonSlots, ButtonState } from './Button.types'; export * from './renderButton'; export * from './useButton'; -export { buttonClassName, useButtonStyles_unstable } from './useButtonStyles'; +export { buttonClassName, buttonClassNames, useButtonStyles_unstable } from './useButtonStyles'; diff --git a/packages/react-button/src/components/Button/useButtonStyles.ts b/packages/react-button/src/components/Button/useButtonStyles.ts index 20061dd94d6cf5..a99ec843b1491e 100644 --- a/packages/react-button/src/components/Button/useButtonStyles.ts +++ b/packages/react-button/src/components/Button/useButtonStyles.ts @@ -1,9 +1,16 @@ import { shorthands, makeStyles, mergeClasses } from '@griffel/react'; import { createCustomFocusIndicatorStyle } from '@fluentui/react-tabster'; import { tokens } from '@fluentui/react-theme'; -import type { ButtonState } from './Button.types'; +import type { SlotClassNames } from '@fluentui/react-utilities'; +import type { ButtonSlots, ButtonState } from './Button.types'; -export const buttonClassName = 'fui-Button'; +export const buttonClassNames: SlotClassNames = { + root: 'fui-Button', + icon: 'fui-Button__icon', +}; + +// TODO temporary export to pass conformance test. +export const buttonClassName = buttonClassNames.root; const useRootStyles = makeStyles({ // Base styles @@ -353,7 +360,7 @@ export const useButtonStyles_unstable = (state: ButtonState): ButtonState => { const { appearance, block, disabled, disabledFocusable, iconOnly, shape, size } = state; state.root.className = mergeClasses( - buttonClassName, + buttonClassNames.root, // Root styles rootStyles.base, @@ -380,7 +387,7 @@ export const useButtonStyles_unstable = (state: ButtonState): ButtonState => { ); if (state.icon) { - state.icon.className = mergeClasses(iconStyles.base, iconStyles[size], state.icon.className); + state.icon.className = mergeClasses(buttonClassNames.icon, iconStyles.base, iconStyles[size], state.icon.className); } return state; diff --git a/packages/react-button/src/components/CompoundButton/index.ts b/packages/react-button/src/components/CompoundButton/index.ts index bc161291f74216..fd0e57899db43a 100644 --- a/packages/react-button/src/components/CompoundButton/index.ts +++ b/packages/react-button/src/components/CompoundButton/index.ts @@ -2,4 +2,8 @@ export * from './CompoundButton'; export * from './CompoundButton.types'; export * from './renderCompoundButton'; export * from './useCompoundButton'; -export { compoundButtonClassName, useCompoundButtonStyles_unstable } from './useCompoundButtonStyles'; +export { + compoundButtonClassName, + compoundButtonClassNames, + useCompoundButtonStyles_unstable, +} from './useCompoundButtonStyles'; diff --git a/packages/react-button/src/components/CompoundButton/useCompoundButtonStyles.ts b/packages/react-button/src/components/CompoundButton/useCompoundButtonStyles.ts index 8ff6efe74b8328..53b6d18ee4afac 100644 --- a/packages/react-button/src/components/CompoundButton/useCompoundButtonStyles.ts +++ b/packages/react-button/src/components/CompoundButton/useCompoundButtonStyles.ts @@ -1,14 +1,19 @@ import { shorthands, mergeClasses, makeStyles } from '@griffel/react'; import { tokens } from '@fluentui/react-theme'; import { useButtonStyles_unstable } from '../Button/useButtonStyles'; -import type { CompoundButtonState } from './CompoundButton.types'; - -export const compoundButtonClassName = 'fui-CompoundButton'; - -const CompoundButtonClassNames = { - secondaryContent: `${compoundButtonClassName}-secondaryContent`, +import type { SlotClassNames } from '@fluentui/react-utilities'; +import type { CompoundButtonSlots, CompoundButtonState } from './CompoundButton.types'; + +export const compoundButtonClassNames: SlotClassNames = { + root: 'fui-CompoundButton', + icon: 'fui-CompoundButton__icon', + contentContainer: 'fui-CompoundButton__contentContainer', + secondaryContent: 'fui-CompoundButton__secondaryContent', }; +// TODO temporary export to pass conformance test. +export const compoundButtonClassName = compoundButtonClassNames.root; + const useRootStyles = makeStyles({ // Base styles base: { @@ -16,18 +21,18 @@ const useRootStyles = makeStyles({ height: 'auto', - [`& .${CompoundButtonClassNames.secondaryContent}`]: { + [`& .${compoundButtonClassNames.secondaryContent}`]: { color: tokens.colorNeutralForeground2, }, ':hover': { - [`& .${CompoundButtonClassNames.secondaryContent}`]: { + [`& .${compoundButtonClassNames.secondaryContent}`]: { color: tokens.colorNeutralForeground2Hover, }, }, ':active': { - [`& .${CompoundButtonClassNames.secondaryContent}`]: { + [`& .${compoundButtonClassNames.secondaryContent}`]: { color: tokens.colorNeutralForeground2Pressed, }, }, @@ -38,52 +43,52 @@ const useRootStyles = makeStyles({ /* No styles */ }, primary: { - [`& .${CompoundButtonClassNames.secondaryContent}`]: { + [`& .${compoundButtonClassNames.secondaryContent}`]: { color: tokens.colorNeutralForegroundOnBrand, }, ':hover': { - [`& .${CompoundButtonClassNames.secondaryContent}`]: { + [`& .${compoundButtonClassNames.secondaryContent}`]: { color: tokens.colorNeutralForegroundOnBrand, }, }, ':active': { - [`& .${CompoundButtonClassNames.secondaryContent}`]: { + [`& .${compoundButtonClassNames.secondaryContent}`]: { color: tokens.colorNeutralForegroundOnBrand, }, }, }, subtle: { - [`& .${CompoundButtonClassNames.secondaryContent}`]: { + [`& .${compoundButtonClassNames.secondaryContent}`]: { color: tokens.colorNeutralForeground2, }, ':hover': { - [`& .${CompoundButtonClassNames.secondaryContent}`]: { + [`& .${compoundButtonClassNames.secondaryContent}`]: { color: tokens.colorNeutralForeground2BrandHover, }, }, ':active': { - [`& .${CompoundButtonClassNames.secondaryContent}`]: { + [`& .${compoundButtonClassNames.secondaryContent}`]: { color: tokens.colorNeutralForeground2BrandPressed, }, }, }, transparent: { - [`& .${CompoundButtonClassNames.secondaryContent}`]: { + [`& .${compoundButtonClassNames.secondaryContent}`]: { color: tokens.colorNeutralForeground2, }, ':hover': { - [`& .${CompoundButtonClassNames.secondaryContent}`]: { + [`& .${compoundButtonClassNames.secondaryContent}`]: { color: tokens.colorNeutralForeground2BrandHover, }, }, ':active': { - [`& .${CompoundButtonClassNames.secondaryContent}`]: { + [`& .${compoundButtonClassNames.secondaryContent}`]: { color: tokens.colorNeutralForeground2BrandPressed, }, }, @@ -111,18 +116,18 @@ const useRootStyles = makeStyles({ // Disabled styles disabled: { - [`& .${CompoundButtonClassNames.secondaryContent}`]: { + [`& .${compoundButtonClassNames.secondaryContent}`]: { color: tokens.colorNeutralForegroundDisabled, }, ':hover': { - [`& .${CompoundButtonClassNames.secondaryContent}`]: { + [`& .${compoundButtonClassNames.secondaryContent}`]: { color: tokens.colorNeutralForegroundDisabled, }, }, ':active': { - [`& .${CompoundButtonClassNames.secondaryContent}`]: { + [`& .${compoundButtonClassNames.secondaryContent}`]: { color: tokens.colorNeutralForegroundDisabled, }, }, @@ -198,7 +203,7 @@ export const useCompoundButtonStyles_unstable = (state: CompoundButtonState): Co const { appearance, disabled, disabledFocusable, iconOnly, size } = state; state.root.className = mergeClasses( - compoundButtonClassName, + compoundButtonClassNames.root, // Root styles rootStyles.base, @@ -215,15 +220,19 @@ export const useCompoundButtonStyles_unstable = (state: CompoundButtonState): Co state.root.className, ); + state.contentContainer.className = mergeClasses( + compoundButtonClassNames.contentContainer, + contentContainerStyles.base, + state.contentContainer.className, + ); + if (state.icon) { - state.icon.className = mergeClasses(iconStyles.base, state.icon.className); + state.icon.className = mergeClasses(compoundButtonClassNames.icon, iconStyles.base, state.icon.className); } - state.contentContainer.className = mergeClasses(contentContainerStyles.base, state.contentContainer.className); - if (state.secondaryContent) { state.secondaryContent.className = mergeClasses( - CompoundButtonClassNames.secondaryContent, + compoundButtonClassNames.secondaryContent, secondaryContentStyles.base, secondaryContentStyles[size], state.secondaryContent.className, diff --git a/packages/react-button/src/components/MenuButton/index.ts b/packages/react-button/src/components/MenuButton/index.ts index 3364a4080eb01c..7ec4cfc5d9d3c3 100644 --- a/packages/react-button/src/components/MenuButton/index.ts +++ b/packages/react-button/src/components/MenuButton/index.ts @@ -2,4 +2,4 @@ export * from './MenuButton.types'; export * from './MenuButton'; export * from './renderMenuButton'; export * from './useMenuButton'; -export { menuButtonClassName, useMenuButtonStyles_unstable } from './useMenuButtonStyles'; +export { menuButtonClassName, menuButtonClassNames, useMenuButtonStyles_unstable } from './useMenuButtonStyles'; diff --git a/packages/react-button/src/components/MenuButton/useMenuButtonStyles.ts b/packages/react-button/src/components/MenuButton/useMenuButtonStyles.ts index a2c0798c380fd3..4210ca3df4b52e 100644 --- a/packages/react-button/src/components/MenuButton/useMenuButtonStyles.ts +++ b/packages/react-button/src/components/MenuButton/useMenuButtonStyles.ts @@ -1,9 +1,17 @@ import { mergeClasses, makeStyles } from '@griffel/react'; import { ButtonState } from '../Button/Button.types'; import { useButtonStyles_unstable } from '../Button/useButtonStyles'; -import type { MenuButtonState } from './MenuButton.types'; +import type { SlotClassNames } from '@fluentui/react-utilities'; +import type { MenuButtonSlots, MenuButtonState } from './MenuButton.types'; -export const menuButtonClassName = 'fui-MenuButton'; +export const menuButtonClassNames: SlotClassNames = { + root: 'fui-MenuButton', + icon: 'fui-MenuButton__icon', + menuIcon: 'fui-MenuButton__menuIcon', +}; + +// TODO temporary export to pass conformance test. +export const menuButtonClassName = menuButtonClassNames.root; const useMenuIconStyles = makeStyles({ // Size appearance @@ -27,7 +35,11 @@ const useMenuIconStyles = makeStyles({ export const useMenuButtonStyles_unstable = (state: MenuButtonState): MenuButtonState => { const menuIconStyles = useMenuIconStyles(); - state.root.className = mergeClasses(menuButtonClassName, state.root.className); + state.root.className = mergeClasses(menuButtonClassNames.root, state.root.className); + + if (state.icon) { + state.icon.className = mergeClasses(menuButtonClassNames.icon, state.icon.className); + } if (state.menuIcon) { state.menuIcon.className = mergeClasses(menuIconStyles[state.size], state.menuIcon.className); diff --git a/packages/react-button/src/components/SplitButton/index.ts b/packages/react-button/src/components/SplitButton/index.ts index 9f5fbe3750cdd4..04ee7588a3d39b 100644 --- a/packages/react-button/src/components/SplitButton/index.ts +++ b/packages/react-button/src/components/SplitButton/index.ts @@ -2,4 +2,4 @@ export * from './SplitButton'; export * from './SplitButton.types'; export * from './renderSplitButton'; export * from './useSplitButton'; -export { splitButtonClassName, useSplitButtonStyles_unstable } from './useSplitButtonStyles'; +export { splitButtonClassName, splitButtonClassNames, useSplitButtonStyles_unstable } from './useSplitButtonStyles'; diff --git a/packages/react-button/src/components/SplitButton/useSplitButtonStyles.ts b/packages/react-button/src/components/SplitButton/useSplitButtonStyles.ts index 7fdc8b014a32c6..48476cad3633a8 100644 --- a/packages/react-button/src/components/SplitButton/useSplitButtonStyles.ts +++ b/packages/react-button/src/components/SplitButton/useSplitButtonStyles.ts @@ -1,15 +1,18 @@ import { makeStyles, mergeClasses } from '@griffel/react'; import { createCustomFocusIndicatorStyle } from '@fluentui/react-tabster'; import { tokens } from '@fluentui/react-theme'; -import type { SplitButtonState } from './SplitButton.types'; +import type { SlotClassNames } from '@fluentui/react-utilities'; +import type { SplitButtonSlots, SplitButtonState } from './SplitButton.types'; -export const splitButtonClassName = 'fui-SplitButton'; - -const SplitButtonClassNames = { - primaryActionButton: `${splitButtonClassName}-primaryActionButton`, - menuButton: `${splitButtonClassName}-menuButton`, +export const splitButtonClassNames: SlotClassNames = { + root: 'fui-SplitButton', + menuButton: 'fui-SplitButton__menuButton', + primaryActionButton: 'fui-SplitButton__primaryActionButton', }; +// TODO temporary export to pass conformance test. +export const splitButtonClassName = splitButtonClassNames.root; + const useFocusStyles = makeStyles({ primaryActionButton: createCustomFocusIndicatorStyle({ borderTopRightRadius: 0, @@ -32,13 +35,13 @@ const useRootStyles = makeStyles({ verticalAlign: 'middle', // Use classnames to increase specificy of rootStyles and avoid collisions. - [`& .${SplitButtonClassNames.primaryActionButton}`]: { + [`& .${splitButtonClassNames.primaryActionButton}`]: { borderTopRightRadius: 0, borderBottomRightRadius: 0, }, // Use classnames to increase specificy of rootStyles and avoid collisions. - [`& .${SplitButtonClassNames.menuButton}`]: { + [`& .${splitButtonClassNames.menuButton}`]: { borderLeftWidth: 0, borderTopLeftRadius: 0, borderBottomLeftRadius: 0, @@ -56,54 +59,54 @@ const useRootStyles = makeStyles({ }, primary: { // Use classnames to increase specificy of rootStyles and avoid collisions. - [`& .${SplitButtonClassNames.primaryActionButton}`]: { + [`& .${splitButtonClassNames.primaryActionButton}`]: { borderRightColor: tokens.colorNeutralForegroundInverted, }, ':hover': { - [`& .${SplitButtonClassNames.primaryActionButton}`]: { + [`& .${splitButtonClassNames.primaryActionButton}`]: { borderRightColor: tokens.colorNeutralForegroundInverted, }, }, ':active': { - [`& .${SplitButtonClassNames.primaryActionButton}`]: { + [`& .${splitButtonClassNames.primaryActionButton}`]: { borderRightColor: tokens.colorNeutralForegroundInverted, }, }, }, subtle: { // Use classnames to increase specificy of rootStyles and avoid collisions. - [`& .${SplitButtonClassNames.primaryActionButton}`]: { + [`& .${splitButtonClassNames.primaryActionButton}`]: { borderRightColor: tokens.colorNeutralStroke1Hover, }, ':hover': { - [`& .${SplitButtonClassNames.primaryActionButton}`]: { + [`& .${splitButtonClassNames.primaryActionButton}`]: { borderRightColor: tokens.colorNeutralStroke1Hover, }, }, ':active': { - [`& .${SplitButtonClassNames.primaryActionButton}`]: { + [`& .${splitButtonClassNames.primaryActionButton}`]: { borderRightColor: tokens.colorNeutralStroke1Hover, }, }, }, transparent: { // Use classnames to increase specificy of rootStyles and avoid collisions. - [`& .${SplitButtonClassNames.primaryActionButton}`]: { + [`& .${splitButtonClassNames.primaryActionButton}`]: { borderRightColor: tokens.colorNeutralStroke1Hover, }, ':hover': { - [`& .${SplitButtonClassNames.primaryActionButton}`]: { + [`& .${splitButtonClassNames.primaryActionButton}`]: { borderRightColor: tokens.colorNeutralStroke1Hover, }, }, ':active': { - [`& .${SplitButtonClassNames.primaryActionButton}`]: { + [`& .${splitButtonClassNames.primaryActionButton}`]: { borderRightColor: tokens.colorNeutralStroke1Hover, }, }, @@ -117,18 +120,18 @@ const useRootStyles = makeStyles({ // Disabled rootStyles disabled: { // Use classnames to increase specificy of rootStyles and avoid collisions. - [`& .${SplitButtonClassNames.primaryActionButton}`]: { + [`& .${splitButtonClassNames.primaryActionButton}`]: { borderRightColor: tokens.colorNeutralStrokeDisabled, }, ':hover': { - [`& .${SplitButtonClassNames.primaryActionButton}`]: { + [`& .${splitButtonClassNames.primaryActionButton}`]: { borderRightColor: tokens.colorNeutralStrokeDisabled, }, }, ':active': { - [`& .${SplitButtonClassNames.primaryActionButton}`]: { + [`& .${splitButtonClassNames.primaryActionButton}`]: { borderRightColor: tokens.colorNeutralStrokeDisabled, }, }, @@ -142,7 +145,7 @@ export const useSplitButtonStyles_unstable = (state: SplitButtonState): SplitBut const { appearance, block, disabled, disabledFocusable } = state; state.root.className = mergeClasses( - splitButtonClassName, + splitButtonClassNames.root, rootStyles.base, block && rootStyles.block, appearance && rootStyles[appearance], @@ -152,7 +155,7 @@ export const useSplitButtonStyles_unstable = (state: SplitButtonState): SplitBut if (state.menuButton) { state.menuButton.className = mergeClasses( - SplitButtonClassNames.menuButton, + splitButtonClassNames.menuButton, focusStyles.menuButton, state.menuButton.className, ); @@ -160,7 +163,7 @@ export const useSplitButtonStyles_unstable = (state: SplitButtonState): SplitBut if (state.primaryActionButton) { state.primaryActionButton.className = mergeClasses( - SplitButtonClassNames.primaryActionButton, + splitButtonClassNames.primaryActionButton, focusStyles.primaryActionButton, state.primaryActionButton.className, ); diff --git a/packages/react-button/src/components/ToggleButton/index.ts b/packages/react-button/src/components/ToggleButton/index.ts index fa0750f5bc00d3..659aefa2b40805 100644 --- a/packages/react-button/src/components/ToggleButton/index.ts +++ b/packages/react-button/src/components/ToggleButton/index.ts @@ -2,4 +2,4 @@ export * from './ToggleButton'; export * from './ToggleButton.types'; export * from './renderToggleButton'; export * from './useToggleButton'; -export { toggleButtonClassName, useToggleButtonStyles_unstable } from './useToggleButtonStyles'; +export { toggleButtonClassName, toggleButtonClassNames, useToggleButtonStyles_unstable } from './useToggleButtonStyles'; diff --git a/packages/react-button/src/components/ToggleButton/useToggleButtonStyles.ts b/packages/react-button/src/components/ToggleButton/useToggleButtonStyles.ts index 7308f61797b090..be2c9536d80a90 100644 --- a/packages/react-button/src/components/ToggleButton/useToggleButtonStyles.ts +++ b/packages/react-button/src/components/ToggleButton/useToggleButtonStyles.ts @@ -1,9 +1,17 @@ import { shorthands, mergeClasses, makeStyles } from '@griffel/react'; import { tokens } from '@fluentui/react-theme'; import { useButtonStyles_unstable } from '../Button/useButtonStyles'; +import type { SlotClassNames } from '@fluentui/react-utilities'; +import type { ButtonSlots } from '../Button/Button.types'; import type { ToggleButtonState } from './ToggleButton.types'; -export const toggleButtonClassName = 'fui-ToggleButton'; +export const toggleButtonClassNames: SlotClassNames = { + root: 'fui-ToggleButton', + icon: 'fui-ToggleButton__icon', +}; + +// TODO temporary export to pass conformance test. +export const toggleButtonClassName = toggleButtonClassNames.root; const useCheckedStyles = makeStyles({ // Base styles @@ -164,7 +172,7 @@ export const useToggleButtonStyles_unstable = (state: ToggleButtonState): Toggle const { appearance, checked, disabled, disabledFocusable } = state; state.root.className = mergeClasses( - toggleButtonClassName, + toggleButtonClassNames.root, // Checked styles checked && checkedStyles.base, @@ -178,6 +186,10 @@ export const useToggleButtonStyles_unstable = (state: ToggleButtonState): Toggle state.root.className, ); + if (state.icon) { + state.icon.className = mergeClasses(toggleButtonClassNames.icon, state.icon.className); + } + useButtonStyles_unstable(state); return state;