Skip to content

Commit 55790fa

Browse files
committed
fixup! feat(react-menu): add base hooks for Menu, MenuList and export them
1 parent 21792df commit 55790fa

13 files changed

Lines changed: 191 additions & 57 deletions

File tree

packages/react-components/react-menu/library/etc/react-menu.api.md

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,12 @@ export const Menu: React_2.FC<MenuProps>;
3232
// @public
3333
export const MENU_ENTER_EVENT = "fuimenuenter";
3434

35+
// @public (undocumented)
36+
export type MenuBaseProps = Omit<MenuProps, 'surfaceMotion'>;
37+
38+
// @public (undocumented)
39+
export type MenuBaseState = Omit<MenuState, 'surfaceMotion' | 'components'>;
40+
3541
// @public (undocumented)
3642
export type MenuCheckedValueChangeData = {
3743
checkedItems: string[];
@@ -167,6 +173,12 @@ export type MenuItemProps = Omit<ComponentProps<Partial<MenuItemSlots>>, 'conten
167173
// @public
168174
export const MenuItemRadio: ForwardRefComponent<MenuItemRadioProps>;
169175

176+
// @public
177+
export type MenuItemRadioBaseProps = MenuItemRadioProps;
178+
179+
// @public
180+
export type MenuItemRadioBaseState = MenuItemRadioState;
181+
170182
// @public (undocumented)
171183
export const menuItemRadioClassNames: SlotClassNames<Omit<MenuItemSlots, 'submenuIndicator'>>;
172184

@@ -221,6 +233,12 @@ export type MenuItemSwitchState = ComponentState<MenuItemSwitchSlots> & MenuItem
221233
// @public
222234
export const MenuList: ForwardRefComponent<MenuListProps>;
223235

236+
// @public
237+
export type MenuListBaseProps = MenuListProps;
238+
239+
// @public
240+
export type MenuListBaseState = MenuListState;
241+
224242
// @public (undocumented)
225243
export const menuListClassNames: SlotClassNames<MenuListSlots>;
226244

@@ -322,6 +340,12 @@ export type MenuOpenEvents = MenuOpenEvent;
322340
// @public
323341
export const MenuPopover: ForwardRefComponent<MenuPopoverProps>;
324342

343+
// @public (undocumented)
344+
export type MenuPopoverBaseProps = MenuPopoverProps;
345+
346+
// @public (undocumented)
347+
export type MenuPopoverBaseState = MenuPopoverState;
348+
325349
// @public (undocumented)
326350
export const menuPopoverClassNames: SlotClassNames<MenuPopoverSlots>;
327351

@@ -482,6 +506,13 @@ export const useMenu_unstable: (props: MenuProps & {
482506
};
483507
}) => MenuState;
484508

509+
// @public
510+
export const useMenuBase_unstable: (props: MenuBaseProps & {
511+
safeZone?: boolean | {
512+
timeout?: number;
513+
};
514+
}) => MenuBaseState;
515+
485516
// @public (undocumented)
486517
export const useMenuContext_unstable: <T>(selector: ContextSelector<MenuContextValue, T>) => T;
487518

@@ -515,21 +546,33 @@ export const useMenuGroupStyles_unstable: (state: MenuGroupState) => MenuGroupSt
515546
// @public
516547
export const useMenuItem_unstable: (props: MenuItemProps, ref: React_2.Ref<ARIAButtonElement<"div">>) => MenuItemState;
517548

549+
// @internal
550+
export const useMenuItemBase_unstable: (props: MenuItemProps, ref: React_2.Ref<ARIAButtonElement<"div">>) => MenuItemState;
551+
518552
// @public
519553
export const useMenuItemCheckbox_unstable: (props: MenuItemCheckboxProps, ref: React_2.Ref<ARIAButtonElement<"div">>) => MenuItemCheckboxState;
520554

