From 4bdc92b8347d6e65482816e5b5ecf78848a2965c Mon Sep 17 00:00:00 2001 From: EnricoGianoglio Date: Thu, 7 May 2026 15:17:35 +0200 Subject: [PATCH 1/6] refactor Menu --- packages/react-cap-theme/src/capStyleHooks.ts | 10 + .../src/components/react-menu/Menu.ts | 17 -- .../src/components/react-menu/MenuDivider.ts | 13 - .../src/components/react-menu/MenuGroup.ts | 17 -- .../components/react-menu/MenuGroupHeader.ts | 13 - .../src/components/react-menu/MenuItem.ts | 15 - .../components/react-menu/MenuItemCheckbox.ts | 12 - .../src/components/react-menu/MenuItemLink.ts | 12 - .../components/react-menu/MenuItemRadio.ts | 12 - .../react-menu/MenuItemSwatchPicker.ts | 7 - .../components/react-menu/MenuItemSwitch.ts | 12 - .../src/components/react-menu/MenuList.ts | 18 -- .../src/components/react-menu/MenuPopover.ts | 14 - .../components/react-menu/MenuSplitGroup.ts | 13 - .../src/components/react-menu/MenuTrigger.ts | 12 - .../useMenuDividerStyles.styles.ts | 15 +- .../useMenuGroupHeaderStyles.styles.ts | 15 +- .../MenuItem/useMenuItemStyles.styles.ts | 22 +- .../useMenuItemCheckboxStyles.styles.ts | 21 +- .../useMenuItemLinkStyles.styles.ts | 72 +++++ .../MenuItemRadio/useMenuItemRadio.tsx | 33 --- .../useMenuItemRadioStyles.styles.ts | 20 +- .../MenuItemSwatchPicker.tsx | 19 -- .../MenuItemSwatchPicker.types.ts | 5 - .../useMenuItemSwatchPicker.tsx | 50 ---- .../useMenuItemSwatchPickerStyles.styles.ts | 37 --- .../useMenuItemSwitchStyles.styles.ts | 260 ++++++++++++++++++ .../useMenuPopoverStyles.styles.ts | 16 +- .../useMenuSplitGroupStyles.styles.ts | 11 +- .../src/components/react-menu/index.ts | 2 + .../selectable/useCheckmarkStyles.style.ts | 87 ++++++ 31 files changed, 443 insertions(+), 439 deletions(-) delete mode 100644 packages/react-cap-theme/src/components/react-menu/Menu.ts delete mode 100644 packages/react-cap-theme/src/components/react-menu/MenuDivider.ts delete mode 100644 packages/react-cap-theme/src/components/react-menu/MenuGroup.ts delete mode 100644 packages/react-cap-theme/src/components/react-menu/MenuGroupHeader.ts delete mode 100644 packages/react-cap-theme/src/components/react-menu/MenuItem.ts delete mode 100644 packages/react-cap-theme/src/components/react-menu/MenuItemCheckbox.ts delete mode 100644 packages/react-cap-theme/src/components/react-menu/MenuItemLink.ts delete mode 100644 packages/react-cap-theme/src/components/react-menu/MenuItemRadio.ts delete mode 100644 packages/react-cap-theme/src/components/react-menu/MenuItemSwatchPicker.ts delete mode 100644 packages/react-cap-theme/src/components/react-menu/MenuItemSwitch.ts delete mode 100644 packages/react-cap-theme/src/components/react-menu/MenuList.ts delete mode 100644 packages/react-cap-theme/src/components/react-menu/MenuPopover.ts delete mode 100644 packages/react-cap-theme/src/components/react-menu/MenuSplitGroup.ts delete mode 100644 packages/react-cap-theme/src/components/react-menu/MenuTrigger.ts create mode 100644 packages/react-cap-theme/src/components/react-menu/components/MenuItemLink/useMenuItemLinkStyles.styles.ts delete mode 100644 packages/react-cap-theme/src/components/react-menu/components/MenuItemRadio/useMenuItemRadio.tsx delete mode 100644 packages/react-cap-theme/src/components/react-menu/components/MenuItemSwatchPicker/MenuItemSwatchPicker.tsx delete mode 100644 packages/react-cap-theme/src/components/react-menu/components/MenuItemSwatchPicker/MenuItemSwatchPicker.types.ts delete mode 100644 packages/react-cap-theme/src/components/react-menu/components/MenuItemSwatchPicker/useMenuItemSwatchPicker.tsx delete mode 100644 packages/react-cap-theme/src/components/react-menu/components/MenuItemSwatchPicker/useMenuItemSwatchPickerStyles.styles.ts create mode 100644 packages/react-cap-theme/src/components/react-menu/components/MenuItemSwitch/useMenuItemSwitchStyles.styles.ts create mode 100644 packages/react-cap-theme/src/components/react-menu/selectable/useCheckmarkStyles.style.ts diff --git a/packages/react-cap-theme/src/capStyleHooks.ts b/packages/react-cap-theme/src/capStyleHooks.ts index b676a4f8..1dfd0bab 100644 --- a/packages/react-cap-theme/src/capStyleHooks.ts +++ b/packages/react-cap-theme/src/capStyleHooks.ts @@ -98,7 +98,9 @@ import { useMenuGroupHeaderStyles, useMenuItemStyles, useMenuItemCheckboxStyles, + useMenuItemLinkStyles, useMenuItemRadioStyles, + useMenuItemSwitchStyles, useMenuPopoverStyles, useMenuSplitGroupStyles, } from './components/react-menu'; @@ -107,7 +109,9 @@ import type { MenuGroupHeaderState, MenuItemState, MenuItemCheckboxState, + MenuItemLinkState, MenuItemRadioState, + MenuItemSwitchState, MenuPopoverState, MenuSplitGroupState, } from '@fluentui/react-menu'; @@ -279,6 +283,12 @@ export const CAP_STYLE_HOOKS: NonNullable< useMenuItemCheckboxStyles_unstable: (state) => { return useMenuItemCheckboxStyles(state as MenuItemCheckboxState); }, + useMenuItemLinkStyles_unstable: (state) => { + return useMenuItemLinkStyles(state as MenuItemLinkState); + }, + useMenuItemSwitchStyles_unstable: (state) => { + return useMenuItemSwitchStyles(state as MenuItemSwitchState); + }, useMenuItemRadioStyles_unstable: (state) => { return useMenuItemRadioStyles(state as MenuItemRadioState); }, diff --git a/packages/react-cap-theme/src/components/react-menu/Menu.ts b/packages/react-cap-theme/src/components/react-menu/Menu.ts deleted file mode 100644 index 70335859..00000000 --- a/packages/react-cap-theme/src/components/react-menu/Menu.ts +++ /dev/null @@ -1,17 +0,0 @@ -export { - Menu, - MenuProvider, - renderMenu_unstable, - useMenu_unstable, - useMenuContext_unstable, - useMenuContextValues_unstable, -} from '@fluentui/react-menu'; -export type { - MenuCheckedValueChangeData, - MenuCheckedValueChangeEvent, - MenuContextValue, - MenuContextValues, - MenuProps, - MenuSlots, - MenuState, -} from '@fluentui/react-menu'; diff --git a/packages/react-cap-theme/src/components/react-menu/MenuDivider.ts b/packages/react-cap-theme/src/components/react-menu/MenuDivider.ts deleted file mode 100644 index 78cf56b4..00000000 --- a/packages/react-cap-theme/src/components/react-menu/MenuDivider.ts +++ /dev/null @@ -1,13 +0,0 @@ -export { - renderMenuDivider_unstable, - useMenuDivider_unstable, -} from '@fluentui/react-menu'; -export type { - MenuDividerProps, - MenuDividerSlots, - MenuDividerState, -} from '@fluentui/react-menu'; -export { - menuDividerClassNames, - useMenuDividerStyles, -} from './components/MenuDivider/useMenuDividerStyles.styles'; diff --git a/packages/react-cap-theme/src/components/react-menu/MenuGroup.ts b/packages/react-cap-theme/src/components/react-menu/MenuGroup.ts deleted file mode 100644 index 06169a6c..00000000 --- a/packages/react-cap-theme/src/components/react-menu/MenuGroup.ts +++ /dev/null @@ -1,17 +0,0 @@ -export { - MenuGroup, - menuGroupClassNames, - MenuGroupContextProvider, - renderMenuGroup_unstable, - useMenuGroup_unstable, - useMenuGroupContext_unstable, - useMenuGroupContextValues_unstable, - useMenuGroupStyles_unstable, -} from '@fluentui/react-menu'; -export type { - MenuGroupContextValue, - MenuGroupContextValues, - MenuGroupProps, - MenuGroupSlots, - MenuGroupState, -} from '@fluentui/react-menu'; diff --git a/packages/react-cap-theme/src/components/react-menu/MenuGroupHeader.ts b/packages/react-cap-theme/src/components/react-menu/MenuGroupHeader.ts deleted file mode 100644 index 99048ce2..00000000 --- a/packages/react-cap-theme/src/components/react-menu/MenuGroupHeader.ts +++ /dev/null @@ -1,13 +0,0 @@ -export { - renderMenuGroupHeader_unstable, - useMenuGroupHeader_unstable, -} from '@fluentui/react-menu'; -export type { - MenuGroupHeaderProps, - MenuGroupHeaderSlots, - MenuGroupHeaderState, -} from '@fluentui/react-menu'; -export { - menuGroupHeaderClassNames, - useMenuGroupHeaderStyles, -} from './components/MenuGroupHeader/useMenuGroupHeaderStyles.styles'; diff --git a/packages/react-cap-theme/src/components/react-menu/MenuItem.ts b/packages/react-cap-theme/src/components/react-menu/MenuItem.ts deleted file mode 100644 index 87502d51..00000000 --- a/packages/react-cap-theme/src/components/react-menu/MenuItem.ts +++ /dev/null @@ -1,15 +0,0 @@ -export { - renderMenuItem_unstable, - useMenuItem_unstable, -} from '@fluentui/react-menu'; -export type { - MenuItemProps, - MenuItemSelectableProps, - MenuItemSelectableState, - MenuItemSlots, - MenuItemState, -} from '@fluentui/react-menu'; -export { - menuItemClassNames, - useMenuItemStyles, -} from './components/MenuItem/useMenuItemStyles.styles'; diff --git a/packages/react-cap-theme/src/components/react-menu/MenuItemCheckbox.ts b/packages/react-cap-theme/src/components/react-menu/MenuItemCheckbox.ts deleted file mode 100644 index 11e9c97c..00000000 --- a/packages/react-cap-theme/src/components/react-menu/MenuItemCheckbox.ts +++ /dev/null @@ -1,12 +0,0 @@ -export { - renderMenuItemCheckbox_unstable, - useMenuItemCheckbox_unstable, -} from '@fluentui/react-menu'; -export type { - MenuItemCheckboxProps, - MenuItemCheckboxState, -} from '@fluentui/react-menu'; -export { - menuItemCheckboxClassNames, - useMenuItemCheckboxStyles, -} from './components/MenuItemCheckbox/useMenuItemCheckboxStyles.styles'; diff --git a/packages/react-cap-theme/src/components/react-menu/MenuItemLink.ts b/packages/react-cap-theme/src/components/react-menu/MenuItemLink.ts deleted file mode 100644 index 91c33158..00000000 --- a/packages/react-cap-theme/src/components/react-menu/MenuItemLink.ts +++ /dev/null @@ -1,12 +0,0 @@ -export { - MenuItemLink, - menuItemLinkClassNames, - renderMenuItemLink_unstable, - useMenuItemLink_unstable, - useMenuItemLinkStyles_unstable, -} from '@fluentui/react-menu'; -export type { - MenuItemLinkProps, - MenuItemLinkSlots, - MenuItemLinkState, -} from '@fluentui/react-menu'; diff --git a/packages/react-cap-theme/src/components/react-menu/MenuItemRadio.ts b/packages/react-cap-theme/src/components/react-menu/MenuItemRadio.ts deleted file mode 100644 index 88060c67..00000000 --- a/packages/react-cap-theme/src/components/react-menu/MenuItemRadio.ts +++ /dev/null @@ -1,12 +0,0 @@ -export { - renderMenuItemRadio_unstable, - useMenuItemRadio_unstable, -} from '@fluentui/react-menu'; -export type { - MenuItemRadioProps, - MenuItemRadioState, -} from '@fluentui/react-menu'; -export { - menuItemRadioClassNames, - useMenuItemRadioStyles, -} from './components/MenuItemRadio/useMenuItemRadioStyles.styles'; diff --git a/packages/react-cap-theme/src/components/react-menu/MenuItemSwatchPicker.ts b/packages/react-cap-theme/src/components/react-menu/MenuItemSwatchPicker.ts deleted file mode 100644 index e638e971..00000000 --- a/packages/react-cap-theme/src/components/react-menu/MenuItemSwatchPicker.ts +++ /dev/null @@ -1,7 +0,0 @@ -export { MenuItemSwatchPicker } from './components/MenuItemSwatchPicker/MenuItemSwatchPicker'; -export type { MenuItemSwatchPickerProps } from './components/MenuItemSwatchPicker/MenuItemSwatchPicker.types'; -export { useMenuItemSwatchPicker } from './components/MenuItemSwatchPicker/useMenuItemSwatchPicker'; -export { - menuItemSwatchPickerClassNames, - useMenuItemSwatchPickerStyles, -} from './components/MenuItemSwatchPicker/useMenuItemSwatchPickerStyles.styles'; diff --git a/packages/react-cap-theme/src/components/react-menu/MenuItemSwitch.ts b/packages/react-cap-theme/src/components/react-menu/MenuItemSwitch.ts deleted file mode 100644 index f69a51fc..00000000 --- a/packages/react-cap-theme/src/components/react-menu/MenuItemSwitch.ts +++ /dev/null @@ -1,12 +0,0 @@ -export { - MenuItemSwitch, - menuItemSwitchClassNames, - renderMenuItemSwitch_unstable, - useMenuItemSwitch_unstable, - useMenuItemSwitchStyles_unstable, -} from '@fluentui/react-menu'; -export type { - MenuItemSwitchProps, - MenuItemSwitchSlots, - MenuItemSwitchState, -} from '@fluentui/react-menu'; diff --git a/packages/react-cap-theme/src/components/react-menu/MenuList.ts b/packages/react-cap-theme/src/components/react-menu/MenuList.ts deleted file mode 100644 index c74077be..00000000 --- a/packages/react-cap-theme/src/components/react-menu/MenuList.ts +++ /dev/null @@ -1,18 +0,0 @@ -export { - MenuList, - menuListClassNames, - MenuListProvider, - renderMenuList_unstable, - useMenuList_unstable, - useMenuListContext_unstable, - useMenuListContextValues_unstable, - useMenuListStyles_unstable, -} from '@fluentui/react-menu'; -export type { - MenuListContextValue, - MenuListContextValues, - MenuListProps, - MenuListSlots, - MenuListState, - UninitializedMenuListState, -} from '@fluentui/react-menu'; diff --git a/packages/react-cap-theme/src/components/react-menu/MenuPopover.ts b/packages/react-cap-theme/src/components/react-menu/MenuPopover.ts deleted file mode 100644 index 0ab08a4a..00000000 --- a/packages/react-cap-theme/src/components/react-menu/MenuPopover.ts +++ /dev/null @@ -1,14 +0,0 @@ -export { - renderMenuPopover_unstable, - useMenuPopover_unstable, - useMenuPopoverStyles_unstable, -} from '@fluentui/react-menu'; -export type { - MenuPopoverProps, - MenuPopoverSlots, - MenuPopoverState, -} from '@fluentui/react-menu'; -export { - menuPopoverClassNames, - useMenuPopoverStyles, -} from './components/MenuPopover/useMenuPopoverStyles.styles'; diff --git a/packages/react-cap-theme/src/components/react-menu/MenuSplitGroup.ts b/packages/react-cap-theme/src/components/react-menu/MenuSplitGroup.ts deleted file mode 100644 index 7095fff0..00000000 --- a/packages/react-cap-theme/src/components/react-menu/MenuSplitGroup.ts +++ /dev/null @@ -1,13 +0,0 @@ -export { - renderMenuSplitGroup_unstable, - useMenuSplitGroup_unstable, -} from '@fluentui/react-menu'; -export type { - MenuSplitGroupProps, - MenuSplitGroupSlots, - MenuSplitGroupState, -} from '@fluentui/react-menu'; -export { - menuSplitGroupClassNames, - useMenuSplitGroupStyles, -} from './components/MenuSplitGroup/useMenuSplitGroupStyles.styles'; diff --git a/packages/react-cap-theme/src/components/react-menu/MenuTrigger.ts b/packages/react-cap-theme/src/components/react-menu/MenuTrigger.ts deleted file mode 100644 index 72374da3..00000000 --- a/packages/react-cap-theme/src/components/react-menu/MenuTrigger.ts +++ /dev/null @@ -1,12 +0,0 @@ -export { - MenuTrigger, - MenuTriggerContextProvider, - renderMenuTrigger_unstable, - useMenuTrigger_unstable, - useMenuTriggerContext_unstable, -} from '@fluentui/react-menu'; -export type { - MenuTriggerChildProps, - MenuTriggerProps, - MenuTriggerState, -} from '@fluentui/react-menu'; diff --git a/packages/react-cap-theme/src/components/react-menu/components/MenuDivider/useMenuDividerStyles.styles.ts b/packages/react-cap-theme/src/components/react-menu/components/MenuDivider/useMenuDividerStyles.styles.ts index 528e529a..8c8f8430 100644 --- a/packages/react-cap-theme/src/components/react-menu/components/MenuDivider/useMenuDividerStyles.styles.ts +++ b/packages/react-cap-theme/src/components/react-menu/components/MenuDivider/useMenuDividerStyles.styles.ts @@ -1,18 +1,8 @@ -import { - type MenuDividerSlots, - type MenuDividerState, -} from '@fluentui/react-menu'; -import { - getSlotClassNameProp_unstable, - type SlotClassNames, -} from '@fluentui/react-utilities'; +import { type MenuDividerState } from '@fluentui/react-menu'; +import { getSlotClassNameProp_unstable } from '@fluentui/react-utilities'; import { tokens } from '@fluentui/tokens'; import { makeStyles, mergeClasses } from '@griffel/react'; -export const menuDividerClassNames: SlotClassNames = { - root: 'fui-MenuDivider', -}; - const useStyles = makeStyles({ root: { borderBottomColor: tokens.colorNeutralStroke3, @@ -26,7 +16,6 @@ export const useMenuDividerStyles = ( const styles = useStyles(); state.root.className = mergeClasses( state.root.className, - menuDividerClassNames.root, styles.root, getSlotClassNameProp_unstable(state.root) ); diff --git a/packages/react-cap-theme/src/components/react-menu/components/MenuGroupHeader/useMenuGroupHeaderStyles.styles.ts b/packages/react-cap-theme/src/components/react-menu/components/MenuGroupHeader/useMenuGroupHeaderStyles.styles.ts index e1c81389..f85b3dff 100644 --- a/packages/react-cap-theme/src/components/react-menu/components/MenuGroupHeader/useMenuGroupHeaderStyles.styles.ts +++ b/packages/react-cap-theme/src/components/react-menu/components/MenuGroupHeader/useMenuGroupHeaderStyles.styles.ts @@ -1,19 +1,9 @@ -import { - type MenuGroupHeaderSlots, - type MenuGroupHeaderState, -} from '@fluentui/react-menu'; -import { - getSlotClassNameProp_unstable, - type SlotClassNames, -} from '@fluentui/react-utilities'; +import { type MenuGroupHeaderState } from '@fluentui/react-menu'; +import { getSlotClassNameProp_unstable } from '@fluentui/react-utilities'; import { tokens } from '@fluentui/tokens'; import { typographyStyles } from '@fluentui/tokens'; import { makeStyles, mergeClasses } from '@griffel/react'; -export const menuGroupHeaderClassNames: SlotClassNames = { - root: 'fui-MenuGroupHeader', -}; - const useStyles = makeStyles({ root: { ...typographyStyles.caption1Strong, @@ -28,7 +18,6 @@ export const useMenuGroupHeaderStyles = ( const styles = useStyles(); state.root.className = mergeClasses( state.root.className, - menuGroupHeaderClassNames.root, styles.root, getSlotClassNameProp_unstable(state.root) ); diff --git a/packages/react-cap-theme/src/components/react-menu/components/MenuItem/useMenuItemStyles.styles.ts b/packages/react-cap-theme/src/components/react-menu/components/MenuItem/useMenuItemStyles.styles.ts index cc955056..284b1b95 100644 --- a/packages/react-cap-theme/src/components/react-menu/components/MenuItem/useMenuItemStyles.styles.ts +++ b/packages/react-cap-theme/src/components/react-menu/components/MenuItem/useMenuItemStyles.styles.ts @@ -1,26 +1,12 @@ import { menuItemClassNames as fluentMenuItemClassNames, - type MenuItemSlots, type MenuItemState, } from '@fluentui/react-menu'; -import { - getSlotClassNameProp_unstable, - type SlotClassNames, -} from '@fluentui/react-utilities'; +import { getSlotClassNameProp_unstable } from '@fluentui/react-utilities'; import { tokens } from '@fluentui/tokens'; import { typographyStyles } from '@fluentui/tokens'; import { makeStyles, mergeClasses } from '@griffel/react'; -export const menuItemClassNames: SlotClassNames = { - root: 'fui-MenuItem', - content: 'fui-MenuItem__content', - icon: 'fui-MenuItem__icon', - checkmark: 'fui-MenuItem__checkmark', - submenuIndicator: 'fui-MenuItem__submenuIndicator', - secondaryContent: 'fui-MenuItem__secondaryContent', - subText: 'fui-MenuItem__subText', -}; - const useStyles = makeStyles({ root: { borderRadius: tokens.borderRadiusXLarge, @@ -97,7 +83,6 @@ export const useMenuItemStyles = (state: MenuItemState): MenuItemState => { state.root.className = mergeClasses( state.root.className, - menuItemClassNames.root, styles.root, disabled && styles.disabled, getSlotClassNameProp_unstable(state.root) @@ -106,14 +91,12 @@ export const useMenuItemStyles = (state: MenuItemState): MenuItemState => { if (state.content) { state.content.className = mergeClasses( state.content.className, - menuItemClassNames.content, styles.content ); } if (state.icon) { state.icon.className = mergeClasses( state.icon.className, - menuItemClassNames.icon, styles.icon, getSlotClassNameProp_unstable(state.icon) ); @@ -121,7 +104,6 @@ export const useMenuItemStyles = (state: MenuItemState): MenuItemState => { if (state.secondaryContent) { state.secondaryContent.className = mergeClasses( state.secondaryContent.className, - menuItemClassNames.secondaryContent, styles.secondaryContent, getSlotClassNameProp_unstable(state.secondaryContent) ); @@ -129,7 +111,6 @@ export const useMenuItemStyles = (state: MenuItemState): MenuItemState => { if (state.submenuIndicator) { state.submenuIndicator.className = mergeClasses( state.submenuIndicator.className, - menuItemClassNames.submenuIndicator, styles.submenuIndicator, getSlotClassNameProp_unstable(state.submenuIndicator) ); @@ -137,7 +118,6 @@ export const useMenuItemStyles = (state: MenuItemState): MenuItemState => { if (state.subText) { state.subText.className = mergeClasses( state.subText.className, - menuItemClassNames.subText, styles.subText, getSlotClassNameProp_unstable(state.subText) ); diff --git a/packages/react-cap-theme/src/components/react-menu/components/MenuItemCheckbox/useMenuItemCheckboxStyles.styles.ts b/packages/react-cap-theme/src/components/react-menu/components/MenuItemCheckbox/useMenuItemCheckboxStyles.styles.ts index df477c80..8f89525b 100644 --- a/packages/react-cap-theme/src/components/react-menu/components/MenuItemCheckbox/useMenuItemCheckboxStyles.styles.ts +++ b/packages/react-cap-theme/src/components/react-menu/components/MenuItemCheckbox/useMenuItemCheckboxStyles.styles.ts @@ -1,24 +1,8 @@ -import type { - MenuItemCheckboxState, - MenuItemSlots, -} from '@fluentui/react-menu'; -import { - getSlotClassNameProp_unstable, - type SlotClassNames, -} from '@fluentui/react-utilities'; +import type { MenuItemCheckboxState } from '@fluentui/react-menu'; +import { getSlotClassNameProp_unstable } from '@fluentui/react-utilities'; import { makeStyles, mergeClasses } from '@griffel/react'; import { useMenuItemStyles } from '../MenuItem/useMenuItemStyles.styles'; -export const menuItemCheckboxClassNames: SlotClassNames = { - root: 'fui-MenuItemCheckbox', - content: 'fui-MenuItemCheckbox__content', - icon: 'fui-MenuItemCheckbox__icon', - checkmark: 'fui-MenuItemCheckbox__checkmark', - submenuIndicator: 'fui-MenuItemCheckbox__submenuIndicator', - secondaryContent: 'fui-MenuItemCheckbox__secondaryContent', - subText: 'fui-MenuItemCheckbox__subText', -}; - const useStyles = makeStyles({ checkmark: { fontSize: '20px', @@ -35,7 +19,6 @@ export const useMenuItemCheckboxStyles = ( if (state.checkmark) { state.checkmark.className = mergeClasses( state.checkmark.className, - menuItemCheckboxClassNames.checkmark, styles.checkmark, getSlotClassNameProp_unstable(state.checkmark) ); diff --git a/packages/react-cap-theme/src/components/react-menu/components/MenuItemLink/useMenuItemLinkStyles.styles.ts b/packages/react-cap-theme/src/components/react-menu/components/MenuItemLink/useMenuItemLinkStyles.styles.ts new file mode 100644 index 00000000..18c880d9 --- /dev/null +++ b/packages/react-cap-theme/src/components/react-menu/components/MenuItemLink/useMenuItemLinkStyles.styles.ts @@ -0,0 +1,72 @@ +import { + type MenuItemLinkState, + type MenuItemState, + menuItemLinkClassNames, +} from '@fluentui/react-menu'; +import { makeStyles, mergeClasses } from '@griffel/react'; +import { getSlotClassNameProp_unstable } from '@fluentui/react-utilities'; +import { useMenuItemStyles } from '../MenuItem/useMenuItemStyles.styles'; + +const useStyles = makeStyles({ + resetLink: { + textDecorationLine: 'none', + textDecorationThickness: 'initial', + textDecorationStyle: 'initial', + textDecorationColor: 'initial', + }, +}); + +/** + * Applies SharePoint-specific styling to MenuItemLink component. + * @param state - The MenuItemLink state object + * @returns The updated state with applied styles + * @alpha + */ +export const useMenuItemLinkStyles = ( + state: MenuItemLinkState +): MenuItemLinkState => { + const styles = useStyles(); + + state.root.className = mergeClasses( + menuItemLinkClassNames.root, + state.root.className, + styles.resetLink, + getSlotClassNameProp_unstable(state.root) + ); + + if (state.icon) { + state.icon.className = mergeClasses( + state.icon.className, + menuItemLinkClassNames.icon, + getSlotClassNameProp_unstable(state.icon) + ); + } + + if (state.content) { + state.content.className = mergeClasses( + state.content.className, + menuItemLinkClassNames.content, + getSlotClassNameProp_unstable(state.content) + ); + } + + if (state.secondaryContent) { + state.secondaryContent.className = mergeClasses( + state.secondaryContent.className, + menuItemLinkClassNames.secondaryContent, + getSlotClassNameProp_unstable(state.secondaryContent) + ); + } + + if (state.checkmark) { + state.checkmark.className = mergeClasses( + state.checkmark.className, + menuItemLinkClassNames.checkmark, + getSlotClassNameProp_unstable(state.checkmark) + ); + } + + useMenuItemStyles(state as MenuItemState); + + return state; +}; diff --git a/packages/react-cap-theme/src/components/react-menu/components/MenuItemRadio/useMenuItemRadio.tsx b/packages/react-cap-theme/src/components/react-menu/components/MenuItemRadio/useMenuItemRadio.tsx deleted file mode 100644 index 4779aa30..00000000 --- a/packages/react-cap-theme/src/components/react-menu/components/MenuItemRadio/useMenuItemRadio.tsx +++ /dev/null @@ -1,33 +0,0 @@ -import type { ARIAButtonElement } from '@fluentui/react-aria'; -import { - RadioButton20Filled, - RadioButton20Regular, -} from '@fluentui/react-icons'; -import { - useMenuItemRadio_unstable, - useMenuListContext_unstable, - type MenuItemRadioProps, - type MenuItemRadioState, -} from '@fluentui/react-menu'; -import { slot } from '@fluentui/react-utilities'; -import * as React from 'react'; - -export const useMenuItemRadio = ( - props: MenuItemRadioProps, - ref: React.Ref> -): MenuItemRadioState => { - const { name, value } = props; - const checked = useMenuListContext_unstable((context) => { - const checkedItems = context.checkedValues?.[name] || []; - return checkedItems.indexOf(value) !== -1; - }); - const checkmark = slot.optional(props.checkmark, { - defaultProps: { - children: checked ? : , - }, - renderByDefault: true, - elementType: 'span', - }); - - return useMenuItemRadio_unstable({ ...props, checkmark }, ref); -}; diff --git a/packages/react-cap-theme/src/components/react-menu/components/MenuItemRadio/useMenuItemRadioStyles.styles.ts b/packages/react-cap-theme/src/components/react-menu/components/MenuItemRadio/useMenuItemRadioStyles.styles.ts index a874928b..fe565e95 100644 --- a/packages/react-cap-theme/src/components/react-menu/components/MenuItemRadio/useMenuItemRadioStyles.styles.ts +++ b/packages/react-cap-theme/src/components/react-menu/components/MenuItemRadio/useMenuItemRadioStyles.styles.ts @@ -1,22 +1,8 @@ -import type { MenuItemRadioState, MenuItemSlots } from '@fluentui/react-menu'; -import { - getSlotClassNameProp_unstable, - type SlotClassNames, -} from '@fluentui/react-utilities'; +import type { MenuItemRadioState } from '@fluentui/react-menu'; +import { getSlotClassNameProp_unstable } from '@fluentui/react-utilities'; import { makeStyles, mergeClasses } from '@griffel/react'; import { useMenuItemStyles } from '../MenuItem/useMenuItemStyles.styles'; -export const menuItemRadioClassNames: SlotClassNames< - Omit -> = { - root: 'fui-MenuItemRadio', - content: 'fui-MenuItemRadio__content', - icon: 'fui-MenuItemRadio__icon', - checkmark: 'fui-MenuItemRadio__checkmark', - secondaryContent: 'fui-MenuItemRadio__secondaryContent', - subText: 'fui-MenuItemRadio__subText', -}; - const useStyles = makeStyles({ checkmark: { fontSize: '20px', @@ -34,13 +20,11 @@ export const useMenuItemRadioStyles = ( state.root.className = mergeClasses( state.root.className, - menuItemRadioClassNames.root, getSlotClassNameProp_unstable(state.root) ); if (state.checkmark) { state.checkmark.className = mergeClasses( state.checkmark.className, - menuItemRadioClassNames.content, styles.checkmark, getSlotClassNameProp_unstable(state.checkmark) ); diff --git a/packages/react-cap-theme/src/components/react-menu/components/MenuItemSwatchPicker/MenuItemSwatchPicker.tsx b/packages/react-cap-theme/src/components/react-menu/components/MenuItemSwatchPicker/MenuItemSwatchPicker.tsx deleted file mode 100644 index 8bdbb751..00000000 --- a/packages/react-cap-theme/src/components/react-menu/components/MenuItemSwatchPicker/MenuItemSwatchPicker.tsx +++ /dev/null @@ -1,19 +0,0 @@ -import { - renderSwatchPicker_unstable, - useSwatchPickerContextValues, -} from '@fluentui/react-swatch-picker'; -import type { ForwardRefComponent } from '@fluentui/react-utilities'; -import * as React from 'react'; -import type { MenuItemSwatchPickerProps } from './MenuItemSwatchPicker.types'; -import { useMenuItemSwatchPicker } from './useMenuItemSwatchPicker'; -import { useMenuItemSwatchPickerStyles } from './useMenuItemSwatchPickerStyles.styles'; - -export const MenuItemSwatchPicker: ForwardRefComponent = - React.forwardRef((props, ref) => { - const state = useMenuItemSwatchPicker(props, ref); - const contextValues = useSwatchPickerContextValues(state); - useMenuItemSwatchPickerStyles(state); - return renderSwatchPicker_unstable(state, contextValues); - }); - -MenuItemSwatchPicker.displayName = 'MenuItemSwatchPicker'; diff --git a/packages/react-cap-theme/src/components/react-menu/components/MenuItemSwatchPicker/MenuItemSwatchPicker.types.ts b/packages/react-cap-theme/src/components/react-menu/components/MenuItemSwatchPicker/MenuItemSwatchPicker.types.ts deleted file mode 100644 index 6be552cf..00000000 --- a/packages/react-cap-theme/src/components/react-menu/components/MenuItemSwatchPicker/MenuItemSwatchPicker.types.ts +++ /dev/null @@ -1,5 +0,0 @@ -import type { MenuItemSelectableProps } from '@fluentui/react-menu'; -import type { SwatchPickerProps } from '@fluentui/react-swatch-picker'; - -export type MenuItemSwatchPickerProps = Pick & - SwatchPickerProps; diff --git a/packages/react-cap-theme/src/components/react-menu/components/MenuItemSwatchPicker/useMenuItemSwatchPicker.tsx b/packages/react-cap-theme/src/components/react-menu/components/MenuItemSwatchPicker/useMenuItemSwatchPicker.tsx deleted file mode 100644 index 60898d46..00000000 --- a/packages/react-cap-theme/src/components/react-menu/components/MenuItemSwatchPicker/useMenuItemSwatchPicker.tsx +++ /dev/null @@ -1,50 +0,0 @@ -import { useMenuListContext_unstable } from '@fluentui/react-menu'; -import { - type SwatchPickerState, - useSwatchPicker_unstable, -} from '@fluentui/react-swatch-picker'; -import { useEventCallback } from '@fluentui/react-utilities'; -import type * as React from 'react'; -import type { MenuItemSwatchPickerProps } from './MenuItemSwatchPicker.types'; - -export const useMenuItemSwatchPicker = ( - props: MenuItemSwatchPickerProps, - ref: React.Ref -): SwatchPickerState => { - const { - layout = 'grid', - name, - spacing = 'medium', - onSelectionChange, - } = props; - const state = useSwatchPicker_unstable({ ...props, layout, spacing }, ref); - - const selectedValue = useMenuListContext_unstable( - (ctx) => ctx.checkedValues?.[name]?.[0] - ); - - const selectMenuItem = useMenuListContext_unstable( - (context) => context.selectRadio - ); - - const requestSelectionChange: SwatchPickerState['requestSelectionChange'] = - useEventCallback((event, data) => { - onSelectionChange?.(event, { - type: 'click', - event, - selectedValue: data.selectedValue, - selectedSwatch: data.selectedSwatch, - }); - selectMenuItem?.( - event as React.MouseEvent, - name, - data.selectedValue, - true - ); - }); - - state.selectedValue = selectedValue; - state.requestSelectionChange = requestSelectionChange; - - return state; -}; diff --git a/packages/react-cap-theme/src/components/react-menu/components/MenuItemSwatchPicker/useMenuItemSwatchPickerStyles.styles.ts b/packages/react-cap-theme/src/components/react-menu/components/MenuItemSwatchPicker/useMenuItemSwatchPickerStyles.styles.ts deleted file mode 100644 index a4415d38..00000000 --- a/packages/react-cap-theme/src/components/react-menu/components/MenuItemSwatchPicker/useMenuItemSwatchPickerStyles.styles.ts +++ /dev/null @@ -1,37 +0,0 @@ -import { - type SwatchPickerSlots, - type SwatchPickerState, -} from '@fluentui/react-swatch-picker'; -import { - getSlotClassNameProp_unstable, - type SlotClassNames, -} from '@fluentui/react-utilities'; -import { tokens } from '@fluentui/tokens'; -import { makeStyles, mergeClasses, shorthands } from '@griffel/react'; - -export const menuItemSwatchPickerClassNames: SlotClassNames = - { - root: 'fui-MenuItemSwatchPicker', - }; - -const useStyles = makeStyles({ - root: { - ...shorthands.padding( - tokens.spacingVerticalMNudge, - tokens.spacingHorizontalMNudge - ), - }, -}); - -export const useMenuItemSwatchPickerStyles = ( - state: SwatchPickerState -): SwatchPickerState => { - const styles = useStyles(); - state.root.className = mergeClasses( - state.root.className, - menuItemSwatchPickerClassNames.root, - styles.root, - getSlotClassNameProp_unstable(state.root) - ); - return state; -}; diff --git a/packages/react-cap-theme/src/components/react-menu/components/MenuItemSwitch/useMenuItemSwitchStyles.styles.ts b/packages/react-cap-theme/src/components/react-menu/components/MenuItemSwitch/useMenuItemSwitchStyles.styles.ts new file mode 100644 index 00000000..7d461b16 --- /dev/null +++ b/packages/react-cap-theme/src/components/react-menu/components/MenuItemSwitch/useMenuItemSwitchStyles.styles.ts @@ -0,0 +1,260 @@ +import { + menuItemSwitchClassNames, + type MenuItemSwitchState, +} from '@fluentui/react-menu'; +import type { ElementType } from 'react'; +import { + makeStyles, + makeResetStyles, + mergeClasses, + shorthands, +} from '@griffel/react'; +import { tokens } from '@fluentui/tokens'; +import { getSlotClassNameProp_unstable } from '@fluentui/react-utilities'; +import { useMenuItemStyles } from '../MenuItem/useMenuItemStyles.styles'; +import { useCheckmarkStyles_unstable } from '../../selectable/useCheckmarkStyles.style'; + +// Copied from Fluent +const circleFilledClassName = + 'fui-MenuItemSwitch__switchIndicator__circleFilled'; + +const spaceBetweenThumbAndTrack = 4; +const trackHeight = 24; +const trackWidth = 48; +const thumbSize = 20; + +const useSwitchIndicatorBaseClassName = makeResetStyles({ + display: 'flex', + alignItems: 'center', + padding: `${tokens.spacingVerticalXXS} ${tokens.spacingHorizontalXXS}`, + fontSize: `${thumbSize}px`, + height: `${trackHeight}px`, + width: `${trackWidth}px`, + borderRadius: tokens.borderRadiusCircular, + border: `${tokens.strokeWidthThin} solid ${tokens.colorNeutralStrokeAccessible}`, + lineHeight: 0, + boxSizing: 'border-box', + fill: 'currentColor', + flexShrink: 0, + transitionDuration: tokens.durationNormal, + transitionTimingFunction: tokens.curveEasyEase, + transitionProperty: 'background, border, color', + + '@media screen and (prefers-reduced-motion: reduce)': { + transitionDuration: '0.01ms', + }, + + [`& .${circleFilledClassName}`]: { + transitionDuration: tokens.durationNormal, + transitionTimingFunction: tokens.curveEasyEase, + transitionProperty: 'transform', + + '@media screen and (prefers-reduced-motion: reduce)': { + transitionDuration: '0.01ms', + }, + }, +}); + +const useStyles = makeStyles({ + root: { + paddingTop: tokens.spacingVerticalXS, + paddingBottom: tokens.spacingVerticalXS, + }, + switchIndicator: { marginLeft: tokens.spacingHorizontalS }, + content: { + marginTop: tokens.spacingVerticalXXS, + marginBottom: tokens.spacingVerticalXXS, + }, + icon: { + marginTop: tokens.spacingVerticalXXS, + marginBottom: tokens.spacingVerticalXXS, + }, + secondaryContent: { + marginTop: tokens.spacingVerticalXXS, + marginBottom: tokens.spacingVerticalXXS, + }, +}); + +const useInteractiveStyles = makeStyles({ + unchecked: { + ':hover': { + [`& .${menuItemSwitchClassNames.switchIndicator}`]: { + ...shorthands.borderColor(tokens.colorNeutralStrokeAccessibleHover), + color: tokens.colorNeutralForeground3Hover, + }, + }, + ':hover:active': { + [`& .${menuItemSwitchClassNames.switchIndicator}`]: { + ...shorthands.borderColor(tokens.colorNeutralStrokeAccessiblePressed), + color: tokens.colorNeutralForeground3Pressed, + }, + }, + '@media (forced-colors: active)': { + ':hover': { + [`& .${menuItemSwitchClassNames.switchIndicator}`]: { + ...shorthands.borderColor('Highlight'), + color: 'inherit', + }, + }, + ':hover:active': { + [`& .${menuItemSwitchClassNames.switchIndicator}`]: { + ...shorthands.borderColor('Highlight'), + color: 'inherit', + }, + }, + }, + }, + checked: { + ':hover': { + [`& .${menuItemSwitchClassNames.switchIndicator}`]: { + backgroundColor: tokens.colorCompoundBrandBackgroundHover, + }, + }, + ':hover:active': { + [`& .${menuItemSwitchClassNames.switchIndicator}`]: { + backgroundColor: tokens.colorCompoundBrandBackgroundPressed, + }, + }, + '@media (forced-colors: active)': { + ':hover': { + [`& .${menuItemSwitchClassNames.switchIndicator}`]: { + backgroundColor: 'Highlight', + }, + }, + ':hover:active': { + [`& .${menuItemSwitchClassNames.switchIndicator}`]: { + backgroundColor: 'Highlight', + }, + }, + }, + }, +}); + +const useSwitchIndicatorStyles = makeStyles({ + unchecked: { color: tokens.colorNeutralForeground3 }, + checked: { + backgroundColor: tokens.colorCompoundBrandBackground, + color: tokens.colorNeutralForegroundInverted, + ...shorthands.borderColor(tokens.colorTransparentStroke), + [`& .${circleFilledClassName}`]: { + transform: `translateX(${ + trackWidth - thumbSize - spaceBetweenThumbAndTrack + }px)`, + }, + + '@media (forced-colors: active)': { + backgroundColor: 'Highlight', + ...shorthands.borderColor('Highlight'), + color: 'HighlightText', + }, + }, + disabled: { + color: 'inherit', + '@media (forced-colors: active)': { + backgroundColor: 'Canvas', + ...shorthands.borderColor('GrayText'), + color: 'inherit', + }, + }, + disabledChecked: { backgroundColor: tokens.colorNeutralBackgroundDisabled }, + disabledUnchecked: { + ...shorthands.borderColor(tokens.colorNeutralStrokeDisabled), + }, +}); + +/** + * Applies SharePoint-specific styling to MenuItemSwitch component. + * @param state - The MenuItemSwitch state object + * @returns The updated state with applied styles + * @alpha + */ +export const useMenuItemSwitchStyles = ( + state: MenuItemSwitchState +): MenuItemSwitchState => { + const styles = useStyles(); + const interactiveStyles = useInteractiveStyles(); + const switchIndicatorBaseStyles = useSwitchIndicatorBaseClassName(); + const switchIndicatorStyles = useSwitchIndicatorStyles(); + + const { checked, disabled } = state; + + state.root.className = mergeClasses( + state.root.className, + menuItemSwitchClassNames.root, + styles.root, + !disabled && + (checked ? interactiveStyles.checked : interactiveStyles.unchecked), + getSlotClassNameProp_unstable(state.root) + ); + + if (state.content) { + state.content.className = mergeClasses( + state.content.className, + menuItemSwitchClassNames.content, + styles.content, + getSlotClassNameProp_unstable(state.content) + ); + } + + if (state.secondaryContent) { + state.secondaryContent.className = mergeClasses( + state.secondaryContent.className, + menuItemSwitchClassNames.secondaryContent, + styles.secondaryContent, + getSlotClassNameProp_unstable(state.secondaryContent) + ); + } + + if (state.icon) { + state.icon.className = mergeClasses( + state.icon.className, + menuItemSwitchClassNames.icon, + styles.icon, + getSlotClassNameProp_unstable(state.icon) + ); + } + + if (state.subText) { + state.subText.className = mergeClasses( + state.subText.className, + menuItemSwitchClassNames.subText, + getSlotClassNameProp_unstable(state.subText) + ); + } + + if (state.switchIndicator) { + state.switchIndicator.className = mergeClasses( + state.switchIndicator.className, + menuItemSwitchClassNames.switchIndicator, + switchIndicatorBaseStyles, + styles.switchIndicator, + checked ? switchIndicatorStyles.checked : switchIndicatorStyles.unchecked, + disabled && switchIndicatorStyles.disabled, + disabled && + (checked + ? switchIndicatorStyles.disabledChecked + : switchIndicatorStyles.disabledUnchecked), + getSlotClassNameProp_unstable(state.switchIndicator) + ); + } + + const partialMenuItemState = { + components: { + ...state.components, + checkmark: 'span' as ElementType, + submenuIndicator: 'span' as ElementType, + }, + hasSubmenu: false, + persistOnClick: true, + }; + + useCheckmarkStyles_unstable({ ...state, ...partialMenuItemState }); + useMenuItemStyles({ + ...state, + ...partialMenuItemState, + checkmark: undefined, + submenuIndicator: undefined, + }); + + return state; +}; diff --git a/packages/react-cap-theme/src/components/react-menu/components/MenuPopover/useMenuPopoverStyles.styles.ts b/packages/react-cap-theme/src/components/react-menu/components/MenuPopover/useMenuPopoverStyles.styles.ts index aab3644b..c7ac0a41 100644 --- a/packages/react-cap-theme/src/components/react-menu/components/MenuPopover/useMenuPopoverStyles.styles.ts +++ b/packages/react-cap-theme/src/components/react-menu/components/MenuPopover/useMenuPopoverStyles.styles.ts @@ -1,19 +1,8 @@ -import { - type MenuPopoverSlots, - type MenuPopoverState, -} from '@fluentui/react-menu'; -import { - getSlotClassNameProp_unstable, - type SlotClassNames, -} from '@fluentui/react-utilities'; +import { type MenuPopoverState } from '@fluentui/react-menu'; +import { getSlotClassNameProp_unstable } from '@fluentui/react-utilities'; import { tokens } from '@fluentui/tokens'; import { makeStyles, mergeClasses } from '@griffel/react'; -export const menuPopoverClassNames: Partial> = - { - root: 'fui-MenuPopover', - }; - const useStyles = makeStyles({ root: { border: `${tokens.strokeWidthThin} solid ${tokens.colorNeutralStrokeAlpha}`, @@ -31,7 +20,6 @@ export const useMenuPopoverStyles = ( state.root.className = mergeClasses( state.root.className, - menuPopoverClassNames.root, styles.root, getSlotClassNameProp_unstable(state.root) ); diff --git a/packages/react-cap-theme/src/components/react-menu/components/MenuSplitGroup/useMenuSplitGroupStyles.styles.ts b/packages/react-cap-theme/src/components/react-menu/components/MenuSplitGroup/useMenuSplitGroupStyles.styles.ts index 7d0fc9b2..c89d04e1 100644 --- a/packages/react-cap-theme/src/components/react-menu/components/MenuSplitGroup/useMenuSplitGroupStyles.styles.ts +++ b/packages/react-cap-theme/src/components/react-menu/components/MenuSplitGroup/useMenuSplitGroupStyles.styles.ts @@ -1,19 +1,11 @@ import { menuItemClassNames, - type MenuSplitGroupSlots, type MenuSplitGroupState, } from '@fluentui/react-menu'; -import { - getSlotClassNameProp_unstable, - type SlotClassNames, -} from '@fluentui/react-utilities'; +import { getSlotClassNameProp_unstable } from '@fluentui/react-utilities'; import { tokens } from '@fluentui/tokens'; import { makeStyles, mergeClasses } from '@griffel/react'; -export const menuSplitGroupClassNames: SlotClassNames = { - root: 'fui-MenuSplitGroup', -}; - const useStyles = makeStyles({ root: { [`& > .${menuItemClassNames.root}:nth-of-type(1)`]: { @@ -43,7 +35,6 @@ export const useMenuSplitGroupStyles = ( const styles = useStyles(); state.root.className = mergeClasses( state.root.className, - menuSplitGroupClassNames.root, styles.root, getSlotClassNameProp_unstable(state.root) ); diff --git a/packages/react-cap-theme/src/components/react-menu/index.ts b/packages/react-cap-theme/src/components/react-menu/index.ts index 32d0ff46..ef4a1aaf 100644 --- a/packages/react-cap-theme/src/components/react-menu/index.ts +++ b/packages/react-cap-theme/src/components/react-menu/index.ts @@ -2,7 +2,9 @@ export { useMenuDividerStyles } from './components/MenuDivider/useMenuDividerSty export { useMenuGroupHeaderStyles } from './components/MenuGroupHeader/useMenuGroupHeaderStyles.styles'; export { useMenuItemStyles } from './components/MenuItem/useMenuItemStyles.styles'; export { useMenuItemCheckboxStyles } from './components/MenuItemCheckbox/useMenuItemCheckboxStyles.styles'; +export { useMenuItemLinkStyles } from './components/MenuItemLink/useMenuItemLinkStyles.styles'; export { useMenuItemRadioStyles } from './components/MenuItemRadio/useMenuItemRadioStyles.styles'; export { useMenuItemSwatchPickerStyles } from './components/MenuItemSwatchPicker/useMenuItemSwatchPickerStyles.styles'; +export { useMenuItemSwitchStyles } from './components/MenuItemSwitch/useMenuItemSwitchStyles.styles'; export { useMenuPopoverStyles } from './components/MenuPopover/useMenuPopoverStyles.styles'; export { useMenuSplitGroupStyles } from './components/MenuSplitGroup/useMenuSplitGroupStyles.styles'; diff --git a/packages/react-cap-theme/src/components/react-menu/selectable/useCheckmarkStyles.style.ts b/packages/react-cap-theme/src/components/react-menu/selectable/useCheckmarkStyles.style.ts new file mode 100644 index 00000000..2cbd4412 --- /dev/null +++ b/packages/react-cap-theme/src/components/react-menu/selectable/useCheckmarkStyles.style.ts @@ -0,0 +1,87 @@ +import { mergeClasses, makeStyles } from '@griffel/react'; +import { + menuItemClassNames, + type MenuItemSelectableState, + type MenuItemState, +} from '@fluentui/react-menu'; +import { + iconFilledClassName, + iconRegularClassName, +} from '@fluentui/react-icons'; +import { tokens } from '@fluentui/tokens'; + +const useStyles = makeStyles({ + checked: { + [`& .${iconFilledClassName}`]: { display: 'inline' }, + [`& .${iconRegularClassName}`]: { display: 'none' }, + + // Override Fluent + [`:hover .${iconFilledClassName}`]: { display: 'inline' }, + [`:hover .${iconRegularClassName}`]: { display: 'none' }, + }, + checkmark: { + boxSizing: 'border-box', + height: '20px', + width: '20px', + marginRight: tokens.spacingHorizontalSNudge, + marginTop: tokens.spacingVerticalNone, + flexShrink: 0, + visibility: 'visible', // override Fluent + }, +}); + +const useInteractiveStyles = makeStyles({ + checked: { + ':hover': { + [`& .${menuItemClassNames.icon}`]: { + color: tokens.colorBrandForeground2Hover, + }, + }, + ':hover:active': { + [`& .${menuItemClassNames.icon}`]: { + color: tokens.colorBrandForeground2Pressed, + }, + }, + '@media (forced-colors: active)': { + ':hover': { [`& .${menuItemClassNames.icon}`]: { color: 'inherit' } }, + ':hover:active': { + [`& .${menuItemClassNames.icon}`]: { color: 'inherit' }, + }, + }, + }, + iconChecked: { color: tokens.colorBrandForeground2 }, +}); + +/** + * Applies styles to selectable menu items + * @param state - Menu item object. Should contain a `checked` prop + * @returns void + * @alpha + */ +export const useCheckmarkStyles_unstable = ( + state: MenuItemSelectableState & MenuItemState +): void => { + const { checked, disabled } = state; + const styles = useStyles(); + const interactiveStyles = useInteractiveStyles(); + + state.root.className = mergeClasses( + state.checked && styles.checked, + !disabled && checked && interactiveStyles.checked, + state.root.className + ); + + if (state.icon) { + state.icon.className = mergeClasses( + !disabled && checked && interactiveStyles.iconChecked, + state.icon.className + ); + } + + if (state.checkmark) { + state.checkmark.className = mergeClasses( + styles.checkmark, + state.checkmark.className + ); + } +}; From f426d634834085bafea299b3759681b3a761ac20 Mon Sep 17 00:00:00 2001 From: EnricoGianoglio Date: Thu, 7 May 2026 15:31:24 +0200 Subject: [PATCH 2/6] removed unnecessary export --- packages/react-cap-theme/src/components/react-menu/index.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/react-cap-theme/src/components/react-menu/index.ts b/packages/react-cap-theme/src/components/react-menu/index.ts index ef4a1aaf..a9ae346b 100644 --- a/packages/react-cap-theme/src/components/react-menu/index.ts +++ b/packages/react-cap-theme/src/components/react-menu/index.ts @@ -4,7 +4,6 @@ export { useMenuItemStyles } from './components/MenuItem/useMenuItemStyles.style export { useMenuItemCheckboxStyles } from './components/MenuItemCheckbox/useMenuItemCheckboxStyles.styles'; export { useMenuItemLinkStyles } from './components/MenuItemLink/useMenuItemLinkStyles.styles'; export { useMenuItemRadioStyles } from './components/MenuItemRadio/useMenuItemRadioStyles.styles'; -export { useMenuItemSwatchPickerStyles } from './components/MenuItemSwatchPicker/useMenuItemSwatchPickerStyles.styles'; export { useMenuItemSwitchStyles } from './components/MenuItemSwitch/useMenuItemSwitchStyles.styles'; export { useMenuPopoverStyles } from './components/MenuPopover/useMenuPopoverStyles.styles'; export { useMenuSplitGroupStyles } from './components/MenuSplitGroup/useMenuSplitGroupStyles.styles'; From 2f740620502fe6519bfbbb659f1363a586caa69f Mon Sep 17 00:00:00 2001 From: EnricoGianoglio Date: Thu, 7 May 2026 15:39:11 +0200 Subject: [PATCH 3/6] fix MenuItemRadio check visibility --- .../components/MenuItemRadio/useMenuItemRadioStyles.styles.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/react-cap-theme/src/components/react-menu/components/MenuItemRadio/useMenuItemRadioStyles.styles.ts b/packages/react-cap-theme/src/components/react-menu/components/MenuItemRadio/useMenuItemRadioStyles.styles.ts index fe565e95..ad3e6ff1 100644 --- a/packages/react-cap-theme/src/components/react-menu/components/MenuItemRadio/useMenuItemRadioStyles.styles.ts +++ b/packages/react-cap-theme/src/components/react-menu/components/MenuItemRadio/useMenuItemRadioStyles.styles.ts @@ -8,7 +8,6 @@ const useStyles = makeStyles({ fontSize: '20px', height: '20px', marginTop: 0, - visibility: 'visible', width: '20px', }, }); From dde006063a409d99b8889f3b000ca71364cc5447 Mon Sep 17 00:00:00 2001 From: EnricoGianoglio Date: Thu, 7 May 2026 15:39:40 +0200 Subject: [PATCH 4/6] remove comments --- .../react-menu/selectable/useCheckmarkStyles.style.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/react-cap-theme/src/components/react-menu/selectable/useCheckmarkStyles.style.ts b/packages/react-cap-theme/src/components/react-menu/selectable/useCheckmarkStyles.style.ts index 2cbd4412..3638628f 100644 --- a/packages/react-cap-theme/src/components/react-menu/selectable/useCheckmarkStyles.style.ts +++ b/packages/react-cap-theme/src/components/react-menu/selectable/useCheckmarkStyles.style.ts @@ -15,7 +15,6 @@ const useStyles = makeStyles({ [`& .${iconFilledClassName}`]: { display: 'inline' }, [`& .${iconRegularClassName}`]: { display: 'none' }, - // Override Fluent [`:hover .${iconFilledClassName}`]: { display: 'inline' }, [`:hover .${iconRegularClassName}`]: { display: 'none' }, }, @@ -26,7 +25,7 @@ const useStyles = makeStyles({ marginRight: tokens.spacingHorizontalSNudge, marginTop: tokens.spacingVerticalNone, flexShrink: 0, - visibility: 'visible', // override Fluent + visibility: 'visible', }, }); From d40138889e46a4f9da31b1a18579a1c82211a9fa Mon Sep 17 00:00:00 2001 From: EnricoGianoglio Date: Thu, 7 May 2026 15:42:21 +0200 Subject: [PATCH 5/6] Change files --- ...act-cap-theme-c05a3706-9c93-47fa-841d-2b7de6a356c8.json | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 change/@fluentui-contrib-react-cap-theme-c05a3706-9c93-47fa-841d-2b7de6a356c8.json diff --git a/change/@fluentui-contrib-react-cap-theme-c05a3706-9c93-47fa-841d-2b7de6a356c8.json b/change/@fluentui-contrib-react-cap-theme-c05a3706-9c93-47fa-841d-2b7de6a356c8.json new file mode 100644 index 00000000..883064f0 --- /dev/null +++ b/change/@fluentui-contrib-react-cap-theme-c05a3706-9c93-47fa-841d-2b7de6a356c8.json @@ -0,0 +1,7 @@ +{ + "type": "patch", + "comment": "react-menu components refactoring", + "packageName": "@fluentui-contrib/react-cap-theme", + "email": "egianoglio@microsoft.com", + "dependentChangeType": "patch" +} From aa2289554cc464954d90ab662db5e2f26aaf1d9b Mon Sep 17 00:00:00 2001 From: EnricoGianoglio Date: Fri, 8 May 2026 19:01:19 +0200 Subject: [PATCH 6/6] removed menuItemLinkClassNames --- .../components/MenuItemLink/useMenuItemLinkStyles.styles.ts | 6 ------ 1 file changed, 6 deletions(-) diff --git a/packages/react-cap-theme/src/components/react-menu/components/MenuItemLink/useMenuItemLinkStyles.styles.ts b/packages/react-cap-theme/src/components/react-menu/components/MenuItemLink/useMenuItemLinkStyles.styles.ts index 18c880d9..b069db02 100644 --- a/packages/react-cap-theme/src/components/react-menu/components/MenuItemLink/useMenuItemLinkStyles.styles.ts +++ b/packages/react-cap-theme/src/components/react-menu/components/MenuItemLink/useMenuItemLinkStyles.styles.ts @@ -1,7 +1,6 @@ import { type MenuItemLinkState, type MenuItemState, - menuItemLinkClassNames, } from '@fluentui/react-menu'; import { makeStyles, mergeClasses } from '@griffel/react'; import { getSlotClassNameProp_unstable } from '@fluentui/react-utilities'; @@ -28,7 +27,6 @@ export const useMenuItemLinkStyles = ( const styles = useStyles(); state.root.className = mergeClasses( - menuItemLinkClassNames.root, state.root.className, styles.resetLink, getSlotClassNameProp_unstable(state.root) @@ -37,7 +35,6 @@ export const useMenuItemLinkStyles = ( if (state.icon) { state.icon.className = mergeClasses( state.icon.className, - menuItemLinkClassNames.icon, getSlotClassNameProp_unstable(state.icon) ); } @@ -45,7 +42,6 @@ export const useMenuItemLinkStyles = ( if (state.content) { state.content.className = mergeClasses( state.content.className, - menuItemLinkClassNames.content, getSlotClassNameProp_unstable(state.content) ); } @@ -53,7 +49,6 @@ export const useMenuItemLinkStyles = ( if (state.secondaryContent) { state.secondaryContent.className = mergeClasses( state.secondaryContent.className, - menuItemLinkClassNames.secondaryContent, getSlotClassNameProp_unstable(state.secondaryContent) ); } @@ -61,7 +56,6 @@ export const useMenuItemLinkStyles = ( if (state.checkmark) { state.checkmark.className = mergeClasses( state.checkmark.className, - menuItemLinkClassNames.checkmark, getSlotClassNameProp_unstable(state.checkmark) ); }