diff --git a/change/@fluentui-react-button-38a748ea-42c6-489f-994d-67f990d28260.json b/change/@fluentui-react-button-38a748ea-42c6-489f-994d-67f990d28260.json new file mode 100644 index 0000000000000..32384b5730a08 --- /dev/null +++ b/change/@fluentui-react-button-38a748ea-42c6-489f-994d-67f990d28260.json @@ -0,0 +1,7 @@ +{ + "type": "patch", + "comment": "feat: implement getComponentSlotClassName utility for dynamic class name generation", + "packageName": "@fluentui/react-button", + "email": "dmytrokirpa@microsoft.com", + "dependentChangeType": "patch" +} diff --git a/change/@fluentui-react-button-5368ba44-0210-43a8-9960-27fb5a61f347.json b/change/@fluentui-react-button-5368ba44-0210-43a8-9960-27fb5a61f347.json new file mode 100644 index 0000000000000..efa4bc34f8bdf --- /dev/null +++ b/change/@fluentui-react-button-5368ba44-0210-43a8-9960-27fb5a61f347.json @@ -0,0 +1,7 @@ +{ + "type": "minor", + "comment": "feat: introduce headless style hooks for button components", + "packageName": "@fluentui/react-button", + "email": "dmytrokirpa@microsoft.com", + "dependentChangeType": "patch" +} diff --git a/change/@fluentui-react-divider-dfaf2632-108c-4558-8643-a154b097f22e.json b/change/@fluentui-react-divider-dfaf2632-108c-4558-8643-a154b097f22e.json new file mode 100644 index 0000000000000..7424af9bffb60 --- /dev/null +++ b/change/@fluentui-react-divider-dfaf2632-108c-4558-8643-a154b097f22e.json @@ -0,0 +1,7 @@ +{ + "type": "minor", + "comment": "feat: implement headless style hook for Divider component", + "packageName": "@fluentui/react-divider", + "email": "dmytrokirpa@microsoft.com", + "dependentChangeType": "patch" +} diff --git a/change/@fluentui-react-divider-fbc7d77f-0ef0-4f5b-9465-b8e6c9ba03ba.json b/change/@fluentui-react-divider-fbc7d77f-0ef0-4f5b-9465-b8e6c9ba03ba.json new file mode 100644 index 0000000000000..318e7c783e38a --- /dev/null +++ b/change/@fluentui-react-divider-fbc7d77f-0ef0-4f5b-9465-b8e6c9ba03ba.json @@ -0,0 +1,7 @@ +{ + "type": "patch", + "comment": "feat: implement getComponentSlotClassName utility for dynamic class name generation", + "packageName": "@fluentui/react-divider", + "email": "dmytrokirpa@microsoft.com", + "dependentChangeType": "patch" +} diff --git a/change/@fluentui-react-input-a24d92c3-39b7-4df3-abbb-5504b2bd9dff.json b/change/@fluentui-react-input-a24d92c3-39b7-4df3-abbb-5504b2bd9dff.json new file mode 100644 index 0000000000000..ca548a73a8d04 --- /dev/null +++ b/change/@fluentui-react-input-a24d92c3-39b7-4df3-abbb-5504b2bd9dff.json @@ -0,0 +1,7 @@ +{ + "type": "minor", + "comment": "feat: add headless mode styles for Input component", + "packageName": "@fluentui/react-input", + "email": "dmytrokirpa@microsoft.com", + "dependentChangeType": "patch" +} diff --git a/change/@fluentui-react-menu-ceaf94dc-69ba-4a03-bc91-114e31e5322b.json b/change/@fluentui-react-menu-ceaf94dc-69ba-4a03-bc91-114e31e5322b.json new file mode 100644 index 0000000000000..bacb63d00b0ce --- /dev/null +++ b/change/@fluentui-react-menu-ceaf94dc-69ba-4a03-bc91-114e31e5322b.json @@ -0,0 +1,7 @@ +{ + "type": "patch", + "comment": "feat: add headless mode styles for Menu components", + "packageName": "@fluentui/react-menu", + "email": "dmytrokirpa@microsoft.com", + "dependentChangeType": "patch" +} diff --git a/change/@fluentui-react-popover-214019b1-b839-4155-a96e-528f061e5310.json b/change/@fluentui-react-popover-214019b1-b839-4155-a96e-528f061e5310.json new file mode 100644 index 0000000000000..77afc85249003 --- /dev/null +++ b/change/@fluentui-react-popover-214019b1-b839-4155-a96e-528f061e5310.json @@ -0,0 +1,7 @@ +{ + "type": "minor", + "comment": "feat: add headless mode support", + "packageName": "@fluentui/react-popover", + "email": "dmytrokirpa@microsoft.com", + "dependentChangeType": "patch" +} diff --git a/change/@fluentui-react-portal-28308c22-5f3a-4ed2-b238-44768cef8e40.json b/change/@fluentui-react-portal-28308c22-5f3a-4ed2-b238-44768cef8e40.json new file mode 100644 index 0000000000000..61b45896fcef5 --- /dev/null +++ b/change/@fluentui-react-portal-28308c22-5f3a-4ed2-b238-44768cef8e40.json @@ -0,0 +1,7 @@ +{ + "type": "minor", + "comment": "feat: add headless mode support", + "packageName": "@fluentui/react-portal", + "email": "dmytrokirpa@microsoft.com", + "dependentChangeType": "patch" +} diff --git a/change/@fluentui-react-tabs-99dec883-6f58-46b2-9edd-3c1e92e640d8.json b/change/@fluentui-react-tabs-99dec883-6f58-46b2-9edd-3c1e92e640d8.json new file mode 100644 index 0000000000000..6a56ca6db7ef4 --- /dev/null +++ b/change/@fluentui-react-tabs-99dec883-6f58-46b2-9edd-3c1e92e640d8.json @@ -0,0 +1,7 @@ +{ + "type": "minor", + "comment": "feat: add headless mode styles for Tab and TabList components", + "packageName": "@fluentui/react-tabs", + "email": "dmytrokirpa@microsoft.com", + "dependentChangeType": "patch" +} diff --git a/change/@fluentui-react-text-7e480d10-e7da-4459-90b3-306d7556661e.json b/change/@fluentui-react-text-7e480d10-e7da-4459-90b3-306d7556661e.json new file mode 100644 index 0000000000000..91ad0e43e75bb --- /dev/null +++ b/change/@fluentui-react-text-7e480d10-e7da-4459-90b3-306d7556661e.json @@ -0,0 +1,7 @@ +{ + "type": "minor", + "comment": "feat: add headless mode styles for Text components", + "packageName": "@fluentui/react-text", + "email": "dmytrokirpa@microsoft.com", + "dependentChangeType": "patch" +} diff --git a/change/@fluentui-react-toolbar-cc3919f8-b89b-48e1-9820-4576d78601f4.json b/change/@fluentui-react-toolbar-cc3919f8-b89b-48e1-9820-4576d78601f4.json new file mode 100644 index 0000000000000..1d18c1cf8af4e --- /dev/null +++ b/change/@fluentui-react-toolbar-cc3919f8-b89b-48e1-9820-4576d78601f4.json @@ -0,0 +1,7 @@ +{ + "type": "minor", + "comment": "feat: add headless mode styles for Toolbar components", + "packageName": "@fluentui/react-toolbar", + "email": "dmytrokirpa@microsoft.com", + "dependentChangeType": "patch" +} diff --git a/change/@fluentui-react-tooltip-be1228e0-020b-4b21-89d9-8c0210815205.json b/change/@fluentui-react-tooltip-be1228e0-020b-4b21-89d9-8c0210815205.json new file mode 100644 index 0000000000000..bfc9cfb288474 --- /dev/null +++ b/change/@fluentui-react-tooltip-be1228e0-020b-4b21-89d9-8c0210815205.json @@ -0,0 +1,7 @@ +{ + "type": "minor", + "comment": "feat(react-tooltip): add headless mode styles for Tooltip component", + "packageName": "@fluentui/react-tooltip", + "email": "dmytrokirpa@microsoft.com", + "dependentChangeType": "patch" +} diff --git a/change/@fluentui-react-utilities-01723da0-8751-4cc6-a4d1-203fef6bee06.json b/change/@fluentui-react-utilities-01723da0-8751-4cc6-a4d1-203fef6bee06.json new file mode 100644 index 0000000000000..1a777c4c771d5 --- /dev/null +++ b/change/@fluentui-react-utilities-01723da0-8751-4cc6-a4d1-203fef6bee06.json @@ -0,0 +1,7 @@ +{ + "type": "patch", + "comment": "feat: implement getComponentSlotClassName utility for dynamic class name generation", + "packageName": "@fluentui/react-utilities", + "email": "dmytrokirpa@microsoft.com", + "dependentChangeType": "patch" +} diff --git a/packages/react-components/react-button/library/src/components/Button/useButtonStyles.styles.headless.ts b/packages/react-components/react-button/library/src/components/Button/useButtonStyles.styles.headless.ts index 621ced016cd5c..b33cd820a5b11 100644 --- a/packages/react-components/react-button/library/src/components/Button/useButtonStyles.styles.headless.ts +++ b/packages/react-components/react-button/library/src/components/Button/useButtonStyles.styles.headless.ts @@ -1,6 +1,6 @@ 'use client'; -import type { SlotClassNames } from '@fluentui/react-utilities'; +import { getComponentSlotClassName, type SlotClassNames } from '@fluentui/react-utilities'; import type { ButtonSlots, ButtonState } from './Button.types'; export const buttonClassNames: SlotClassNames = { @@ -14,37 +14,10 @@ export const buttonClassNames: SlotClassNames = { export const useButtonStyles_unstable = (state: ButtonState): ButtonState => { 'use no memo'; - const { appearance, disabled, disabledFocusable, icon, iconOnly, iconPosition, shape, size } = state; - - state.root.className = [ - buttonClassNames.root, - - // Appearance - appearance && `${buttonClassNames.root}--${appearance}`, - - // Size - `${buttonClassNames.root}--${size}`, - - // Shape - `${buttonClassNames.root}--${shape}`, - - // Disabled styles - disabled && `${buttonClassNames.root}--disabled`, - disabledFocusable && `${buttonClassNames.root}--disabledFocusable`, - - // Icon styles - icon && iconPosition === 'before' && `${buttonClassNames.root}--iconBefore`, - icon && iconPosition === 'after' && `${buttonClassNames.root}--iconAfter`, - iconOnly && `${buttonClassNames.root}--iconOnly`, - - // User provided class name - state.root.className, - ] - .filter(Boolean) - .join(' '); + state.root.className = getComponentSlotClassName(buttonClassNames.root, state.root, state); if (state.icon) { - state.icon.className = [buttonClassNames.icon, state.icon.className].filter(Boolean).join(' '); + state.icon.className = getComponentSlotClassName(buttonClassNames.icon, state.icon); } return state; diff --git a/packages/react-components/react-button/library/src/components/CompoundButton/useCompoundButtonStyles.styles.headless.ts b/packages/react-components/react-button/library/src/components/CompoundButton/useCompoundButtonStyles.styles.headless.ts index 7ad9383b509ba..9e2524cf1f4ea 100644 --- a/packages/react-components/react-button/library/src/components/CompoundButton/useCompoundButtonStyles.styles.headless.ts +++ b/packages/react-components/react-button/library/src/components/CompoundButton/useCompoundButtonStyles.styles.headless.ts @@ -1,6 +1,6 @@ 'use client'; -import type { SlotClassNames } from '@fluentui/react-utilities'; +import { getComponentSlotClassName, type SlotClassNames } from '@fluentui/react-utilities'; import type { CompoundButtonSlots, CompoundButtonState } from './CompoundButton.types'; // Re-export the same slot class names mapping used by the griffel styles file @@ -17,47 +17,22 @@ export const compoundButtonClassNames: SlotClassNames = { export const useCompoundButtonStyles_unstable = (state: CompoundButtonState): CompoundButtonState => { 'use no memo'; - const { appearance, disabled, disabledFocusable, icon, iconOnly, iconPosition, shape, size } = state; - - state.root.className = [ - compoundButtonClassNames.root, - - // Appearance - appearance && `${compoundButtonClassNames.root}--${appearance}`, - - // Size - size && `${compoundButtonClassNames.root}--${size}`, - - // Shape - shape && `${compoundButtonClassNames.root}--${shape}`, - - // Disabled styles - disabled && `${compoundButtonClassNames.root}--disabled`, - disabledFocusable && `${compoundButtonClassNames.root}--disabledFocusable`, - - // Icon styles - icon && iconPosition === 'before' && `${compoundButtonClassNames.root}--iconBefore`, - icon && iconPosition === 'after' && `${compoundButtonClassNames.root}--iconAfter`, - icon && iconOnly && `${compoundButtonClassNames.root}--iconOnly`, - - // User provided class name - state.root.className, - ] - .filter(Boolean) - .join(' '); + state.root.className = getComponentSlotClassName(compoundButtonClassNames.root, state.root, state); if (state.icon) { - state.icon.className = [compoundButtonClassNames.icon, state.icon.className].filter(Boolean).join(' '); + state.icon.className = getComponentSlotClassName(compoundButtonClassNames.icon, state.icon); } - state.contentContainer.className = [compoundButtonClassNames.contentContainer, state.contentContainer.className] - .filter(Boolean) - .join(' '); + state.contentContainer.className = getComponentSlotClassName( + compoundButtonClassNames.contentContainer, + state.contentContainer, + ); if (state.secondaryContent) { - state.secondaryContent.className = [compoundButtonClassNames.secondaryContent, state.secondaryContent.className] - .filter(Boolean) - .join(' '); + state.secondaryContent.className = getComponentSlotClassName( + compoundButtonClassNames.secondaryContent, + state.secondaryContent, + ); } return state; diff --git a/packages/react-components/react-button/library/src/components/MenuButton/useMenuButtonStyles.styles.headless.ts b/packages/react-components/react-button/library/src/components/MenuButton/useMenuButtonStyles.styles.headless.ts index 735d2024ca0a2..f1cbc0dd9eeff 100644 --- a/packages/react-components/react-button/library/src/components/MenuButton/useMenuButtonStyles.styles.headless.ts +++ b/packages/react-components/react-button/library/src/components/MenuButton/useMenuButtonStyles.styles.headless.ts @@ -1,6 +1,6 @@ 'use client'; -import type { SlotClassNames } from '@fluentui/react-utilities'; +import { getComponentSlotClassName, type SlotClassNames } from '@fluentui/react-utilities'; import type { MenuButtonSlots, MenuButtonState } from './MenuButton.types'; export const menuButtonClassNames: SlotClassNames = { @@ -15,43 +15,17 @@ export const menuButtonClassNames: SlotClassNames = { export const useMenuButtonStyles_unstable = (state: MenuButtonState): MenuButtonState => { 'use no memo'; - const { appearance, disabled, disabledFocusable, shape, size, icon, iconOnly } = state; - const expanded = !!state.root['aria-expanded']; - - state.root.className = [ - menuButtonClassNames.root, - - // Appearance - appearance && `${menuButtonClassNames.root}--${appearance}`, - - // Size - size && `${menuButtonClassNames.root}--${size}`, - - // Shape - shape && `${menuButtonClassNames.root}--${shape}`, - - // Disabled styles - disabled && `${menuButtonClassNames.root}--disabled`, - disabledFocusable && `${menuButtonClassNames.root}--disabledFocusable`, - - // Expanded - expanded && `${menuButtonClassNames.root}--expanded`, - - // Icons - icon && iconOnly && `${menuButtonClassNames.root}--iconOnly`, - - // User provided class name - state.root.className, - ] - .filter(Boolean) - .join(' '); + state.root.className = getComponentSlotClassName(menuButtonClassNames.root, state.root, { + ...state, + expanded: !!state.root['aria-expanded'], + }); if (state.icon) { - state.icon.className = [menuButtonClassNames.icon, state.icon.className].filter(Boolean).join(' '); + state.icon.className = getComponentSlotClassName(menuButtonClassNames.icon, state.icon); } if (state.menuIcon) { - state.menuIcon.className = [menuButtonClassNames.menuIcon, state.menuIcon.className].filter(Boolean).join(' '); + state.menuIcon.className = getComponentSlotClassName(menuButtonClassNames.menuIcon, state.menuIcon); } return state; diff --git a/packages/react-components/react-button/library/src/components/SplitButton/useSplitButtonStyles.styles.headless.ts b/packages/react-components/react-button/library/src/components/SplitButton/useSplitButtonStyles.styles.headless.ts index 2822d6f7df43a..94d4a72922d0a 100644 --- a/packages/react-components/react-button/library/src/components/SplitButton/useSplitButtonStyles.styles.headless.ts +++ b/packages/react-components/react-button/library/src/components/SplitButton/useSplitButtonStyles.styles.headless.ts @@ -1,6 +1,6 @@ 'use client'; -import type { SlotClassNames } from '@fluentui/react-utilities'; +import { getComponentSlotClassName, type SlotClassNames } from '@fluentui/react-utilities'; import type { SplitButtonSlots, SplitButtonState } from './SplitButton.types'; export const splitButtonClassNames: SlotClassNames = { @@ -15,43 +15,17 @@ export const splitButtonClassNames: SlotClassNames = { export const useSplitButtonStyles_unstable = (state: SplitButtonState): SplitButtonState => { 'use no memo'; - const { appearance, disabled, disabledFocusable, shape, size } = state; - - state.root.className = [ - splitButtonClassNames.root, - - // Appearance - appearance && `${splitButtonClassNames.root}--${appearance}`, - - // Size - size && `${splitButtonClassNames.root}--${size}`, - - // Shape - shape && `${splitButtonClassNames.root}--${shape}`, - - // Disabled styles - disabled && `${splitButtonClassNames.root}--disabled`, - disabledFocusable && !disabled && `${splitButtonClassNames.root}--disabledFocusable`, - - // User provided class name - state.root.className, - ] - .filter(Boolean) - .join(' '); + state.root.className = getComponentSlotClassName(splitButtonClassNames.root, state.root, state); if (state.primaryActionButton) { - state.primaryActionButton.className = [ + state.primaryActionButton.className = getComponentSlotClassName( splitButtonClassNames.primaryActionButton, - state.primaryActionButton.className, - ] - .filter(Boolean) - .join(' '); + state.primaryActionButton, + ); } if (state.menuButton) { - state.menuButton.className = [splitButtonClassNames.menuButton, state.menuButton.className] - .filter(Boolean) - .join(' '); + state.menuButton.className = getComponentSlotClassName(splitButtonClassNames.menuButton, state.menuButton); } return state; diff --git a/packages/react-components/react-button/library/src/components/ToggleButton/useToggleButtonStyles.styles.headless.ts b/packages/react-components/react-button/library/src/components/ToggleButton/useToggleButtonStyles.styles.headless.ts index 20500ab961eeb..2fa109216ed61 100644 --- a/packages/react-components/react-button/library/src/components/ToggleButton/useToggleButtonStyles.styles.headless.ts +++ b/packages/react-components/react-button/library/src/components/ToggleButton/useToggleButtonStyles.styles.headless.ts @@ -1,6 +1,6 @@ 'use client'; -import type { SlotClassNames } from '@fluentui/react-utilities'; +import { getComponentSlotClassName, type SlotClassNames } from '@fluentui/react-utilities'; import type { ButtonSlots } from '../Button/Button.types'; import type { ToggleButtonState } from './ToggleButton.types'; @@ -15,38 +15,10 @@ export const toggleButtonClassNames: SlotClassNames = { export const useToggleButtonStyles_unstable = (state: ToggleButtonState): ToggleButtonState => { 'use no memo'; - const { appearance, disabled, disabledFocusable, shape, size, checked, iconOnly } = state; - - state.root.className = [ - toggleButtonClassNames.root, - - // Appearance - appearance && `${toggleButtonClassNames.root}--${appearance}`, - - // Size - size && `${toggleButtonClassNames.root}--${size}`, - - // Shape - shape && `${toggleButtonClassNames.root}--${shape}`, - - // Checked - checked && `${toggleButtonClassNames.root}--checked`, - - // Icons - iconOnly && `${toggleButtonClassNames.root}--iconOnly`, - - // Disabled - disabled && `${toggleButtonClassNames.root}--disabled`, - disabledFocusable && `${toggleButtonClassNames.root}--disabledFocusable`, - - // User provided class name - state.root.className, - ] - .filter(Boolean) - .join(' '); + state.root.className = getComponentSlotClassName(toggleButtonClassNames.root, state.root, state); if (state.icon) { - state.icon.className = [toggleButtonClassNames.icon, state.icon.className].filter(Boolean).join(' '); + state.icon.className = getComponentSlotClassName(toggleButtonClassNames.icon, state.icon); } return state; diff --git a/packages/react-components/react-divider/library/src/components/Divider/useDividerStyles.styles.headless.ts b/packages/react-components/react-divider/library/src/components/Divider/useDividerStyles.styles.headless.ts index 528c532f762e9..7ecc0148bee10 100644 --- a/packages/react-components/react-divider/library/src/components/Divider/useDividerStyles.styles.headless.ts +++ b/packages/react-components/react-divider/library/src/components/Divider/useDividerStyles.styles.headless.ts @@ -1,7 +1,7 @@ 'use client'; import { DividerSlots, DividerState } from './Divider.types'; -import type { SlotClassNames } from '@fluentui/react-utilities'; +import { getComponentSlotClassName, type SlotClassNames } from '@fluentui/react-utilities'; export const dividerClassNames: SlotClassNames = { root: 'fui-Divider', @@ -14,31 +14,10 @@ export const dividerClassNames: SlotClassNames = { export const useDividerStyles_unstable = (state: DividerState): DividerState => { 'use no memo'; - const { alignContent, appearance, inset, vertical } = state; - - state.root.className = [ - dividerClassNames.root, - - // Alignment - `${dividerClassNames}--align-${alignContent}`, - - // Appearance - `${dividerClassNames}--${appearance}`, - - // Orientation - vertical ? `${dividerClassNames}--vertical` : `${dividerClassNames}--horizontal`, - - // Inset - inset && `${dividerClassNames}--inset`, - - // User provided class name - state.root.className, - ] - .filter(Boolean) - .join(' '); + state.root.className = getComponentSlotClassName(dividerClassNames.root, state.root, state); if (state.wrapper) { - state.wrapper.className = [dividerClassNames.wrapper, state.wrapper.className].filter(Boolean).join(' '); + state.wrapper.className = getComponentSlotClassName(dividerClassNames.wrapper, state.wrapper); } return state; diff --git a/packages/react-components/react-input/library/src/components/Input/useInputStyles.headless.ts b/packages/react-components/react-input/library/src/components/Input/useInputStyles.headless.ts new file mode 100644 index 0000000000000..b9f5397108830 --- /dev/null +++ b/packages/react-components/react-input/library/src/components/Input/useInputStyles.headless.ts @@ -0,0 +1,28 @@ +import type { SlotClassNames } from '@fluentui/react-utilities'; +import { getComponentSlotClassName } from '@fluentui/react-utilities'; +import type { InputSlots, InputState } from './Input.types'; + +export const inputClassNames: SlotClassNames = { + root: 'fui-Input', + input: 'fui-Input__input', + contentBefore: 'fui-Input__contentBefore', + contentAfter: 'fui-Input__contentAfter', +}; + +export const useInputStyles_unstable = (state: InputState): InputState => { + state.root.className = getComponentSlotClassName(inputClassNames.root, state.root, state); + + if (state.input) { + state.input.className = getComponentSlotClassName(inputClassNames.input, state.input); + } + + if (state.contentBefore) { + state.contentBefore.className = getComponentSlotClassName(inputClassNames.contentBefore, state.contentBefore); + } + + if (state.contentAfter) { + state.contentAfter.className = getComponentSlotClassName(inputClassNames.contentAfter, state.contentAfter); + } + + return state; +}; diff --git a/packages/react-components/react-menu/library/src/components/MenuDivider/useMenuDividerStyles.headless.ts b/packages/react-components/react-menu/library/src/components/MenuDivider/useMenuDividerStyles.headless.ts new file mode 100644 index 0000000000000..345d8318c314c --- /dev/null +++ b/packages/react-components/react-menu/library/src/components/MenuDivider/useMenuDividerStyles.headless.ts @@ -0,0 +1,12 @@ +import type { SlotClassNames } from '@fluentui/react-utilities'; +import { getComponentSlotClassName } from '@fluentui/react-utilities'; +import type { MenuDividerSlots, MenuDividerState } from './MenuDivider.types'; + +export const menuDividerClassNames: SlotClassNames = { + root: 'fui-MenuDivider', +}; + +export const useMenuDividerStyles_unstable = (state: MenuDividerState): MenuDividerState => { + state.root.className = getComponentSlotClassName(menuDividerClassNames.root, state.root, state); + return state; +}; diff --git a/packages/react-components/react-menu/library/src/components/MenuGroup/useMenuGroupStyles.headless.ts b/packages/react-components/react-menu/library/src/components/MenuGroup/useMenuGroupStyles.headless.ts new file mode 100644 index 0000000000000..fd58e15a96d97 --- /dev/null +++ b/packages/react-components/react-menu/library/src/components/MenuGroup/useMenuGroupStyles.headless.ts @@ -0,0 +1,12 @@ +import type { SlotClassNames } from '@fluentui/react-utilities'; +import { getComponentSlotClassName } from '@fluentui/react-utilities'; +import type { MenuGroupSlots, MenuGroupState } from './MenuGroup.types'; + +export const menuGroupClassNames: SlotClassNames = { + root: 'fui-MenuGroup', +}; + +export const useMenuGroupStyles_unstable = (state: MenuGroupState): MenuGroupState => { + state.root.className = getComponentSlotClassName(menuGroupClassNames.root, state.root, state); + return state; +}; diff --git a/packages/react-components/react-menu/library/src/components/MenuGroupHeader/useMenuGroupHeaderStyles.headless.ts b/packages/react-components/react-menu/library/src/components/MenuGroupHeader/useMenuGroupHeaderStyles.headless.ts new file mode 100644 index 0000000000000..be649bbe433c0 --- /dev/null +++ b/packages/react-components/react-menu/library/src/components/MenuGroupHeader/useMenuGroupHeaderStyles.headless.ts @@ -0,0 +1,13 @@ +import type { SlotClassNames } from '@fluentui/react-utilities'; +import { getComponentSlotClassName } from '@fluentui/react-utilities'; +import type { MenuGroupHeaderSlots, MenuGroupHeaderState } from './MenuGroupHeader.types'; + +export const menuGroupHeaderClassNames: SlotClassNames = { + root: 'fui-MenuGroupHeader', +}; + +export const useMenuGroupHeaderStyles_unstable = (state: MenuGroupHeaderState): MenuGroupHeaderState => { + state.root.className = getComponentSlotClassName(menuGroupHeaderClassNames.root, state.root, state); + + return state; +}; diff --git a/packages/react-components/react-menu/library/src/components/MenuItem/useMenuItemStyles.headless.ts b/packages/react-components/react-menu/library/src/components/MenuItem/useMenuItemStyles.headless.ts new file mode 100644 index 0000000000000..d82c276ddc250 --- /dev/null +++ b/packages/react-components/react-menu/library/src/components/MenuItem/useMenuItemStyles.headless.ts @@ -0,0 +1,49 @@ +import type { SlotClassNames } from '@fluentui/react-utilities'; +import { getComponentSlotClassName } from '@fluentui/react-utilities'; +import type { MenuItemSlots, MenuItemState } from './MenuItem.types'; + +export const menuItemClassNames: SlotClassNames = { + root: 'fui-MenuItem', + icon: 'fui-MenuItem__icon', + checkmark: 'fui-MenuItem__checkmark', + submenuIndicator: 'fui-MenuItem__submenuIndicator', + content: 'fui-MenuItem__content', + secondaryContent: 'fui-MenuItem__secondaryContent', + subText: 'fui-MenuItem__subText', +}; + +export const useMenuItemStyles_unstable = (state: MenuItemState): MenuItemState => { + state.root.className = getComponentSlotClassName(menuItemClassNames.root, state.root, state); + + if (state.content) { + state.content.className = getComponentSlotClassName(menuItemClassNames.content, state.content); + } + + if (state.checkmark) { + state.checkmark.className = getComponentSlotClassName(menuItemClassNames.checkmark, state.checkmark); + } + + if (state.secondaryContent) { + state.secondaryContent.className = getComponentSlotClassName( + menuItemClassNames.secondaryContent, + state.secondaryContent, + ); + } + + if (state.icon) { + state.icon.className = getComponentSlotClassName(menuItemClassNames.icon, state.icon); + } + + if (state.submenuIndicator) { + state.submenuIndicator.className = getComponentSlotClassName( + menuItemClassNames.submenuIndicator, + state.submenuIndicator, + ); + } + + if (state.subText) { + state.subText.className = getComponentSlotClassName(menuItemClassNames.subText, state.subText); + } + + return state; +}; diff --git a/packages/react-components/react-menu/library/src/components/MenuItemCheckbox/useMenuItemCheckboxStyles.headless.ts b/packages/react-components/react-menu/library/src/components/MenuItemCheckbox/useMenuItemCheckboxStyles.headless.ts new file mode 100644 index 0000000000000..45657fa3f271e --- /dev/null +++ b/packages/react-components/react-menu/library/src/components/MenuItemCheckbox/useMenuItemCheckboxStyles.headless.ts @@ -0,0 +1,42 @@ +import type { SlotClassNames } from '@fluentui/react-utilities'; +import { getComponentSlotClassName } from '@fluentui/react-utilities'; +import type { MenuItemSlots } from '../index'; +import type { MenuItemCheckboxState } from './MenuItemCheckbox.types'; + +export const menuItemCheckboxClassNames: SlotClassNames> = { + root: 'fui-MenuItemCheckbox', + icon: 'fui-MenuItemCheckbox__icon', + checkmark: 'fui-MenuItemCheckbox__checkmark', + content: 'fui-MenuItemCheckbox__content', + secondaryContent: 'fui-MenuItemCheckbox__secondaryContent', + subText: 'fui-MenuItemCheckbox__subText', +}; + +export const useMenuItemCheckboxStyles_unstable = (state: MenuItemCheckboxState): MenuItemCheckboxState => { + state.root.className = getComponentSlotClassName(menuItemCheckboxClassNames.root, state.root, state); + + if (state.content) { + state.content.className = getComponentSlotClassName(menuItemCheckboxClassNames.content, state.content); + } + + if (state.secondaryContent) { + state.secondaryContent.className = getComponentSlotClassName( + menuItemCheckboxClassNames.secondaryContent, + state.secondaryContent, + ); + } + + if (state.icon) { + state.icon.className = getComponentSlotClassName(menuItemCheckboxClassNames.icon, state.icon); + } + + if (state.checkmark) { + state.checkmark.className = getComponentSlotClassName(menuItemCheckboxClassNames.checkmark, state.checkmark); + } + + if (state.subText) { + state.subText.className = getComponentSlotClassName(menuItemCheckboxClassNames.subText, state.subText); + } + + return state; +}; diff --git a/packages/react-components/react-menu/library/src/components/MenuItemLink/useMenuItemLinkStyles.headless.ts b/packages/react-components/react-menu/library/src/components/MenuItemLink/useMenuItemLinkStyles.headless.ts new file mode 100644 index 0000000000000..276a7503d082f --- /dev/null +++ b/packages/react-components/react-menu/library/src/components/MenuItemLink/useMenuItemLinkStyles.headless.ts @@ -0,0 +1,36 @@ +import type { SlotClassNames } from '@fluentui/react-utilities'; +import { getComponentSlotClassName } from '@fluentui/react-utilities'; +import type { MenuItemLinkSlots, MenuItemLinkState } from './MenuItemLink.types'; + +export const menuItemLinkClassNames: SlotClassNames = { + root: 'fui-MenuItemLink', + icon: 'fui-MenuItemLink__icon', + checkmark: 'fui-MenuItemLink__checkmark', + content: 'fui-MenuItemLink__content', + secondaryContent: 'fui-MenuItemLink__secondaryContent', +}; + +export const useMenuItemLinkStyles_unstable = (state: MenuItemLinkState): MenuItemLinkState => { + state.root.className = getComponentSlotClassName(menuItemLinkClassNames.root, state.root, state); + + if (state.icon) { + state.icon.className = getComponentSlotClassName(menuItemLinkClassNames.icon, state.icon); + } + + if (state.content) { + state.content.className = getComponentSlotClassName(menuItemLinkClassNames.content, state.content); + } + + if (state.secondaryContent) { + state.secondaryContent.className = getComponentSlotClassName( + menuItemLinkClassNames.secondaryContent, + state.secondaryContent, + ); + } + + if (state.checkmark) { + state.checkmark.className = getComponentSlotClassName(menuItemLinkClassNames.checkmark, state.checkmark); + } + + return state; +}; diff --git a/packages/react-components/react-menu/library/src/components/MenuItemRadio/useMenuItemRadioStyles.headless.ts b/packages/react-components/react-menu/library/src/components/MenuItemRadio/useMenuItemRadioStyles.headless.ts new file mode 100644 index 0000000000000..4b389bb795243 --- /dev/null +++ b/packages/react-components/react-menu/library/src/components/MenuItemRadio/useMenuItemRadioStyles.headless.ts @@ -0,0 +1,40 @@ +import type { SlotClassNames } from '@fluentui/react-utilities'; +import { getComponentSlotClassName } from '@fluentui/react-utilities'; +import type { MenuItemSlots } from '../index'; +import type { MenuItemRadioState } from './MenuItemRadio.types'; + +export const menuItemRadioClassNames: SlotClassNames> = { + root: 'fui-MenuItemRadio', + icon: 'fui-MenuItemRadio__icon', + checkmark: 'fui-MenuItemRadio__checkmark', + content: 'fui-MenuItemRadio__content', + secondaryContent: 'fui-MenuItemRadio__secondaryContent', + subText: 'fui-MenuItemRadio__subText', +}; + +export const useMenuItemRadioStyles_unstable = (state: MenuItemRadioState): void => { + state.root.className = getComponentSlotClassName(menuItemRadioClassNames.root, state.root, state); + + if (state.content) { + state.content.className = getComponentSlotClassName(menuItemRadioClassNames.content, state.content); + } + + if (state.secondaryContent) { + state.secondaryContent.className = getComponentSlotClassName( + menuItemRadioClassNames.secondaryContent, + state.secondaryContent, + ); + } + + if (state.icon) { + state.icon.className = getComponentSlotClassName(menuItemRadioClassNames.icon, state.icon); + } + + if (state.checkmark) { + state.checkmark.className = getComponentSlotClassName(menuItemRadioClassNames.checkmark, state.checkmark); + } + + if (state.subText) { + state.subText.className = getComponentSlotClassName(menuItemRadioClassNames.subText, state.subText); + } +}; diff --git a/packages/react-components/react-menu/library/src/components/MenuItemSwitch/useMenuItemSwitchStyles.headless.ts b/packages/react-components/react-menu/library/src/components/MenuItemSwitch/useMenuItemSwitchStyles.headless.ts new file mode 100644 index 0000000000000..732b208c97ebe --- /dev/null +++ b/packages/react-components/react-menu/library/src/components/MenuItemSwitch/useMenuItemSwitchStyles.headless.ts @@ -0,0 +1,46 @@ +import type { SlotClassNames } from '@fluentui/react-utilities'; +import { getComponentSlotClassName } from '@fluentui/react-utilities'; +import type { MenuItemSwitchSlots, MenuItemSwitchState } from './MenuItemSwitch.types'; + +export const menuItemSwitchClassNames: SlotClassNames = { + root: 'fui-MenuItemSwitch', + icon: 'fui-MenuItemSwitch__icon', + content: 'fui-MenuItemSwitch__content', + secondaryContent: 'fui-MenuItemSwitch__secondaryContent', + switchIndicator: 'fui-MenuItemSwitch__switchIndicator', + subText: 'fui-MenuItemSwitch__subText', +}; + +export const circleFilledClassName = 'fui-MenuItemSwitch__switchIndicator__circleFilled'; + +export const useMenuItemSwitchStyles_unstable = (state: MenuItemSwitchState): MenuItemSwitchState => { + state.root.className = getComponentSlotClassName(menuItemSwitchClassNames.root, state.root, state); + + if (state.content) { + state.content.className = getComponentSlotClassName(menuItemSwitchClassNames.content, state.content); + } + + if (state.secondaryContent) { + state.secondaryContent.className = getComponentSlotClassName( + menuItemSwitchClassNames.secondaryContent, + state.secondaryContent, + ); + } + + if (state.icon) { + state.icon.className = getComponentSlotClassName(menuItemSwitchClassNames.icon, state.icon); + } + + if (state.subText) { + state.subText.className = getComponentSlotClassName(menuItemSwitchClassNames.subText, state.subText); + } + + if (state.switchIndicator) { + state.switchIndicator.className = getComponentSlotClassName( + menuItemSwitchClassNames.switchIndicator, + state.switchIndicator, + ); + } + + return state; +}; diff --git a/packages/react-components/react-menu/library/src/components/MenuList/useMenuListStyles.headless.ts b/packages/react-components/react-menu/library/src/components/MenuList/useMenuListStyles.headless.ts new file mode 100644 index 0000000000000..01473d6b8722d --- /dev/null +++ b/packages/react-components/react-menu/library/src/components/MenuList/useMenuListStyles.headless.ts @@ -0,0 +1,12 @@ +import type { SlotClassNames } from '@fluentui/react-utilities'; +import { getComponentSlotClassName } from '@fluentui/react-utilities'; +import type { MenuListSlots, MenuListState } from './MenuList.types'; + +export const menuListClassNames: SlotClassNames = { + root: 'fui-MenuList', +}; + +export const useMenuListStyles_unstable = (state: MenuListState): MenuListState => { + state.root.className = getComponentSlotClassName(menuListClassNames.root, state.root, state); + return state; +}; diff --git a/packages/react-components/react-menu/library/src/components/MenuPopover/useMenuPopoverStyles.headless.ts b/packages/react-components/react-menu/library/src/components/MenuPopover/useMenuPopoverStyles.headless.ts new file mode 100644 index 0000000000000..08e09178ced32 --- /dev/null +++ b/packages/react-components/react-menu/library/src/components/MenuPopover/useMenuPopoverStyles.headless.ts @@ -0,0 +1,13 @@ +import type { SlotClassNames } from '@fluentui/react-utilities'; +import { getComponentSlotClassName } from '@fluentui/react-utilities'; +import type { MenuPopoverSlots, MenuPopoverState } from './MenuPopover.types'; + +export const menuPopoverClassNames: SlotClassNames = { + root: 'fui-MenuPopover', +}; + +export const useMenuPopoverStyles_unstable = (state: MenuPopoverState): MenuPopoverState => { + const { mountNode, safeZone, ...componentState } = state; + state.root.className = getComponentSlotClassName(menuPopoverClassNames.root, state.root, componentState); + return state; +}; diff --git a/packages/react-components/react-menu/library/src/components/MenuSplitGroup/useMenuSplitGroupStyles.headless.ts b/packages/react-components/react-menu/library/src/components/MenuSplitGroup/useMenuSplitGroupStyles.headless.ts new file mode 100644 index 0000000000000..9b0e9efef0168 --- /dev/null +++ b/packages/react-components/react-menu/library/src/components/MenuSplitGroup/useMenuSplitGroupStyles.headless.ts @@ -0,0 +1,14 @@ +import type { SlotClassNames } from '@fluentui/react-utilities'; +import { getComponentSlotClassName } from '@fluentui/react-utilities'; +import type { MenuSplitGroupSlots, MenuSplitGroupState } from './MenuSplitGroup.types'; + +export const menuSplitGroupMultilineAttr = 'data-multiline'; + +export const menuSplitGroupClassNames: SlotClassNames = { + root: 'fui-MenuSplitGroup', +}; + +export const useMenuSplitGroupStyles_unstable = (state: MenuSplitGroupState): MenuSplitGroupState => { + state.root.className = getComponentSlotClassName(menuSplitGroupClassNames.root, state.root, state); + return state; +}; diff --git a/packages/react-components/react-popover/library/src/components/PopoverSurface/usePopoverSurfaceStyles.styles.headless.ts b/packages/react-components/react-popover/library/src/components/PopoverSurface/usePopoverSurfaceStyles.styles.headless.ts new file mode 100644 index 0000000000000..c54b83ee6e5e8 --- /dev/null +++ b/packages/react-components/react-popover/library/src/components/PopoverSurface/usePopoverSurfaceStyles.styles.headless.ts @@ -0,0 +1,32 @@ +'use client'; + +import type { PopoverSize } from '../Popover/Popover.types'; +import type { PopoverSurfaceSlots, PopoverSurfaceState } from './PopoverSurface.types'; +import { getComponentSlotClassName, type SlotClassNames } from '@fluentui/react-utilities'; + +export const popoverSurfaceClassNames: SlotClassNames = { + root: 'fui-PopoverSurface', +}; + +const popoverArrowClassName = 'fui-PopoverSurface__arrow'; + +export const arrowHeights: Record = { + small: 6, + medium: 8, + large: 8, +}; + +/** + * Apply styling to the PopoverSurface slots based on the state + */ +export const usePopoverSurfaceStyles_unstable = (state: PopoverSurfaceState): PopoverSurfaceState => { + 'use no memo'; + + const { mountNode: _, ...componentState } = state; + + state.root.className = getComponentSlotClassName(popoverSurfaceClassNames.root, state.root, componentState); + + state.arrowClassName = popoverArrowClassName; + + return state; +}; diff --git a/packages/react-components/react-portal/library/src/components/Portal/usePortalMountNode.ts b/packages/react-components/react-portal/library/src/components/Portal/usePortalMountNode.ts index 60f46090a8579..4b4743e5bc293 100644 --- a/packages/react-components/react-portal/library/src/components/Portal/usePortalMountNode.ts +++ b/packages/react-components/react-portal/library/src/components/Portal/usePortalMountNode.ts @@ -6,10 +6,9 @@ import { useFluent_unstable as useFluent, usePortalMountNode as usePortalMountNodeContext, } from '@fluentui/react-shared-contexts'; -import { mergeClasses } from '@griffel/react'; import { useFocusVisible } from '@fluentui/react-tabster'; -import { usePortalMountNodeStylesStyles } from './usePortalMountNodeStyles.styles'; +import { usePortalMountNodeClassName } from './usePortalMountNodeStyles.styles'; const useInsertionEffect = (React as never)['useInsertion' + 'Effect'] as typeof React.useLayoutEffect | undefined; @@ -243,7 +242,6 @@ export const usePortalMountNode = (options: UsePortalMountNodeOptions): HTMLElem // eslint-disable-next-line @typescript-eslint/no-deprecated const focusVisibleRef = useFocusVisible() as React.MutableRefObject; - const classes = usePortalMountNodeStylesStyles(); const themeClassName = useThemeClassName(); const factoryOptions: UseElementFactoryOptions = { @@ -251,7 +249,7 @@ export const usePortalMountNode = (options: UsePortalMountNodeOptions): HTMLElem disabled: options.disabled, focusVisibleRef, - className: mergeClasses(themeClassName, classes.root, options.className), + className: usePortalMountNodeClassName(themeClassName, options.className), targetNode: mountNode ?? targetDocument?.body, }; diff --git a/packages/react-components/react-portal/library/src/components/Portal/usePortalMountNodeStyles.styles.headless.ts b/packages/react-components/react-portal/library/src/components/Portal/usePortalMountNodeStyles.styles.headless.ts new file mode 100644 index 0000000000000..18fafa5fdf889 --- /dev/null +++ b/packages/react-components/react-portal/library/src/components/Portal/usePortalMountNodeStyles.styles.headless.ts @@ -0,0 +1,12 @@ +'use client'; + +const portalMountNodeClassNames = { + root: 'fui-PortalMountNode', +}; + +/** + * Applies class names to the Portal mount node + */ +export const usePortalMountNodeClassName = (themeClassName: string, className?: string): string => { + return [portalMountNodeClassNames.root, themeClassName, className].filter(Boolean).join(' '); +}; diff --git a/packages/react-components/react-portal/library/src/components/Portal/usePortalMountNodeStyles.styles.ts b/packages/react-components/react-portal/library/src/components/Portal/usePortalMountNodeStyles.styles.ts index a3882f6d1b933..b170eda238dea 100644 --- a/packages/react-components/react-portal/library/src/components/Portal/usePortalMountNodeStyles.styles.ts +++ b/packages/react-components/react-portal/library/src/components/Portal/usePortalMountNodeStyles.styles.ts @@ -1,6 +1,8 @@ -import { makeStyles } from '@griffel/react'; +'use client'; -export const usePortalMountNodeStylesStyles = makeStyles({ +import { makeStyles, mergeClasses } from '@griffel/react'; + +const useStyles = makeStyles({ root: { // Creates new stacking context to prevent z-index issues // https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_positioned_layout/Understanding_z-index/Stacking_context @@ -14,3 +16,12 @@ export const usePortalMountNodeStylesStyles = makeStyles({ zIndex: 1000000, }, }); + +/** + * Applies styles and class names to the Portal mount node + */ +export const usePortalMountNodeClassName = (themeClassName: string, className?: string): string => { + const classes = useStyles(); + + return mergeClasses(themeClassName, classes.root, className); +}; diff --git a/packages/react-components/react-tabs/library/src/components/Tab/useTabStyles.styles.headless.ts b/packages/react-components/react-tabs/library/src/components/Tab/useTabStyles.styles.headless.ts new file mode 100644 index 0000000000000..80e2eaf66131e --- /dev/null +++ b/packages/react-components/react-tabs/library/src/components/Tab/useTabStyles.styles.headless.ts @@ -0,0 +1,93 @@ +'use client'; + +import { getComponentSlotClassName, type SlotClassNames } from '@fluentui/react-utilities'; +import type { TabSlots, TabState } from './Tab.types'; + +export const tabClassNames: SlotClassNames = { + root: 'fui-Tab', + icon: 'fui-Tab__icon', + content: 'fui-Tab__content', +}; + +export const tabReservedSpaceClassNames = { + content: 'fui-Tab__content--reserved-space', +}; + +/** + * Apply styling to the Tab slots based on the state + */ +export const useTabStyles_unstable = (state: TabState): TabState => { + 'use no memo'; + + useTabButtonStyles_unstable(state, state.root); + useTabContentStyles_unstable(state); + useTabIndicatorStyles_unstable(state); + + return state; +}; + +/** + * Applies styles for the Tab indicator based on its current state. + * + * This hook is typically used internally by `useTabStyles_unstable`. You should + * only use it directly if you're creating a custom `Tab` component. + * + * @param state - The `Tab` component's current state + * @returns The state object with updated button styles + */ +export const useTabIndicatorStyles_unstable = (state: TabState): TabState => { + return state; +}; + +/** + * Applies styles to the Tab button slot based on its current state. + * + * This hook is typically used internally by `useTabStyles_unstable`. You should + * only use it directly if you're creating a custom `Tab` component. + * + * @param state - The Tab component's current state + * @param slot - The button slot of the Tab component + * @returns The state object with updated button styles + */ +export const useTabButtonStyles_unstable = (state: TabState, slot: TabState['root']): TabState => { + 'use no memo'; + + const { value, ...componentState } = state; + + slot.className = getComponentSlotClassName(tabClassNames.root, slot, componentState); + + return state; +}; + +/** + * Applies styles to the Tab content slot based on its current state. + * + * This hook is typically used internally by `useTabStyles_unstable`. You should + * only use it directly if you're creating a custom `Tab` component. + * + * @param state - The Tab component's current state + * @returns The state object with updated content styles + */ +export const useTabContentStyles_unstable = (state: TabState): TabState => { + 'use no memo'; + + if (state.icon) { + state.icon.className = getComponentSlotClassName(tabClassNames.icon, state.icon); + } + + // This needs to be before state.content.className is updated + if (state.contentReservedSpace) { + state.contentReservedSpace.className = getComponentSlotClassName( + tabReservedSpaceClassNames.content, + state.contentReservedSpace, + ); + // FIXME: this is a deprecated API + // should be removed in the next major version + // eslint-disable-next-line @typescript-eslint/no-deprecated + state.contentReservedSpaceClassName = state.contentReservedSpace.className; + } + + state.content.className = getComponentSlotClassName(tabClassNames.content, state.content); + + return state; +}; diff --git a/packages/react-components/react-tabs/library/src/components/TabList/useTabListStyles.styles.headless.ts b/packages/react-components/react-tabs/library/src/components/TabList/useTabListStyles.styles.headless.ts new file mode 100644 index 0000000000000..976aaca6eb6f1 --- /dev/null +++ b/packages/react-components/react-tabs/library/src/components/TabList/useTabListStyles.styles.headless.ts @@ -0,0 +1,20 @@ +'use client'; + +import { getComponentSlotClassName, SlotClassNames } from '@fluentui/react-utilities'; +import type { TabListSlots, TabListState } from './TabList.types'; + +export const tabListClassNames: SlotClassNames = { + root: 'fui-TabList', +}; +/** + * Apply styling to the TabList slots based on the state + */ +export const useTabListStyles_unstable = (state: TabListState): TabListState => { + 'use no memo'; + + const { selectedValue, ...componentState } = state; + + state.root.className = getComponentSlotClassName(tabListClassNames.root, state.root, componentState); + + return state; +}; diff --git a/packages/react-components/react-text/library/src/components/Text/useTextStyles.headless.ts b/packages/react-components/react-text/library/src/components/Text/useTextStyles.headless.ts new file mode 100644 index 0000000000000..faa9f2e59a98d --- /dev/null +++ b/packages/react-components/react-text/library/src/components/Text/useTextStyles.headless.ts @@ -0,0 +1,12 @@ +import type { SlotClassNames } from '@fluentui/react-utilities'; +import { getComponentSlotClassName } from '@fluentui/react-utilities'; +import type { TextSlots, TextState } from './Text.types'; + +export const textClassNames: SlotClassNames = { + root: 'fui-Text', +}; + +export const useTextStyles_unstable = (state: TextState): TextState => { + state.root.className = getComponentSlotClassName(textClassNames.root, state.root, state); + return state; +}; diff --git a/packages/react-components/react-text/library/src/components/presets/Body1/Body1.tsx b/packages/react-components/react-text/library/src/components/presets/Body1/Body1.tsx index 35ff31e82c7bf..4bfd8d2eb5e87 100644 --- a/packages/react-components/react-text/library/src/components/presets/Body1/Body1.tsx +++ b/packages/react-components/react-text/library/src/components/presets/Body1/Body1.tsx @@ -1,13 +1,12 @@ import * as React from 'react'; import { createPreset } from '../createPreset'; import type { TextPresetProps } from '../../Text/Text.types'; -import { body1ClassNames, useBody1Styles } from './useBody1Styles.styles'; +import { useBody1Styles } from './useBody1Styles.styles'; /** * Text preset component for the Body1 typography variant */ export const Body1: React.FunctionComponent = createPreset({ useStyles: useBody1Styles, - className: body1ClassNames.root, displayName: 'Body1', }); diff --git a/packages/react-components/react-text/library/src/components/presets/Body1/useBody1Styles.headless.ts b/packages/react-components/react-text/library/src/components/presets/Body1/useBody1Styles.headless.ts new file mode 100644 index 0000000000000..dd66393387be8 --- /dev/null +++ b/packages/react-components/react-text/library/src/components/presets/Body1/useBody1Styles.headless.ts @@ -0,0 +1,12 @@ +import { getComponentSlotClassName, type SlotClassNames } from '@fluentui/react-utilities'; +import { TextSlots, TextState } from '../../Text/Text.types'; + +export const body1ClassNames: SlotClassNames = { + root: 'fui-Body1', +}; + +export const useBody1Styles = (state: TextState): TextState => { + state.root.className = getComponentSlotClassName(body1ClassNames.root, state.root); + + return state; +}; diff --git a/packages/react-components/react-text/library/src/components/presets/Body1/useBody1Styles.styles.ts b/packages/react-components/react-text/library/src/components/presets/Body1/useBody1Styles.styles.ts index 0df28b21d38eb..6517f80bbee5e 100644 --- a/packages/react-components/react-text/library/src/components/presets/Body1/useBody1Styles.styles.ts +++ b/packages/react-components/react-text/library/src/components/presets/Body1/useBody1Styles.styles.ts @@ -1,6 +1,6 @@ -import { makeStyles } from '@griffel/react'; +import { makeStyles, mergeClasses } from '@griffel/react'; import { SlotClassNames } from '@fluentui/react-utilities'; -import type { TextSlots } from '../../Text/Text.types'; +import type { TextSlots, TextState } from '../../Text/Text.types'; import { typographyStyles } from '@fluentui/react-theme'; export const body1ClassNames: SlotClassNames = { @@ -10,6 +10,14 @@ export const body1ClassNames: SlotClassNames = { /** * Styles for the root slot */ -export const useBody1Styles = makeStyles({ +const useStyles = makeStyles({ root: typographyStyles.body1, }); + +export const useBody1Styles = (state: TextState): TextState => { + const styles = useStyles(); + + state.root.className = mergeClasses(body1ClassNames.root, styles.root, state.root.className); + + return state; +}; diff --git a/packages/react-components/react-text/library/src/components/presets/Body1Strong/Body1Strong.tsx b/packages/react-components/react-text/library/src/components/presets/Body1Strong/Body1Strong.tsx index a141e8a5c5db2..f59c6ba0c8e60 100644 --- a/packages/react-components/react-text/library/src/components/presets/Body1Strong/Body1Strong.tsx +++ b/packages/react-components/react-text/library/src/components/presets/Body1Strong/Body1Strong.tsx @@ -1,13 +1,12 @@ import * as React from 'react'; import { createPreset } from '../createPreset'; import type { TextPresetProps } from '../../Text/Text.types'; -import { body1StrongClassNames, useBody1StrongStyles } from './useBody1StrongStyles.styles'; +import { useBody1StrongStyles } from './useBody1StrongStyles.styles'; /** * Text preset component for the Body1Strong typography variant */ export const Body1Strong: React.FunctionComponent = createPreset({ useStyles: useBody1StrongStyles, - className: body1StrongClassNames.root, displayName: 'Body1Strong', }); diff --git a/packages/react-components/react-text/library/src/components/presets/Body1Strong/useBody1StrongStyles.headless.ts b/packages/react-components/react-text/library/src/components/presets/Body1Strong/useBody1StrongStyles.headless.ts new file mode 100644 index 0000000000000..a08818daf2b3d --- /dev/null +++ b/packages/react-components/react-text/library/src/components/presets/Body1Strong/useBody1StrongStyles.headless.ts @@ -0,0 +1,12 @@ +import { getComponentSlotClassName, type SlotClassNames } from '@fluentui/react-utilities'; +import { TextSlots, TextState } from '../../Text/Text.types'; + +export const body1StrongClassNames: SlotClassNames = { + root: 'fui-Body1Strong', +}; + +export const useBody1StrongStyles = (state: TextState): TextState => { + state.root.className = getComponentSlotClassName(body1StrongClassNames.root, state.root); + + return state; +}; diff --git a/packages/react-components/react-text/library/src/components/presets/Body1Strong/useBody1StrongStyles.styles.ts b/packages/react-components/react-text/library/src/components/presets/Body1Strong/useBody1StrongStyles.styles.ts index a29f3e9c1702f..34fb445f81a05 100644 --- a/packages/react-components/react-text/library/src/components/presets/Body1Strong/useBody1StrongStyles.styles.ts +++ b/packages/react-components/react-text/library/src/components/presets/Body1Strong/useBody1StrongStyles.styles.ts @@ -1,6 +1,6 @@ -import { makeStyles } from '@griffel/react'; -import { SlotClassNames } from '@fluentui/react-utilities'; -import type { TextSlots } from '../../Text/Text.types'; +import { makeStyles, mergeClasses } from '@griffel/react'; +import type { SlotClassNames } from '@fluentui/react-utilities'; +import type { TextSlots, TextState } from '../../Text/Text.types'; import { typographyStyles } from '@fluentui/react-theme'; export const body1StrongClassNames: SlotClassNames = { @@ -10,6 +10,15 @@ export const body1StrongClassNames: SlotClassNames = { /** * Styles for the root slot */ -export const useBody1StrongStyles = makeStyles({ + +const useStyles = makeStyles({ root: typographyStyles.body1Strong, }); + +export const useBody1StrongStyles = (state: TextState): TextState => { + const styles = useStyles(); + + state.root.className = mergeClasses(body1StrongClassNames.root, styles.root, state.root.className); + + return state; +}; diff --git a/packages/react-components/react-text/library/src/components/presets/Body1Stronger/Body1Stronger.tsx b/packages/react-components/react-text/library/src/components/presets/Body1Stronger/Body1Stronger.tsx index 7888663a18764..423b3a0da3f34 100644 --- a/packages/react-components/react-text/library/src/components/presets/Body1Stronger/Body1Stronger.tsx +++ b/packages/react-components/react-text/library/src/components/presets/Body1Stronger/Body1Stronger.tsx @@ -1,13 +1,12 @@ import * as React from 'react'; import { createPreset } from '../createPreset'; import type { TextPresetProps } from '../../Text/Text.types'; -import { body1StrongerClassNames, useBody1StrongerStyles } from './useBody1StrongerStyles.styles'; +import { useBody1StrongerStyles } from './useBody1StrongerStyles.styles'; /** * Text preset component for the Body1Stronger typography variant */ export const Body1Stronger: React.FunctionComponent = createPreset({ useStyles: useBody1StrongerStyles, - className: body1StrongerClassNames.root, displayName: 'Body1Stronger', }); diff --git a/packages/react-components/react-text/library/src/components/presets/Body1Stronger/useBody1StrongerStyles.headless.ts b/packages/react-components/react-text/library/src/components/presets/Body1Stronger/useBody1StrongerStyles.headless.ts new file mode 100644 index 0000000000000..995de1752d34b --- /dev/null +++ b/packages/react-components/react-text/library/src/components/presets/Body1Stronger/useBody1StrongerStyles.headless.ts @@ -0,0 +1,12 @@ +import { getComponentSlotClassName, type SlotClassNames } from '@fluentui/react-utilities'; +import { TextSlots, TextState } from '../../Text/Text.types'; + +export const body1StrongerClassNames: SlotClassNames = { + root: 'fui-Body1Stronger', +}; + +export const useBody1StrongerStyles = (state: TextState): TextState => { + state.root.className = getComponentSlotClassName(body1StrongerClassNames.root, state.root); + + return state; +}; diff --git a/packages/react-components/react-text/library/src/components/presets/Body1Stronger/useBody1StrongerStyles.styles.ts b/packages/react-components/react-text/library/src/components/presets/Body1Stronger/useBody1StrongerStyles.styles.ts index cb883ab7e0846..f4ab2fa848df3 100644 --- a/packages/react-components/react-text/library/src/components/presets/Body1Stronger/useBody1StrongerStyles.styles.ts +++ b/packages/react-components/react-text/library/src/components/presets/Body1Stronger/useBody1StrongerStyles.styles.ts @@ -1,6 +1,6 @@ -import { makeStyles } from '@griffel/react'; +import { makeStyles, mergeClasses } from '@griffel/react'; import { SlotClassNames } from '@fluentui/react-utilities'; -import type { TextSlots } from '../../Text/Text.types'; +import type { TextSlots, TextState } from '../../Text/Text.types'; import { typographyStyles } from '@fluentui/react-theme'; export const body1StrongerClassNames: SlotClassNames = { @@ -10,6 +10,14 @@ export const body1StrongerClassNames: SlotClassNames = { /** * Styles for the root slot */ -export const useBody1StrongerStyles = makeStyles({ +const useStyles = makeStyles({ root: typographyStyles.body1Stronger, }); + +export const useBody1StrongerStyles = (state: TextState): TextState => { + const styles = useStyles(); + + state.root.className = mergeClasses(body1StrongerClassNames.root, styles.root, state.root.className); + + return state; +}; diff --git a/packages/react-components/react-text/library/src/components/presets/Body2/Body2.tsx b/packages/react-components/react-text/library/src/components/presets/Body2/Body2.tsx index e8890915931a1..e6c2d0e81c8aa 100644 --- a/packages/react-components/react-text/library/src/components/presets/Body2/Body2.tsx +++ b/packages/react-components/react-text/library/src/components/presets/Body2/Body2.tsx @@ -1,13 +1,12 @@ import * as React from 'react'; import { createPreset } from '../createPreset'; import type { TextPresetProps } from '../../Text/Text.types'; -import { body2ClassNames, useBody2Styles } from './useBody2Styles.styles'; +import { useBody2Styles } from './useBody2Styles.styles'; /** * Text preset component for the Body2 typography variant */ export const Body2: React.FunctionComponent = createPreset({ useStyles: useBody2Styles, - className: body2ClassNames.root, displayName: 'Body2', }); diff --git a/packages/react-components/react-text/library/src/components/presets/Body2/useBody2Styles.headless.ts b/packages/react-components/react-text/library/src/components/presets/Body2/useBody2Styles.headless.ts new file mode 100644 index 0000000000000..49c9c3127875b --- /dev/null +++ b/packages/react-components/react-text/library/src/components/presets/Body2/useBody2Styles.headless.ts @@ -0,0 +1,12 @@ +import { getComponentSlotClassName, type SlotClassNames } from '@fluentui/react-utilities'; +import { TextSlots, TextState } from '../../Text/Text.types'; + +export const body2ClassNames: SlotClassNames = { + root: 'fui-Body2', +}; + +export const useBody2Styles = (state: TextState): TextState => { + state.root.className = getComponentSlotClassName(body2ClassNames.root, state.root); + + return state; +}; diff --git a/packages/react-components/react-text/library/src/components/presets/Body2/useBody2Styles.styles.ts b/packages/react-components/react-text/library/src/components/presets/Body2/useBody2Styles.styles.ts index 116208d5d3834..869f3760fc26c 100644 --- a/packages/react-components/react-text/library/src/components/presets/Body2/useBody2Styles.styles.ts +++ b/packages/react-components/react-text/library/src/components/presets/Body2/useBody2Styles.styles.ts @@ -1,6 +1,6 @@ -import { makeStyles } from '@griffel/react'; +import { makeStyles, mergeClasses } from '@griffel/react'; import { SlotClassNames } from '@fluentui/react-utilities'; -import type { TextSlots } from '../../Text/Text.types'; +import type { TextSlots, TextState } from '../../Text/Text.types'; import { typographyStyles } from '@fluentui/react-theme'; export const body2ClassNames: SlotClassNames = { @@ -10,6 +10,14 @@ export const body2ClassNames: SlotClassNames = { /** * Styles for the root slot */ -export const useBody2Styles = makeStyles({ +const useStyles = makeStyles({ root: typographyStyles.body2, }); + +export const useBody2Styles = (state: TextState): TextState => { + const styles = useStyles(); + + state.root.className = mergeClasses(body2ClassNames.root, styles.root, state.root.className); + + return state; +}; diff --git a/packages/react-components/react-text/library/src/components/presets/Caption1/Caption1.tsx b/packages/react-components/react-text/library/src/components/presets/Caption1/Caption1.tsx index fb218b9c125b0..770413d8b0bb9 100644 --- a/packages/react-components/react-text/library/src/components/presets/Caption1/Caption1.tsx +++ b/packages/react-components/react-text/library/src/components/presets/Caption1/Caption1.tsx @@ -1,13 +1,12 @@ import * as React from 'react'; import { createPreset } from '../createPreset'; import type { TextPresetProps } from '../../Text/Text.types'; -import { caption1ClassNames, useCaption1Styles } from './useCaption1Styles.styles'; +import { useCaption1Styles } from './useCaption1Styles.styles'; /** * Text preset component for the Caption1 typography variant */ export const Caption1: React.FunctionComponent = createPreset({ useStyles: useCaption1Styles, - className: caption1ClassNames.root, displayName: 'Caption1', }); diff --git a/packages/react-components/react-text/library/src/components/presets/Caption1/useCaption1Styles.headless.ts b/packages/react-components/react-text/library/src/components/presets/Caption1/useCaption1Styles.headless.ts new file mode 100644 index 0000000000000..8724f7ce6b4bf --- /dev/null +++ b/packages/react-components/react-text/library/src/components/presets/Caption1/useCaption1Styles.headless.ts @@ -0,0 +1,12 @@ +import { getComponentSlotClassName, type SlotClassNames } from '@fluentui/react-utilities'; +import { TextSlots, TextState } from '../../Text/Text.types'; + +export const caption1ClassNames: SlotClassNames = { + root: 'fui-Caption1', +}; + +export const useCaption1Styles = (state: TextState): TextState => { + state.root.className = getComponentSlotClassName(caption1ClassNames.root, state.root); + + return state; +}; diff --git a/packages/react-components/react-text/library/src/components/presets/Caption1/useCaption1Styles.styles.ts b/packages/react-components/react-text/library/src/components/presets/Caption1/useCaption1Styles.styles.ts index cff14d3f68638..644211356229b 100644 --- a/packages/react-components/react-text/library/src/components/presets/Caption1/useCaption1Styles.styles.ts +++ b/packages/react-components/react-text/library/src/components/presets/Caption1/useCaption1Styles.styles.ts @@ -1,6 +1,6 @@ -import { makeStyles } from '@griffel/react'; +import { makeStyles, mergeClasses } from '@griffel/react'; import { SlotClassNames } from '@fluentui/react-utilities'; -import type { TextSlots } from '../../Text/Text.types'; +import type { TextSlots, TextState } from '../../Text/Text.types'; import { typographyStyles } from '@fluentui/react-theme'; export const caption1ClassNames: SlotClassNames = { @@ -10,6 +10,14 @@ export const caption1ClassNames: SlotClassNames = { /** * Styles for the root slot */ -export const useCaption1Styles = makeStyles({ +const useStyles = makeStyles({ root: typographyStyles.caption1, }); + +export const useCaption1Styles = (state: TextState): TextState => { + const styles = useStyles(); + + state.root.className = mergeClasses(caption1ClassNames.root, styles.root, state.root.className); + + return state; +}; diff --git a/packages/react-components/react-text/library/src/components/presets/Caption1Strong/Caption1Strong.tsx b/packages/react-components/react-text/library/src/components/presets/Caption1Strong/Caption1Strong.tsx index e7bcf1d044103..70edd1203f47f 100644 --- a/packages/react-components/react-text/library/src/components/presets/Caption1Strong/Caption1Strong.tsx +++ b/packages/react-components/react-text/library/src/components/presets/Caption1Strong/Caption1Strong.tsx @@ -1,13 +1,12 @@ import * as React from 'react'; import { createPreset } from '../createPreset'; import type { TextPresetProps } from '../../Text/Text.types'; -import { caption1StrongClassNames, useCaption1StrongStyles } from './useCaption1StrongStyles.styles'; +import { useCaption1StrongStyles } from './useCaption1StrongStyles.styles'; /** * Text preset component for the Caption1Strong typography variant */ export const Caption1Strong: React.FunctionComponent = createPreset({ useStyles: useCaption1StrongStyles, - className: caption1StrongClassNames.root, displayName: 'Caption1Strong', }); diff --git a/packages/react-components/react-text/library/src/components/presets/Caption1Strong/useCaption1Strong.styles.headless.ts b/packages/react-components/react-text/library/src/components/presets/Caption1Strong/useCaption1Strong.styles.headless.ts new file mode 100644 index 0000000000000..56447ecbf1d92 --- /dev/null +++ b/packages/react-components/react-text/library/src/components/presets/Caption1Strong/useCaption1Strong.styles.headless.ts @@ -0,0 +1,11 @@ +import type { SlotClassNames } from '@fluentui/react-utilities'; +import { getComponentSlotClassName } from '@fluentui/react-utilities'; +import type { TextSlots, TextState } from '../../Text/Text.types'; + +export const caption1StrongClassNames: SlotClassNames = { + root: 'fui-Caption1Strong', +}; +export const useCaption1StrongStyles_unstable = (state: TextState): TextState => { + state.root.className = getComponentSlotClassName(caption1StrongClassNames.root, state.root); + return state; +}; diff --git a/packages/react-components/react-text/library/src/components/presets/Caption1Strong/useCaption1StrongStyles.styles.ts b/packages/react-components/react-text/library/src/components/presets/Caption1Strong/useCaption1StrongStyles.styles.ts index 0e9512d9753ba..b54b06543eb36 100644 --- a/packages/react-components/react-text/library/src/components/presets/Caption1Strong/useCaption1StrongStyles.styles.ts +++ b/packages/react-components/react-text/library/src/components/presets/Caption1Strong/useCaption1StrongStyles.styles.ts @@ -1,6 +1,6 @@ -import { makeStyles } from '@griffel/react'; +import { makeStyles, mergeClasses } from '@griffel/react'; import { SlotClassNames } from '@fluentui/react-utilities'; -import type { TextSlots } from '../../Text/Text.types'; +import type { TextSlots, TextState } from '../../Text/Text.types'; import { typographyStyles } from '@fluentui/react-theme'; export const caption1StrongClassNames: SlotClassNames = { @@ -10,6 +10,14 @@ export const caption1StrongClassNames: SlotClassNames = { /** * Styles for the root slot */ -export const useCaption1StrongStyles = makeStyles({ +const useStyles = makeStyles({ root: typographyStyles.caption1Strong, }); + +export const useCaption1StrongStyles = (state: TextState): TextState => { + const styles = useStyles(); + + state.root.className = mergeClasses(caption1StrongClassNames.root, styles.root, state.root.className); + + return state; +}; diff --git a/packages/react-components/react-text/library/src/components/presets/Caption1Stronger/Caption1Stronger.tsx b/packages/react-components/react-text/library/src/components/presets/Caption1Stronger/Caption1Stronger.tsx index a75e250a85d04..95fa6e2470fbf 100644 --- a/packages/react-components/react-text/library/src/components/presets/Caption1Stronger/Caption1Stronger.tsx +++ b/packages/react-components/react-text/library/src/components/presets/Caption1Stronger/Caption1Stronger.tsx @@ -1,13 +1,12 @@ import * as React from 'react'; import { createPreset } from '../createPreset'; import type { TextPresetProps } from '../../Text/Text.types'; -import { caption1StrongerClassNames, useCaption1StrongerStyles } from './useCaption1Stronger.styles'; +import { useCaption1StrongerStyles } from './useCaption1Stronger.styles'; /** * Text preset component for the Caption1Stronger typography variant */ export const Caption1Stronger: React.FunctionComponent = createPreset({ useStyles: useCaption1StrongerStyles, - className: caption1StrongerClassNames.root, displayName: 'Caption1Stronger', }); diff --git a/packages/react-components/react-text/library/src/components/presets/Caption1Stronger/useCaption1Stronger.styles.headless.ts b/packages/react-components/react-text/library/src/components/presets/Caption1Stronger/useCaption1Stronger.styles.headless.ts new file mode 100644 index 0000000000000..a31f30832b706 --- /dev/null +++ b/packages/react-components/react-text/library/src/components/presets/Caption1Stronger/useCaption1Stronger.styles.headless.ts @@ -0,0 +1,12 @@ +import { getComponentSlotClassName, type SlotClassNames } from '@fluentui/react-utilities'; +import { TextSlots, TextState } from '../../Text/Text.types'; + +export const caption1StrongerClassNames: SlotClassNames = { + root: 'fui-Caption1Stronger', +}; + +export const useCaption1StrongerStyles = (state: TextState): TextState => { + state.root.className = getComponentSlotClassName(caption1StrongerClassNames.root, state.root); + + return state; +}; diff --git a/packages/react-components/react-text/library/src/components/presets/Caption1Stronger/useCaption1Stronger.styles.ts b/packages/react-components/react-text/library/src/components/presets/Caption1Stronger/useCaption1Stronger.styles.ts index 57094df4c6767..f6470b10d5fe9 100644 --- a/packages/react-components/react-text/library/src/components/presets/Caption1Stronger/useCaption1Stronger.styles.ts +++ b/packages/react-components/react-text/library/src/components/presets/Caption1Stronger/useCaption1Stronger.styles.ts @@ -1,6 +1,6 @@ -import { makeStyles } from '@griffel/react'; +import { makeStyles, mergeClasses } from '@griffel/react'; import { SlotClassNames } from '@fluentui/react-utilities'; -import type { TextSlots } from '../../Text/Text.types'; +import type { TextSlots, TextState } from '../../Text/Text.types'; import { typographyStyles } from '@fluentui/react-theme'; export const caption1StrongerClassNames: SlotClassNames = { @@ -10,6 +10,14 @@ export const caption1StrongerClassNames: SlotClassNames = { /** * Styles for the root slot */ -export const useCaption1StrongerStyles = makeStyles({ +const useStyles = makeStyles({ root: typographyStyles.caption1Stronger, }); + +export const useCaption1StrongerStyles = (state: TextState): TextState => { + const styles = useStyles(); + + state.root.className = mergeClasses(caption1StrongerClassNames.root, styles.root, state.root.className); + + return state; +}; diff --git a/packages/react-components/react-text/library/src/components/presets/Caption2/Caption2.tsx b/packages/react-components/react-text/library/src/components/presets/Caption2/Caption2.tsx index 2e04cbb0fb58c..50684d41afde2 100644 --- a/packages/react-components/react-text/library/src/components/presets/Caption2/Caption2.tsx +++ b/packages/react-components/react-text/library/src/components/presets/Caption2/Caption2.tsx @@ -1,13 +1,12 @@ import * as React from 'react'; import { createPreset } from '../createPreset'; import type { TextPresetProps } from '../../Text/Text.types'; -import { caption2ClassNames, useCaption2Styles } from './useCaption2Styles.styles'; +import { useCaption2Styles } from './useCaption2Styles.styles'; /** * Text preset component for the Caption2 typography variant */ export const Caption2: React.FunctionComponent = createPreset({ useStyles: useCaption2Styles, - className: caption2ClassNames.root, displayName: 'Caption2', }); diff --git a/packages/react-components/react-text/library/src/components/presets/Caption2/useCaption2Styles.headless.ts b/packages/react-components/react-text/library/src/components/presets/Caption2/useCaption2Styles.headless.ts new file mode 100644 index 0000000000000..d6696b1e7869e --- /dev/null +++ b/packages/react-components/react-text/library/src/components/presets/Caption2/useCaption2Styles.headless.ts @@ -0,0 +1,12 @@ +import { getComponentSlotClassName, type SlotClassNames } from '@fluentui/react-utilities'; +import { TextSlots, TextState } from '../../Text/Text.types'; + +export const caption2ClassNames: SlotClassNames = { + root: 'fui-Caption2', +}; + +export const useCaption2Styles = (state: TextState): TextState => { + state.root.className = getComponentSlotClassName(caption2ClassNames.root, state.root); + + return state; +}; diff --git a/packages/react-components/react-text/library/src/components/presets/Caption2/useCaption2Styles.styles.ts b/packages/react-components/react-text/library/src/components/presets/Caption2/useCaption2Styles.styles.ts index 3b91b20030bae..5e161a8257d31 100644 --- a/packages/react-components/react-text/library/src/components/presets/Caption2/useCaption2Styles.styles.ts +++ b/packages/react-components/react-text/library/src/components/presets/Caption2/useCaption2Styles.styles.ts @@ -1,6 +1,6 @@ -import { makeStyles } from '@griffel/react'; +import { makeStyles, mergeClasses } from '@griffel/react'; import { SlotClassNames } from '@fluentui/react-utilities'; -import type { TextSlots } from '../../Text/Text.types'; +import type { TextSlots, TextState } from '../../Text/Text.types'; import { typographyStyles } from '@fluentui/react-theme'; export const caption2ClassNames: SlotClassNames = { @@ -10,6 +10,14 @@ export const caption2ClassNames: SlotClassNames = { /** * Styles for the root slot */ -export const useCaption2Styles = makeStyles({ +const useStyles = makeStyles({ root: typographyStyles.caption2, }); + +export const useCaption2Styles = (state: TextState): TextState => { + const styles = useStyles(); + + state.root.className = mergeClasses(caption2ClassNames.root, styles.root, state.root.className); + + return state; +}; diff --git a/packages/react-components/react-text/library/src/components/presets/Caption2Strong/Caption2Strong.tsx b/packages/react-components/react-text/library/src/components/presets/Caption2Strong/Caption2Strong.tsx index dec57fd5b13b5..3208f5a7138af 100644 --- a/packages/react-components/react-text/library/src/components/presets/Caption2Strong/Caption2Strong.tsx +++ b/packages/react-components/react-text/library/src/components/presets/Caption2Strong/Caption2Strong.tsx @@ -2,13 +2,12 @@ import * as React from 'react'; import { createPreset } from '../createPreset'; import type { TextPresetProps } from '../../Text/Text.types'; -import { caption2StrongClassNames, useCaption2StrongStyles } from './useCaption2StrongStyles.styles'; +import { useCaption2StrongStyles } from './useCaption2StrongStyles.styles'; /** * Text preset component for the Caption2Strong typography variant */ export const Caption2Strong: React.FunctionComponent = createPreset({ useStyles: useCaption2StrongStyles, - className: caption2StrongClassNames.root, displayName: 'Caption2Strong', }); diff --git a/packages/react-components/react-text/library/src/components/presets/Caption2Strong/useCaption2Strong.styles.headless.ts b/packages/react-components/react-text/library/src/components/presets/Caption2Strong/useCaption2Strong.styles.headless.ts new file mode 100644 index 0000000000000..5b12ef370013e --- /dev/null +++ b/packages/react-components/react-text/library/src/components/presets/Caption2Strong/useCaption2Strong.styles.headless.ts @@ -0,0 +1,12 @@ +import { getComponentSlotClassName, type SlotClassNames } from '@fluentui/react-utilities'; +import { TextSlots, TextState } from '../../Text/Text.types'; + +export const caption2StrongClassNames: SlotClassNames = { + root: 'fui-Caption2Strong', +}; + +export const useCaption2StrongStyles = (state: TextState): TextState => { + state.root.className = getComponentSlotClassName(caption2StrongClassNames.root, state.root); + + return state; +}; diff --git a/packages/react-components/react-text/library/src/components/presets/Caption2Strong/useCaption2StrongStyles.styles.ts b/packages/react-components/react-text/library/src/components/presets/Caption2Strong/useCaption2StrongStyles.styles.ts index 7f8770d425567..88c8546124078 100644 --- a/packages/react-components/react-text/library/src/components/presets/Caption2Strong/useCaption2StrongStyles.styles.ts +++ b/packages/react-components/react-text/library/src/components/presets/Caption2Strong/useCaption2StrongStyles.styles.ts @@ -1,6 +1,6 @@ -import { makeStyles } from '@griffel/react'; +import { makeStyles, mergeClasses } from '@griffel/react'; import { SlotClassNames } from '@fluentui/react-utilities'; -import type { TextSlots } from '../../Text/Text.types'; +import type { TextSlots, TextState } from '../../Text/Text.types'; import { typographyStyles } from '@fluentui/react-theme'; export const caption2StrongClassNames: SlotClassNames = { @@ -10,6 +10,14 @@ export const caption2StrongClassNames: SlotClassNames = { /** * Styles for the root slot */ -export const useCaption2StrongStyles = makeStyles({ +const useStyles = makeStyles({ root: typographyStyles.caption2Strong, }); + +export const useCaption2StrongStyles = (state: TextState): TextState => { + const styles = useStyles(); + + state.root.className = mergeClasses(caption2StrongClassNames.root, styles.root, state.root.className); + + return state; +}; diff --git a/packages/react-components/react-text/library/src/components/presets/Display/Display.tsx b/packages/react-components/react-text/library/src/components/presets/Display/Display.tsx index 2a6de3425b97a..60ad273e2018e 100644 --- a/packages/react-components/react-text/library/src/components/presets/Display/Display.tsx +++ b/packages/react-components/react-text/library/src/components/presets/Display/Display.tsx @@ -1,13 +1,12 @@ import * as React from 'react'; import { createPreset } from '../createPreset'; import type { TextPresetProps } from '../../Text/Text.types'; -import { displayClassNames, useDisplayStyles } from './useDisplayStyles.styles'; +import { useDisplayStyles } from './useDisplayStyles.styles'; /** * Text preset component for the Display typography variant */ export const Display: React.FunctionComponent = createPreset({ useStyles: useDisplayStyles, - className: displayClassNames.root, displayName: 'Display', }); diff --git a/packages/react-components/react-text/library/src/components/presets/Display/useDisplayStyles.headless.ts b/packages/react-components/react-text/library/src/components/presets/Display/useDisplayStyles.headless.ts new file mode 100644 index 0000000000000..750c261e64c27 --- /dev/null +++ b/packages/react-components/react-text/library/src/components/presets/Display/useDisplayStyles.headless.ts @@ -0,0 +1,13 @@ +import type { SlotClassNames } from '@fluentui/react-utilities'; +import { getComponentSlotClassName } from '@fluentui/react-utilities'; +import type { TextSlots, TextState } from '../../Text/Text.types'; + +export const displayClassNames: SlotClassNames = { + root: 'fui-Display', +}; + +export const useDisplayStyles_unstable = (state: TextState): TextState => { + state.root.className = getComponentSlotClassName(displayClassNames.root, state.root); + + return state; +}; diff --git a/packages/react-components/react-text/library/src/components/presets/Display/useDisplayStyles.styles.ts b/packages/react-components/react-text/library/src/components/presets/Display/useDisplayStyles.styles.ts index 354c41720f213..d0c7b09c2d11b 100644 --- a/packages/react-components/react-text/library/src/components/presets/Display/useDisplayStyles.styles.ts +++ b/packages/react-components/react-text/library/src/components/presets/Display/useDisplayStyles.styles.ts @@ -1,6 +1,6 @@ -import { makeStyles } from '@griffel/react'; +import { makeStyles, mergeClasses } from '@griffel/react'; import { SlotClassNames } from '@fluentui/react-utilities'; -import type { TextSlots } from '../../Text/Text.types'; +import type { TextSlots, TextState } from '../../Text/Text.types'; import { typographyStyles } from '@fluentui/react-theme'; export const displayClassNames: SlotClassNames = { @@ -10,6 +10,14 @@ export const displayClassNames: SlotClassNames = { /** * Styles for the root slot */ -export const useDisplayStyles = makeStyles({ +const useStyles = makeStyles({ root: typographyStyles.display, }); + +export const useDisplayStyles = (state: TextState): TextState => { + const styles = useStyles(); + + state.root.className = mergeClasses(displayClassNames.root, styles.root, state.root.className); + + return state; +}; diff --git a/packages/react-components/react-text/library/src/components/presets/LargeTitle/LargeTitle.tsx b/packages/react-components/react-text/library/src/components/presets/LargeTitle/LargeTitle.tsx index 1bfaba1dbd9dc..25c9f5bbdf462 100644 --- a/packages/react-components/react-text/library/src/components/presets/LargeTitle/LargeTitle.tsx +++ b/packages/react-components/react-text/library/src/components/presets/LargeTitle/LargeTitle.tsx @@ -1,13 +1,12 @@ import * as React from 'react'; import { createPreset } from '../createPreset'; import type { TextPresetProps } from '../../Text/Text.types'; -import { largeTitleClassNames, useLargeTitleStyles } from './useLargeTitleStyles.styles'; +import { useLargeTitleStyles } from './useLargeTitleStyles.styles'; /** * Text preset component for the Large Title typography variant */ export const LargeTitle: React.FunctionComponent = createPreset({ useStyles: useLargeTitleStyles, - className: largeTitleClassNames.root, displayName: 'LargeTitle', }); diff --git a/packages/react-components/react-text/library/src/components/presets/LargeTitle/useLargeTitleStyles.headless.ts b/packages/react-components/react-text/library/src/components/presets/LargeTitle/useLargeTitleStyles.headless.ts new file mode 100644 index 0000000000000..304b3b10694f6 --- /dev/null +++ b/packages/react-components/react-text/library/src/components/presets/LargeTitle/useLargeTitleStyles.headless.ts @@ -0,0 +1,12 @@ +import { getComponentSlotClassName, type SlotClassNames } from '@fluentui/react-utilities'; +import { TextSlots, TextState } from '../../Text/Text.types'; + +export const largeTitleClassNames: SlotClassNames = { + root: 'fui-LargeTitle', +}; + +export const useLargeTitleStyles = (state: TextState): TextState => { + state.root.className = getComponentSlotClassName(largeTitleClassNames.root, state.root); + + return state; +}; diff --git a/packages/react-components/react-text/library/src/components/presets/LargeTitle/useLargeTitleStyles.styles.ts b/packages/react-components/react-text/library/src/components/presets/LargeTitle/useLargeTitleStyles.styles.ts index 864703643dcc3..7030c761b2298 100644 --- a/packages/react-components/react-text/library/src/components/presets/LargeTitle/useLargeTitleStyles.styles.ts +++ b/packages/react-components/react-text/library/src/components/presets/LargeTitle/useLargeTitleStyles.styles.ts @@ -1,6 +1,6 @@ -import { makeStyles } from '@griffel/react'; +import { makeStyles, mergeClasses } from '@griffel/react'; import { SlotClassNames } from '@fluentui/react-utilities'; -import type { TextSlots } from '../../Text/Text.types'; +import type { TextSlots, TextState } from '../../Text/Text.types'; import { typographyStyles } from '@fluentui/react-theme'; export const largeTitleClassNames: SlotClassNames = { @@ -10,6 +10,14 @@ export const largeTitleClassNames: SlotClassNames = { /** * Styles for the root slot */ -export const useLargeTitleStyles = makeStyles({ +const useStyles = makeStyles({ root: typographyStyles.largeTitle, }); + +export const useLargeTitleStyles = (state: TextState): TextState => { + const styles = useStyles(); + + state.root.className = mergeClasses(largeTitleClassNames.root, styles.root, state.root.className); + + return state; +}; diff --git a/packages/react-components/react-text/library/src/components/presets/Subtitle1/Subtitle1.tsx b/packages/react-components/react-text/library/src/components/presets/Subtitle1/Subtitle1.tsx index 26e0cc3a65ad7..0f4e7ea140e54 100644 --- a/packages/react-components/react-text/library/src/components/presets/Subtitle1/Subtitle1.tsx +++ b/packages/react-components/react-text/library/src/components/presets/Subtitle1/Subtitle1.tsx @@ -1,13 +1,12 @@ import * as React from 'react'; import { createPreset } from '../createPreset'; import type { TextPresetProps } from '../../Text/Text.types'; -import { subtitle1ClassNames, useSubtitle1Styles } from './useSubtitle1Styles.styles'; +import { useSubtitle1Styles } from './useSubtitle1Styles.styles'; /** * Text preset component for the Subtitle1 typography variant */ export const Subtitle1: React.FunctionComponent = createPreset({ useStyles: useSubtitle1Styles, - className: subtitle1ClassNames.root, displayName: 'Subtitle1', }); diff --git a/packages/react-components/react-text/library/src/components/presets/Subtitle1/useSubtitle1Styles.headless.ts b/packages/react-components/react-text/library/src/components/presets/Subtitle1/useSubtitle1Styles.headless.ts new file mode 100644 index 0000000000000..0bb5482ec7d80 --- /dev/null +++ b/packages/react-components/react-text/library/src/components/presets/Subtitle1/useSubtitle1Styles.headless.ts @@ -0,0 +1,12 @@ +import { getComponentSlotClassName, type SlotClassNames } from '@fluentui/react-utilities'; +import { TextSlots, TextState } from '../../Text/Text.types'; + +export const subtitle1ClassNames: SlotClassNames = { + root: 'fui-Subtitle1', +}; + +export const useSubtitle1Styles = (state: TextState): TextState => { + state.root.className = getComponentSlotClassName(subtitle1ClassNames.root, state.root); + + return state; +}; diff --git a/packages/react-components/react-text/library/src/components/presets/Subtitle1/useSubtitle1Styles.styles.ts b/packages/react-components/react-text/library/src/components/presets/Subtitle1/useSubtitle1Styles.styles.ts index 06f48757cca04..c085ed9c4196b 100644 --- a/packages/react-components/react-text/library/src/components/presets/Subtitle1/useSubtitle1Styles.styles.ts +++ b/packages/react-components/react-text/library/src/components/presets/Subtitle1/useSubtitle1Styles.styles.ts @@ -1,6 +1,6 @@ -import { makeStyles } from '@griffel/react'; +import { makeStyles, mergeClasses } from '@griffel/react'; import { SlotClassNames } from '@fluentui/react-utilities'; -import type { TextSlots } from '../../Text/Text.types'; +import type { TextSlots, TextState } from '../../Text/Text.types'; import { typographyStyles } from '@fluentui/react-theme'; export const subtitle1ClassNames: SlotClassNames = { @@ -10,6 +10,14 @@ export const subtitle1ClassNames: SlotClassNames = { /** * Styles for the root slot */ -export const useSubtitle1Styles = makeStyles({ +const useStyles = makeStyles({ root: typographyStyles.subtitle1, }); + +export const useSubtitle1Styles = (state: TextState): TextState => { + const styles = useStyles(); + + state.root.className = mergeClasses(subtitle1ClassNames.root, styles.root, state.root.className); + + return state; +}; diff --git a/packages/react-components/react-text/library/src/components/presets/Subtitle2/Subtitle2.tsx b/packages/react-components/react-text/library/src/components/presets/Subtitle2/Subtitle2.tsx index 90d59875956a5..46ece052700e7 100644 --- a/packages/react-components/react-text/library/src/components/presets/Subtitle2/Subtitle2.tsx +++ b/packages/react-components/react-text/library/src/components/presets/Subtitle2/Subtitle2.tsx @@ -1,13 +1,12 @@ import * as React from 'react'; import { createPreset } from '../createPreset'; import type { TextPresetProps } from '../../Text/Text.types'; -import { subtitle2ClassNames, useSubtitle2Styles } from './useSubtitle2Styles.styles'; +import { useSubtitle2Styles } from './useSubtitle2Styles.styles'; /** * Text preset component for the Subtitle2 typography variant */ export const Subtitle2: React.FunctionComponent = createPreset({ useStyles: useSubtitle2Styles, - className: subtitle2ClassNames.root, displayName: 'Subtitle2', }); diff --git a/packages/react-components/react-text/library/src/components/presets/Subtitle2/useSubtitle2Styles.headless.ts b/packages/react-components/react-text/library/src/components/presets/Subtitle2/useSubtitle2Styles.headless.ts new file mode 100644 index 0000000000000..6482d6fef8ee2 --- /dev/null +++ b/packages/react-components/react-text/library/src/components/presets/Subtitle2/useSubtitle2Styles.headless.ts @@ -0,0 +1,12 @@ +import { getComponentSlotClassName, type SlotClassNames } from '@fluentui/react-utilities'; +import { TextSlots, TextState } from '../../Text/Text.types'; + +export const subtitle2ClassNames: SlotClassNames = { + root: 'fui-Subtitle2', +}; + +export const useSubtitle2Styles = (state: TextState): TextState => { + state.root.className = getComponentSlotClassName(subtitle2ClassNames.root, state.root); + + return state; +}; diff --git a/packages/react-components/react-text/library/src/components/presets/Subtitle2/useSubtitle2Styles.styles.ts b/packages/react-components/react-text/library/src/components/presets/Subtitle2/useSubtitle2Styles.styles.ts index 9ce5de3a44f6c..17af054457068 100644 --- a/packages/react-components/react-text/library/src/components/presets/Subtitle2/useSubtitle2Styles.styles.ts +++ b/packages/react-components/react-text/library/src/components/presets/Subtitle2/useSubtitle2Styles.styles.ts @@ -1,6 +1,6 @@ -import { makeStyles } from '@griffel/react'; +import { makeStyles, mergeClasses } from '@griffel/react'; import { SlotClassNames } from '@fluentui/react-utilities'; -import type { TextSlots } from '../../Text/Text.types'; +import type { TextSlots, TextState } from '../../Text/Text.types'; import { typographyStyles } from '@fluentui/react-theme'; export const subtitle2ClassNames: SlotClassNames = { @@ -10,6 +10,14 @@ export const subtitle2ClassNames: SlotClassNames = { /** * Styles for the root slot */ -export const useSubtitle2Styles = makeStyles({ +const useStyles = makeStyles({ root: typographyStyles.subtitle2, }); + +export const useSubtitle2Styles = (state: TextState): TextState => { + const styles = useStyles(); + + state.root.className = mergeClasses(subtitle2ClassNames.root, styles.root, state.root.className); + + return state; +}; diff --git a/packages/react-components/react-text/library/src/components/presets/Subtitle2Stronger/Subtitle2Stronger.tsx b/packages/react-components/react-text/library/src/components/presets/Subtitle2Stronger/Subtitle2Stronger.tsx index 7958fedf13796..fe2df179b7ea3 100644 --- a/packages/react-components/react-text/library/src/components/presets/Subtitle2Stronger/Subtitle2Stronger.tsx +++ b/packages/react-components/react-text/library/src/components/presets/Subtitle2Stronger/Subtitle2Stronger.tsx @@ -1,13 +1,12 @@ import * as React from 'react'; import { createPreset } from '../createPreset'; import type { TextPresetProps } from '../../Text/Text.types'; -import { subtitle2StrongerClassNames, useSubtitle2StrongerStyles } from './useSubtitle2Stronger.styles'; +import { useSubtitle2StrongerStyles } from './useSubtitle2Stronger.styles'; /** * Text preset component for the Subtitle2Stronger typography variant */ export const Subtitle2Stronger: React.FunctionComponent = createPreset({ useStyles: useSubtitle2StrongerStyles, - className: subtitle2StrongerClassNames.root, displayName: 'Subtitle2Stronger', }); diff --git a/packages/react-components/react-text/library/src/components/presets/Subtitle2Stronger/useSubtitle2Stronger.styles.ts b/packages/react-components/react-text/library/src/components/presets/Subtitle2Stronger/useSubtitle2Stronger.styles.ts index a0fbdcfb1b708..25b931090a206 100644 --- a/packages/react-components/react-text/library/src/components/presets/Subtitle2Stronger/useSubtitle2Stronger.styles.ts +++ b/packages/react-components/react-text/library/src/components/presets/Subtitle2Stronger/useSubtitle2Stronger.styles.ts @@ -1,6 +1,6 @@ -import { makeStyles } from '@griffel/react'; +import { makeStyles, mergeClasses } from '@griffel/react'; import { SlotClassNames } from '@fluentui/react-utilities'; -import type { TextSlots } from '../../Text/Text.types'; +import type { TextSlots, TextState } from '../../Text/Text.types'; import { typographyStyles } from '@fluentui/react-theme'; export const subtitle2StrongerClassNames: SlotClassNames = { @@ -10,6 +10,14 @@ export const subtitle2StrongerClassNames: SlotClassNames = { /** * Styles for the root slot */ -export const useSubtitle2StrongerStyles = makeStyles({ +const useStyles = makeStyles({ root: typographyStyles.subtitle2Stronger, }); + +export const useSubtitle2StrongerStyles = (state: TextState): TextState => { + const styles = useStyles(); + + state.root.className = mergeClasses(subtitle2StrongerClassNames.root, styles.root, state.root.className); + + return state; +}; diff --git a/packages/react-components/react-text/library/src/components/presets/Subtitle2Stronger/useSubtitle2StrongerStyles.headless.ts b/packages/react-components/react-text/library/src/components/presets/Subtitle2Stronger/useSubtitle2StrongerStyles.headless.ts new file mode 100644 index 0000000000000..3819418e216b9 --- /dev/null +++ b/packages/react-components/react-text/library/src/components/presets/Subtitle2Stronger/useSubtitle2StrongerStyles.headless.ts @@ -0,0 +1,12 @@ +import { getComponentSlotClassName, type SlotClassNames } from '@fluentui/react-utilities'; +import { TextSlots, TextState } from '../../Text/Text.types'; + +export const subtitle2StrongerClassNames: SlotClassNames = { + root: 'fui-Subtitle2Stronger', +}; + +export const useSubtitle2StrongerStyles = (state: TextState): TextState => { + state.root.className = getComponentSlotClassName(subtitle2StrongerClassNames.root, state.root); + + return state; +}; diff --git a/packages/react-components/react-text/library/src/components/presets/Title1/Title1.tsx b/packages/react-components/react-text/library/src/components/presets/Title1/Title1.tsx index 8597aff94acc3..d1b651f733e2c 100644 --- a/packages/react-components/react-text/library/src/components/presets/Title1/Title1.tsx +++ b/packages/react-components/react-text/library/src/components/presets/Title1/Title1.tsx @@ -1,13 +1,12 @@ import * as React from 'react'; import { createPreset } from '../createPreset'; import type { TextPresetProps } from '../../Text/Text.types'; -import { title1ClassNames, useTitle1Styles } from './useTitle1Styles.styles'; +import { useTitle1Styles } from './useTitle1Styles.styles'; /** * Text preset component for the Title 1 typography variant */ export const Title1: React.FunctionComponent = createPreset({ useStyles: useTitle1Styles, - className: title1ClassNames.root, displayName: 'Title1', }); diff --git a/packages/react-components/react-text/library/src/components/presets/Title1/useTitle1Styles.headless.ts b/packages/react-components/react-text/library/src/components/presets/Title1/useTitle1Styles.headless.ts new file mode 100644 index 0000000000000..c8eeb12e3f25d --- /dev/null +++ b/packages/react-components/react-text/library/src/components/presets/Title1/useTitle1Styles.headless.ts @@ -0,0 +1,12 @@ +import { getComponentSlotClassName, type SlotClassNames } from '@fluentui/react-utilities'; +import { TextSlots, TextState } from '../../Text/Text.types'; + +export const title1ClassNames: SlotClassNames = { + root: 'fui-Title1', +}; + +export const useTitle1Styles = (state: TextState): TextState => { + state.root.className = getComponentSlotClassName(title1ClassNames.root, state.root); + + return state; +}; diff --git a/packages/react-components/react-text/library/src/components/presets/Title1/useTitle1Styles.styles.ts b/packages/react-components/react-text/library/src/components/presets/Title1/useTitle1Styles.styles.ts index 126f5eda5accf..c6e4acd461791 100644 --- a/packages/react-components/react-text/library/src/components/presets/Title1/useTitle1Styles.styles.ts +++ b/packages/react-components/react-text/library/src/components/presets/Title1/useTitle1Styles.styles.ts @@ -1,6 +1,6 @@ -import { makeStyles } from '@griffel/react'; +import { makeStyles, mergeClasses } from '@griffel/react'; import { SlotClassNames } from '@fluentui/react-utilities'; -import type { TextSlots } from '../../Text/Text.types'; +import type { TextSlots, TextState } from '../../Text/Text.types'; import { typographyStyles } from '@fluentui/react-theme'; export const title1ClassNames: SlotClassNames = { @@ -10,6 +10,14 @@ export const title1ClassNames: SlotClassNames = { /** * Styles for the root slot */ -export const useTitle1Styles = makeStyles({ +const useStyles = makeStyles({ root: typographyStyles.title1, }); + +export const useTitle1Styles = (state: TextState): TextState => { + const styles = useStyles(); + + state.root.className = mergeClasses(title1ClassNames.root, styles.root, state.root.className); + + return state; +}; diff --git a/packages/react-components/react-text/library/src/components/presets/Title2/Title2.tsx b/packages/react-components/react-text/library/src/components/presets/Title2/Title2.tsx index 6d1c2da80a1dd..e089d8b3161de 100644 --- a/packages/react-components/react-text/library/src/components/presets/Title2/Title2.tsx +++ b/packages/react-components/react-text/library/src/components/presets/Title2/Title2.tsx @@ -1,13 +1,12 @@ import * as React from 'react'; import { createPreset } from '../createPreset'; import type { TextPresetProps } from '../../Text/Text.types'; -import { title2ClassNames, useTitle2Styles } from './useTitle2Styles.styles'; +import { useTitle2Styles } from './useTitle2Styles.styles'; /** * Text preset component for the Title 2 typography variant */ export const Title2: React.FunctionComponent = createPreset({ useStyles: useTitle2Styles, - className: title2ClassNames.root, displayName: 'Title2', }); diff --git a/packages/react-components/react-text/library/src/components/presets/Title2/useTitle2Styles.headless.ts b/packages/react-components/react-text/library/src/components/presets/Title2/useTitle2Styles.headless.ts new file mode 100644 index 0000000000000..da6bfec60d868 --- /dev/null +++ b/packages/react-components/react-text/library/src/components/presets/Title2/useTitle2Styles.headless.ts @@ -0,0 +1,12 @@ +import { getComponentSlotClassName, type SlotClassNames } from '@fluentui/react-utilities'; +import { TextSlots, TextState } from '../../Text/Text.types'; + +export const title2ClassNames: SlotClassNames = { + root: 'fui-Title2', +}; + +export const useTitle2Styles = (state: TextState): TextState => { + state.root.className = getComponentSlotClassName(title2ClassNames.root, state.root); + + return state; +}; diff --git a/packages/react-components/react-text/library/src/components/presets/Title2/useTitle2Styles.styles.ts b/packages/react-components/react-text/library/src/components/presets/Title2/useTitle2Styles.styles.ts index 0d6a78592c958..91d4f056444eb 100644 --- a/packages/react-components/react-text/library/src/components/presets/Title2/useTitle2Styles.styles.ts +++ b/packages/react-components/react-text/library/src/components/presets/Title2/useTitle2Styles.styles.ts @@ -1,6 +1,6 @@ -import { makeStyles } from '@griffel/react'; +import { makeStyles, mergeClasses } from '@griffel/react'; import { SlotClassNames } from '@fluentui/react-utilities'; -import type { TextSlots } from '../../Text/Text.types'; +import type { TextSlots, TextState } from '../../Text/Text.types'; import { typographyStyles } from '@fluentui/react-theme'; export const title2ClassNames: SlotClassNames = { @@ -10,6 +10,14 @@ export const title2ClassNames: SlotClassNames = { /** * Styles for the root slot */ -export const useTitle2Styles = makeStyles({ +const useStyles = makeStyles({ root: typographyStyles.title2, }); + +export const useTitle2Styles = (state: TextState): TextState => { + const styles = useStyles(); + + state.root.className = mergeClasses(title2ClassNames.root, styles.root, state.root.className); + + return state; +}; diff --git a/packages/react-components/react-text/library/src/components/presets/Title3/Title3.tsx b/packages/react-components/react-text/library/src/components/presets/Title3/Title3.tsx index 353b01fc5fefa..6cbf784c4650d 100644 --- a/packages/react-components/react-text/library/src/components/presets/Title3/Title3.tsx +++ b/packages/react-components/react-text/library/src/components/presets/Title3/Title3.tsx @@ -1,13 +1,12 @@ import * as React from 'react'; import { createPreset } from '../createPreset'; import type { TextPresetProps } from '../../Text/Text.types'; -import { title3ClassNames, useTitle3Styles } from './useTitle3Styles.styles'; +import { useTitle3Styles } from './useTitle3Styles.styles'; /** * Text preset component for the Title 3 typography variant */ export const Title3: React.FunctionComponent = createPreset({ useStyles: useTitle3Styles, - className: title3ClassNames.root, displayName: 'Title3', }); diff --git a/packages/react-components/react-text/library/src/components/presets/Title3/useTitle3Styles.headless.ts b/packages/react-components/react-text/library/src/components/presets/Title3/useTitle3Styles.headless.ts new file mode 100644 index 0000000000000..bdc124479d0ad --- /dev/null +++ b/packages/react-components/react-text/library/src/components/presets/Title3/useTitle3Styles.headless.ts @@ -0,0 +1,12 @@ +import { getComponentSlotClassName, type SlotClassNames } from '@fluentui/react-utilities'; +import { TextSlots, TextState } from '../../Text/Text.types'; + +export const title3ClassNames: SlotClassNames = { + root: 'fui-Title3', +}; + +export const useTitle3Styles = (state: TextState): TextState => { + state.root.className = getComponentSlotClassName(title3ClassNames.root, state.root); + + return state; +}; diff --git a/packages/react-components/react-text/library/src/components/presets/Title3/useTitle3Styles.styles.ts b/packages/react-components/react-text/library/src/components/presets/Title3/useTitle3Styles.styles.ts index 26996a6eb0209..708a68a8db7f4 100644 --- a/packages/react-components/react-text/library/src/components/presets/Title3/useTitle3Styles.styles.ts +++ b/packages/react-components/react-text/library/src/components/presets/Title3/useTitle3Styles.styles.ts @@ -1,6 +1,6 @@ -import { makeStyles } from '@griffel/react'; +import { makeStyles, mergeClasses } from '@griffel/react'; import { SlotClassNames } from '@fluentui/react-utilities'; -import type { TextSlots } from '../../Text/Text.types'; +import type { TextSlots, TextState } from '../../Text/Text.types'; import { typographyStyles } from '@fluentui/react-theme'; export const title3ClassNames: SlotClassNames = { @@ -10,6 +10,14 @@ export const title3ClassNames: SlotClassNames = { /** * Styles for the root slot */ -export const useTitle3Styles = makeStyles({ +const useStyles = makeStyles({ root: typographyStyles.title3, }); + +export const useTitle3Styles = (state: TextState): TextState => { + const styles = useStyles(); + + state.root.className = mergeClasses(title3ClassNames.root, styles.root, state.root.className); + + return state; +}; diff --git a/packages/react-components/react-text/library/src/components/presets/createPreset.ts b/packages/react-components/react-text/library/src/components/presets/createPreset.ts index e40c671c7d491..8032353eee54d 100644 --- a/packages/react-components/react-text/library/src/components/presets/createPreset.ts +++ b/packages/react-components/react-text/library/src/components/presets/createPreset.ts @@ -1,26 +1,22 @@ 'use client'; import * as React from 'react'; -import { mergeClasses } from '@griffel/react'; import { renderText_unstable, useText_unstable, useTextStyles_unstable } from '../Text'; -import type { TextProps, TextPresetProps } from '../Text'; +import type { TextProps, TextPresetProps, TextState } from '../Text'; import type { ForwardRefComponent } from '@fluentui/react-utilities'; export function createPreset(options: { - className: string; displayName: string; - useStyles: () => Record<'root', string>; + useStyles: (state: TextState) => TextState; }): React.FunctionComponent { - const { useStyles, className, displayName } = options; + const { useStyles, displayName } = options; const Wrapper: ForwardRefComponent = React.forwardRef((props, ref) => { 'use no memo'; - const styles = useStyles(); const state = useText_unstable(props as TextProps, ref); useTextStyles_unstable(state); - - state.root.className = mergeClasses(className, state.root.className, styles.root, props.className); + useStyles(state); return renderText_unstable(state); }); diff --git a/packages/react-components/react-text/library/src/testing/isConformant.ts b/packages/react-components/react-text/library/src/testing/isConformant.ts index fa21686f98f19..8ed2da0f92513 100644 --- a/packages/react-components/react-text/library/src/testing/isConformant.ts +++ b/packages/react-components/react-text/library/src/testing/isConformant.ts @@ -9,13 +9,6 @@ export function isConformant( tsConfig: { configName: 'tsconfig.spec.json' }, componentPath: require.main?.filename.replace('.test', ''), extraTests: griffelTests as TestObject, - testOptions: { - 'make-styles-overrides-win': { - callCount: 2, - }, - // TODO: https://github.com/microsoft/fluentui/issues/19618 - // eslint-disable-next-line @typescript-eslint/no-explicit-any - } as any, }; baseIsConformant(defaultOptions, testInfo); diff --git a/packages/react-components/react-toolbar/library/src/components/Toolbar/useToolbarStyles.headless.ts b/packages/react-components/react-toolbar/library/src/components/Toolbar/useToolbarStyles.headless.ts new file mode 100644 index 0000000000000..42ae2d428ba78 --- /dev/null +++ b/packages/react-components/react-toolbar/library/src/components/Toolbar/useToolbarStyles.headless.ts @@ -0,0 +1,20 @@ +'use client'; + +import type { SlotClassNames } from '@fluentui/react-utilities'; +import { getComponentSlotClassName } from '@fluentui/react-utilities'; +import type { ToolbarSlots, ToolbarState } from './Toolbar.types'; + +export const toolbarClassNames: SlotClassNames = { + root: 'fui-Toolbar', +}; + +/** + * Apply styling to the Toolbar slots based on the state + */ +export const useToolbarStyles_unstable = (state: ToolbarState): ToolbarState => { + 'use no memo'; + + state.root.className = getComponentSlotClassName(toolbarClassNames.root, state.root); + + return state; +}; diff --git a/packages/react-components/react-toolbar/library/src/components/ToolbarButton/useToolbarButtonStyles.headless.ts b/packages/react-components/react-toolbar/library/src/components/ToolbarButton/useToolbarButtonStyles.headless.ts new file mode 100644 index 0000000000000..8471db6bf14a0 --- /dev/null +++ b/packages/react-components/react-toolbar/library/src/components/ToolbarButton/useToolbarButtonStyles.headless.ts @@ -0,0 +1,13 @@ +'use client'; + +import { useButtonStyles_unstable } from '@fluentui/react-button'; +import type { ToolbarButtonState } from './ToolbarButton.types'; + +/** + * Apply styling to the ToolbarButton slots based on the state + */ +export const useToolbarButtonStyles_unstable = (state: ToolbarButtonState): void => { + 'use no memo'; + + useButtonStyles_unstable(state); +}; diff --git a/packages/react-components/react-toolbar/library/src/components/ToolbarDivider/useToolbarDividerStyles.headless.ts b/packages/react-components/react-toolbar/library/src/components/ToolbarDivider/useToolbarDividerStyles.headless.ts new file mode 100644 index 0000000000000..bc84bfc868a32 --- /dev/null +++ b/packages/react-components/react-toolbar/library/src/components/ToolbarDivider/useToolbarDividerStyles.headless.ts @@ -0,0 +1,15 @@ +'use client'; + +import { useDividerStyles_unstable } from '@fluentui/react-divider'; +import type { ToolbarDividerState } from './ToolbarDivider.types'; + +/** + * Apply styling to the ToolbarDivider slots based on the state + */ +export const useToolbarDividerStyles_unstable = (state: ToolbarDividerState): ToolbarDividerState => { + 'use no memo'; + + useDividerStyles_unstable(state); + + return state; +}; diff --git a/packages/react-components/react-toolbar/library/src/components/ToolbarGroup/useToolbarGroupStyles.headless.ts b/packages/react-components/react-toolbar/library/src/components/ToolbarGroup/useToolbarGroupStyles.headless.ts new file mode 100644 index 0000000000000..ff441b92502a5 --- /dev/null +++ b/packages/react-components/react-toolbar/library/src/components/ToolbarGroup/useToolbarGroupStyles.headless.ts @@ -0,0 +1,21 @@ +'use client'; + +import type { SlotClassNames } from '@fluentui/react-utilities'; +import { getComponentSlotClassName } from '@fluentui/react-utilities'; + +import type { ToolbarGroupSlots, ToolbarGroupState } from './ToolbarGroup.types'; + +export const toolbarGroupClassNames: SlotClassNames = { + root: 'fui-ToolbarGroup', +}; + +/** + * Apply styling to the Toolbar slots based on the state + */ +export const useToolbarGroupStyles_unstable = (state: ToolbarGroupState): ToolbarGroupState => { + 'use no memo'; + + state.root.className = getComponentSlotClassName(toolbarGroupClassNames.root, state.root); + + return state; +}; diff --git a/packages/react-components/react-toolbar/library/src/components/ToolbarRadioButton/useToolbarRadioButtonStyles.headless.ts b/packages/react-components/react-toolbar/library/src/components/ToolbarRadioButton/useToolbarRadioButtonStyles.headless.ts new file mode 100644 index 0000000000000..baa8d505724c6 --- /dev/null +++ b/packages/react-components/react-toolbar/library/src/components/ToolbarRadioButton/useToolbarRadioButtonStyles.headless.ts @@ -0,0 +1,15 @@ +'use client'; + +import { useToggleButtonStyles_unstable } from '@fluentui/react-button'; +import type { ToolbarRadioButtonState } from './ToolbarRadioButton.types'; + +/** + * Apply styling to the ToolbarRadioButton slots based on the state + */ +export const useToolbarRadioButtonStyles_unstable = (state: ToolbarRadioButtonState): ToolbarRadioButtonState => { + 'use no memo'; + + useToggleButtonStyles_unstable(state); + + return state; +}; diff --git a/packages/react-components/react-toolbar/library/src/components/ToolbarToggleButton/useToolbarToggleButtonStyles.headless.ts b/packages/react-components/react-toolbar/library/src/components/ToolbarToggleButton/useToolbarToggleButtonStyles.headless.ts new file mode 100644 index 0000000000000..87dd26faa819b --- /dev/null +++ b/packages/react-components/react-toolbar/library/src/components/ToolbarToggleButton/useToolbarToggleButtonStyles.headless.ts @@ -0,0 +1,15 @@ +'use client'; + +import { useToggleButtonStyles_unstable } from '@fluentui/react-button'; +import type { ToolbarToggleButtonState } from './ToolbarToggleButton.types'; + +/** + * Apply styling to the ToolbarToggleButton slots based on the state + */ +export const useToolbarToggleButtonStyles_unstable = (state: ToolbarToggleButtonState): ToolbarToggleButtonState => { + 'use no memo'; + + useToggleButtonStyles_unstable(state); + + return state; +}; diff --git a/packages/react-components/react-tooltip/library/src/components/Tooltip/useTooltipStyles.styles.headless.ts b/packages/react-components/react-tooltip/library/src/components/Tooltip/useTooltipStyles.styles.headless.ts new file mode 100644 index 0000000000000..45e8b37db2521 --- /dev/null +++ b/packages/react-components/react-tooltip/library/src/components/Tooltip/useTooltipStyles.styles.headless.ts @@ -0,0 +1,25 @@ +'use client'; + +import type { TooltipSlots, TooltipState } from './Tooltip.types'; +import { getComponentSlotClassName, type SlotClassNames } from '@fluentui/react-utilities'; + +export const tooltipClassNames: SlotClassNames = { + content: 'fui-Tooltip__content', +}; + +const tooltipArrowClassName = 'fui-Tooltip__arrow'; + +/** + * Apply styling to the Tooltip slots based on the state + */ +export const useTooltipStyles_unstable = (state: TooltipState): TooltipState => { + 'use no memo'; + + const { arrowRef, children, mountNode, ...componentState } = state; + + state.content.className = getComponentSlotClassName(tooltipClassNames.content, state.content, componentState); + + state.arrowClassName = tooltipArrowClassName; + + return state; +}; diff --git a/packages/react-components/react-utilities/etc/react-utilities.api.md b/packages/react-components/react-utilities/etc/react-utilities.api.md index d8d6952afd44f..79edbb3a35dbe 100644 --- a/packages/react-components/react-utilities/etc/react-utilities.api.md +++ b/packages/react-components/react-utilities/etc/react-utilities.api.md @@ -65,6 +65,11 @@ export type FluentTriggerComponent = { // @public export type ForwardRefComponent = NamedExoticComponent>>; +// @public +export function getComponentSlotClassName(baseClassName: string, slotProps: SlotProps, componentState?: ComponentState & Record): string; + // @public export function getEventClientCoords(event: TouchOrMouseEvent): { clientX: number; diff --git a/packages/react-components/react-utilities/src/index.ts b/packages/react-components/react-utilities/src/index.ts index 68d394bf67003..ed79b24404ec7 100644 --- a/packages/react-components/react-utilities/src/index.ts +++ b/packages/react-components/react-utilities/src/index.ts @@ -70,6 +70,7 @@ export { getReactElementRef, getRTLSafeKey, mergeCallbacks, + getComponentSlotClassName, isHTMLElement, isInteractiveHTMLElement, omit, diff --git a/packages/react-components/react-utilities/src/utils/getComponentSlotClassName.test.ts b/packages/react-components/react-utilities/src/utils/getComponentSlotClassName.test.ts new file mode 100644 index 0000000000000..c7df92cdba039 --- /dev/null +++ b/packages/react-components/react-utilities/src/utils/getComponentSlotClassName.test.ts @@ -0,0 +1,140 @@ +import * as React from 'react'; +import { slot } from '../compose'; +import type { ComponentState, Slot } from '../compose/types'; +import { getComponentSlotClassName } from './getComponentSlotClassName'; + +type ButtonSlots = { + root: Slot<'button'>; + icon: Slot<'span'>; +}; + +type ButtonState = { + disabled?: boolean; + appearance?: 'primary' | 'secondary'; + size?: 'small' | 'medium' | 'large'; + iconOnly?: boolean; + iconPosition?: 'before' | 'after'; +}; + +describe('getComponentSlotClassName', () => { + describe('without component state', () => { + it('returns the base class name when slot has no className', () => { + expect(getComponentSlotClassName('fui-Button', {})).toBe('fui-Button'); + }); + + it('combines base class with user-provided className', () => { + expect(getComponentSlotClassName('fui-Button', { className: 'custom-button' })).toBe('fui-Button custom-button'); + }); + + it('ignores empty user-provided className', () => { + expect(getComponentSlotClassName('fui-Button', { className: '' })).toBe('fui-Button'); + }); + }); + + describe('with component state', () => { + const createButtonState = ( + // eslint-disable-next-line @typescript-eslint/no-explicit-any + state: ButtonState & Record = {}, + ): ComponentState & ButtonState => { + const { className = '', ...stateOverrides } = state; + return { + appearance: 'primary', + size: 'medium', + disabled: false, + iconOnly: false, + iconPosition: 'before', + components: { + root: 'button', + icon: 'span', + }, + root: slot.always>({ className }, { elementType: 'button' }), + icon: slot.optional>({}, { elementType: 'span' }), + ...stateOverrides, + }; + }; + + it('generates modifier classes from state boolean properties', () => { + const state = createButtonState({ disabled: true }); + expect(getComponentSlotClassName('fui-Button', state.root, state)).toContain('fui-Button--disabled'); + }); + + it('generates modifier classes from state string properties', () => { + const state = createButtonState({ appearance: 'secondary' }); + expect(getComponentSlotClassName('fui-Button', state.root, state)).toContain('fui-Button--appearance-secondary'); + }); + + it('combines state modifiers with user-provided className', () => { + const state = createButtonState({ disabled: true, className: 'custom-class' }); + const result = getComponentSlotClassName('fui-Button', state.root, state); + + expect(result).toContain('fui-Button--disabled'); + expect(result).toContain('custom-class'); + expect(result).toBe( + 'fui-Button fui-Button--appearance-primary fui-Button--size-medium fui-Button--disabled fui-Button--iconPosition-before custom-class', + ); + }); + + it('ignores falsy state values (false, undefined, null, empty string)', () => { + const state = createButtonState({ + disabled: false, + appearance: undefined, + iconOnly: false, + }); + const result = getComponentSlotClassName('fui-Button', state.root, state); + + // Should not contain disabled, appearance, or iconOnly modifiers + expect(result).not.toContain('--disabled'); + expect(result).not.toContain('--appearance-undefined'); + expect(result).not.toContain('--iconOnly'); + }); + + it('ignores non-primitive state values (objects, functions)', () => { + // eslint-disable-next-line @typescript-eslint/no-empty-function + const state = createButtonState({ foo: 'bar', customFn: () => {} }); + + const result = getComponentSlotClassName('fui-Button', state.root, state); + + // Should not generate classes for object/function properties + expect(result).not.toContain('--customObj'); + expect(result).not.toContain('--customFn'); + }); + + it('ignores the deprecated components property', () => { + const state = createButtonState(); + const result = getComponentSlotClassName('fui-Button', state.root, state); + + expect(result).not.toContain('--components'); + }); + }); + + describe('slot className property', () => { + it('handles slot without className property', () => { + expect(getComponentSlotClassName('fui-Button__icon', {})).toBe('fui-Button__icon'); + }); + + it('preserves slot className even when empty', () => { + // Empty string className should be filtered out + expect(getComponentSlotClassName('fui-Button__icon', { className: '' })).toBe('fui-Button__icon'); + }); + + it('combines multiple classes in correct order: baseClass, modifiers, userClass', () => { + const state: ComponentState & ButtonState = { + appearance: 'primary', + size: 'large', + disabled: true, + iconOnly: false, + iconPosition: 'before', + components: { root: 'button', icon: 'span' }, + root: slot.always({ className: 'user-custom-class' }, { elementType: 'button' }), + icon: slot.optional>({}, { elementType: 'span' }), + }; + + const result = getComponentSlotClassName('fui-Button', state.root, state); + const parts = result.split(' '); + + expect(parts[0]).toBe('fui-Button'); // base class first + expect(parts.at(-1)).toBe('user-custom-class'); // user class last + expect(parts.slice(1, -1).every(p => p.startsWith('fui-Button--'))).toBe(true); // modifiers in middle + }); + }); +}); diff --git a/packages/react-components/react-utilities/src/utils/getComponentSlotClassName.ts b/packages/react-components/react-utilities/src/utils/getComponentSlotClassName.ts new file mode 100644 index 0000000000000..eec78639ae134 --- /dev/null +++ b/packages/react-components/react-utilities/src/utils/getComponentSlotClassName.ts @@ -0,0 +1,94 @@ +import type { SlotPropsRecord, ComponentState } from '../compose/types'; + +/** + * Generates a complete CSS class name string for a component slot by combining: + * - The base class name for the slot + * - Generated modifier classes based on component state (if provided) + * - Any user-provided class name on the slot + * + * This function is useful for slots that need to apply state-based styling modifiers + * while also preserving user-provided classes for customization. + * + * @param baseClassName - The base CSS class name for the slot (e.g., 'fui-Button', 'fui-Button__icon') + * @param slotProps - The slot props object, which may contain a user-provided className + * @param componentState - Optional component state object for generating modifier classes. + * Only primitive values (boolean, string, number) are mapped to classes. + * @returns A space-separated string of CSS class names + * + * @example + * ```ts + * // Without state + * getComponentSlotClassName('fui-Button', { className: 'custom-button' }) + * // Returns: 'fui-Button custom-button' + * + * // With state + * getComponentSlotClassName( + * 'fui-Button', + * { className: 'custom-button' }, + * { appearance: 'primary', disabled: true, size: 'large' } + * ) + * // Returns: 'fui-Button fui-Button--appearance-primary fui-Button--disabled fui-Button--size-large custom-button' + * ``` + */ +export function getComponentSlotClassName( + baseClassName: string, + slotProps: SlotProps, + // eslint-disable-next-line @typescript-eslint/no-explicit-any + componentState?: ComponentState & Record, +): string { + const classes = [baseClassName]; + + // Add state-based modifier classes if state is provided + if (componentState) { + classes.push(...mapStateToSlotModifiers(baseClassName, componentState)); + } + + // Add user-provided class name from slot props + if (slotProps.className) { + classes.push(slotProps.className); + } + + return classes.join(' '); +} + +/** + * Maps component state values to BEM-style modifier classes. + * @internal + */ +function mapStateToSlotModifiers( + baseClassName: string, + // eslint-disable-next-line @typescript-eslint/no-explicit-any + state: Record, +): string[] { + const modifiers: string[] = []; + + for (const [stateKey, stateValue] of Object.entries(state)) { + // Skip non-primitive values (objects, functions) + if ( + stateValue === null || + stateValue === undefined || + typeof stateValue === 'object' || + typeof stateValue === 'function' + ) { + continue; + } + + // Skip falsy non-null values (false, '', 0) + if (!stateValue && stateValue !== 0) { + continue; + } + + if (typeof stateValue === 'boolean') { + // Boolean true: baseClassName--key (e.g., 'fui-Button--disabled') + modifiers.push(`${baseClassName}--${stateKey}`); + } else { + // String/Number: baseClassName--key-value (e.g., 'fui-Button--size-large') + const normalizedValue = stateValue.toString().trim(); + if (normalizedValue) { + modifiers.push(`${baseClassName}--${stateKey}-${normalizedValue}`); + } + } + } + + return modifiers; +} diff --git a/packages/react-components/react-utilities/src/utils/index.ts b/packages/react-components/react-utilities/src/utils/index.ts index 4b2fe5c0c3d17..00f717472caea 100644 --- a/packages/react-components/react-utilities/src/utils/index.ts +++ b/packages/react-components/react-utilities/src/utils/index.ts @@ -8,6 +8,7 @@ export { getReactElementRef } from './getReactElementRef'; export { getRTLSafeKey } from './getRTLSafeKey'; export { mergeCallbacks } from './mergeCallbacks'; export { omit } from './omit'; +export { getComponentSlotClassName } from './getComponentSlotClassName'; export { anchorProperties, audioProperties,