555+
// @internal
556+
export const useMenuItemCheckboxBase_unstable: (props: MenuItemCheckboxProps, ref: React_2.Ref<ARIAButtonElement<"div">>) => MenuItemCheckboxState;
557+
521558
// @public (undocumented)
522559
export const useMenuItemCheckboxStyles_unstable: (state: MenuItemCheckboxState) => MenuItemCheckboxState;
523560

524561
// @public
525562
export const useMenuItemLink_unstable: (props: MenuItemLinkProps, ref: React_2.Ref<HTMLAnchorElement>) => MenuItemLinkState;
526563

564+
// @public
565+
export const useMenuItemLinkBase_unstable: (props: MenuItemLinkProps, ref: React_2.Ref<HTMLAnchorElement>) => MenuItemLinkState;
566+
527567
// @public
528568
export const useMenuItemLinkStyles_unstable: (state: MenuItemLinkState) => MenuItemLinkState;
529569

530570
// @public
531571
export const useMenuItemRadio_unstable: (props: MenuItemRadioProps, ref: React_2.Ref<ARIAButtonElement<"div">>) => MenuItemRadioState;
532572

573+
// @internal
574+
export const useMenuItemRadioBase_unstable: (props: MenuItemRadioBaseProps, ref: React_2.Ref<ARIAButtonElement<"div">>) => MenuItemRadioBaseState;
575+
533576
// @public (undocumented)
534577
export const useMenuItemRadioStyles_unstable: (state: MenuItemRadioState) => void;
535578

@@ -539,12 +582,18 @@ export const useMenuItemStyles_unstable: (state: MenuItemState) => MenuItemState
539582
// @public
540583
export const useMenuItemSwitch_unstable: (props: MenuItemSwitchProps, ref: React_2.Ref<HTMLDivElement>) => MenuItemSwitchState;
541584

585+
// @internal
586+
export const useMenuItemSwitchBase_unstable: (props: MenuItemSwitchProps, ref: React_2.Ref<HTMLDivElement>) => MenuItemSwitchState;
587+
542588
// @public
543589
export const useMenuItemSwitchStyles_unstable: (state: MenuItemSwitchState) => MenuItemSwitchState;
544590

545591
// @public
546592
export const useMenuList_unstable: (props: MenuListProps, ref: React_2.Ref<HTMLElement>) => MenuListState;
547593

594+
// @public
595+
export const useMenuListBase_unstable: (props: MenuListBaseProps, ref: React_2.Ref<HTMLElement>) => MenuListBaseState;
596+
548597
// @public (undocumented)
549598
export const useMenuListContext_unstable: <T>(selector: ContextSelector<MenuListContextValue, T>) => T;
550599

@@ -557,6 +606,9 @@ export const useMenuListStyles_unstable: (state: MenuListState) => MenuListState
557606
// @public
558607
export const useMenuPopover_unstable: (props: MenuPopoverProps, ref: React_2.Ref<HTMLElement>) => MenuPopoverState;
559608

609+
// @public
610+
export const useMenuPopoverBase_unstable: (props: MenuPopoverBaseProps, ref: React_2.Ref<HTMLElement>) => MenuPopoverBaseState;
611+
560612
// @public
561613
export const useMenuPopoverStyles_unstable: (state: MenuPopoverState) => MenuPopoverState;
562614

packages/react-components/react-menu/library/src/MenuItemLink.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ export {
33
MenuItemLink,
44
menuItemLinkClassNames,
55
renderMenuItemLink_unstable,
6+
useMenuItemLinkBase_unstable,
67
useMenuItemLinkStyles_unstable,
78
useMenuItemLink_unstable,
89
} from './components/MenuItemLink/index';
Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,14 @@
1-
export type { MenuItemRadioProps, MenuItemRadioState } from './components/MenuItemRadio/index';
1+
export type {
2+
MenuItemRadioBaseProps,
3+
MenuItemRadioBaseState,
4+
MenuItemRadioProps,
5+
MenuItemRadioState,
6+
} from './components/MenuItemRadio/index';
27
export {
38
MenuItemRadio,
49
menuItemRadioClassNames,
510
renderMenuItemRadio_unstable,
11+
useMenuItemRadioBase_unstable,
612
useMenuItemRadioStyles_unstable,
713
useMenuItemRadio_unstable,
8-
useMenuItemRadioBase_unstable,
914
} from './components/MenuItemRadio/index';
Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,15 @@
1-
export type { MenuPopoverProps, MenuPopoverSlots, MenuPopoverState } from './components/MenuPopover/index';
1+
export type {
2+
MenuPopoverBaseProps,
3+
MenuPopoverBaseState,
4+
MenuPopoverProps,
5+
MenuPopoverSlots,
6+
MenuPopoverState,
7+
} from './components/MenuPopover/index';
28
export {
39
MenuPopover,
410
menuPopoverClassNames,
511
renderMenuPopover_unstable,
12+
useMenuPopoverBase_unstable,
613
useMenuPopoverStyles_unstable,
714
useMenuPopover_unstable,
815
} from './components/MenuPopover/index';

packages/react-components/react-menu/library/src/components/Menu/Menu.types.ts

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -187,17 +187,9 @@ export type MenuState = ComponentState<InternalMenuSlots> &
187187
safeZone?: React.ReactElement | null;
188188
};
189189

190-
/**
191-
* MenuBase Props - omits the design-related `surfaceMotion` slot.
192-
*/
193190
export type MenuBaseProps = Omit<MenuProps, 'surfaceMotion'>;
194191

195-
/**
196-
* MenuBase State - omits the design-related `surfaceMotion` slot and its `components` entry.
197-
*/
198-
export type MenuBaseState = Omit<MenuState, 'surfaceMotion' | 'components'> & {
199-
components: Record<string, never>;
200-
};
192+
export type MenuBaseState = Omit<MenuState, 'surfaceMotion' | 'components'>;
201193

202194
export type MenuContextValues = {
203195
menu: MenuContextValue;

packages/react-components/react-menu/library/src/components/Menu/useMenu.tsx

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ export const useMenu_unstable = (props: MenuProps & { safeZone?: boolean | { tim
7979
* Base hook for Menu component, produces state required to render the component.
8080
* It doesn't set any design-related slots specific to Menu such as `surfaceMotion`.
8181
*
82-
* @internal
82+
* @param props - props from this instance of Menu
8383
*/
8484
export const useMenuBase_unstable = (
8585
props: MenuBaseProps & { safeZone?: boolean | { timeout?: number } },
@@ -224,7 +224,6 @@ export const useMenuBase_unstable = (
224224
mountNode,
225225
triggerRef,
226226
menuPopoverRef,
227-
components: {},
228227
openOnContext,
229228
open,
230229
setOpen,
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
export { MenuItemLink } from './MenuItemLink';
22
export type { MenuItemLinkProps, MenuItemLinkSlots, MenuItemLinkState } from './MenuItemLink.types';
33
export { renderMenuItemLink_unstable } from './renderMenuItemLink';
4-
export { useMenuItemLink_unstable } from './useMenuItemLink';
4+
export { useMenuItemLinkBase_unstable, useMenuItemLink_unstable } from './useMenuItemLink';
55
export { menuItemLinkClassNames, useMenuItemLinkStyles_unstable } from './useMenuItemLinkStyles.styles';

packages/react-components/react-menu/library/src/components/MenuItemLink/useMenuItemLink.ts

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import type * as React from 'react';
44
import type { ExtractSlotProps, Slot } from '@fluentui/react-utilities';
55
import { getIntrinsicElementProps, slot } from '@fluentui/react-utilities';
66
import type { MenuItemLinkProps, MenuItemLinkState } from './MenuItemLink.types';
7-
import { useMenuItem_unstable } from '../MenuItem/useMenuItem';
7+
import { useMenuItemBase_unstable, useMenuItem_unstable } from '../MenuItem/useMenuItem';
88
import type { MenuItemProps } from '../MenuItem/MenuItem.types';
99

1010
/**
@@ -43,3 +43,34 @@ export const useMenuItemLink_unstable = (
4343
),
4444
};
4545
};
46+
47+
/**
48+
* Base hook for MenuItemLink, mirrors `useMenuItemLink_unstable` but composes with
49+
* `useMenuItemBase_unstable`.
50+
*
51+
* @param props - props from this instance of MenuItemLink
52+
* @param ref - reference to root HTMLElement of MenuItemLink
53+
*/
54+
export const useMenuItemLinkBase_unstable = (
55+
props: MenuItemLinkProps,
56+
ref: React.Ref<HTMLAnchorElement>,
57+
): MenuItemLinkState => {
58+
const baseState = useMenuItemBase_unstable(props as MenuItemProps, null);
59+
const _props = { ...props, ...(baseState.root as ExtractSlotProps<Slot<'a'>>), ref, tabIndex: props.tabIndex };
60+
61+
return {
62+
...baseState,
63+
components: {
64+
// eslint-disable-next-line @typescript-eslint/no-deprecated
65+
...baseState.components,
66+
root: 'a',
67+
},
68+
root: slot.always(
69+
getIntrinsicElementProps('a', {
70+
role: 'menuitem',
71+
..._props,
72+
}),
73+
{ elementType: 'a' },
74+
),
75+
};
76+
};

packages/react-components/react-menu/library/src/components/MenuList/MenuList.types.ts

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -72,14 +72,15 @@ export type MenuListState = ComponentState<MenuListSlots> &
7272
};
7373

7474
/**
75-
* MenuListBase Props - omits design-related props (`hasIcons`, `hasCheckmarks`).
75+
* MenuListBase Props - has the same shape as `MenuListProps`.
7676
*/
77-
export type MenuListBaseProps = Omit<MenuListProps, 'hasIcons' | 'hasCheckmarks'>;
77+
export type MenuListBaseProps = MenuListProps;
7878

7979
/**
80-
* MenuListBase State - omits design-related state (`hasIcons`, `hasCheckmarks`).
80+
* MenuListBase State - has the same shape as `MenuListState`; the headless hook simply skips the
81+
* Tabster-driven attributes
8182
*/
82-
export type MenuListBaseState = Omit<MenuListState, 'hasIcons' | 'hasCheckmarks'>;
83+
export type MenuListBaseState = MenuListState;
8384

8485
export type MenuListContextValues = {
8586
menuList: MenuListContextValue;

packages/react-components/react-menu/library/src/components/MenuList/useMenuList.ts

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -104,13 +104,10 @@ export const useMenuList_unstable = (props: MenuListProps, ref: React.Ref<HTMLEl
104104
* Base hook for MenuList component, produces state required to render the component.
105105
*
106106
* Tabster-free: this hook does not import from `@fluentui/react-tabster` and does
107-
* not couple consumers to Tabster's runtime. It drops the design-related slot
108-
* alignment hints (`hasIcons`, `hasCheckmarks`), the arrow-key navigation
109-
* data-attributes, the `TabsterMoveFocusEvent` listener that coordinates Tab
110-
* key handling with `useMenuPopover_unstable`, and uses a native DOM walker
111-
* for `setFocusByFirstCharacter`.
107+
* not couple consumers to Tabster's runtime.
112108
*
113-
* @internal
109+
* @param props - props from this instance of MenuList
110+
* @param ref - reference to root HTMLElement of MenuList
114111
*/
115112
export const useMenuListBase_unstable = (props: MenuListBaseProps, ref: React.Ref<HTMLElement>): MenuListBaseState => {
116113
const triggerId = useMenuContext_unstable(context => context.triggerId);
@@ -176,6 +173,8 @@ export const useMenuListBase_unstable = (props: MenuListBaseProps, ref: React.Re
176173
{ elementType: 'div' },
177174
),
178175
checkedValues,
176+
hasIcons: props.hasIcons ?? false,
177+
hasCheckmarks: props.hasCheckmarks ?? false,
179178
hasMenuContext,
180179
setFocusByFirstCharacter,
181180
selectRadio,

0 commit comments

Comments
 (0)