Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
Copy link
Copy Markdown

@github-actions github-actions Bot May 4, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🕵🏾‍♀️ visual changes to review in the Visual Change Report

vr-tests-react-components/Avatar Converged 2 screenshots
Image Name Diff(in Pixels) Image Type
vr-tests-react-components/Avatar Converged.badgeMask - RTL.normal.chromium.png 6 Changed
vr-tests-react-components/Avatar Converged.badgeMask.normal.chromium.png 5 Changed
vr-tests-react-components/Charts-DonutChart 1 screenshots
Image Name Diff(in Pixels) Image Type
vr-tests-react-components/Charts-DonutChart.Dynamic.default.chromium.png 5581 Changed
vr-tests-react-components/Positioning 2 screenshots
Image Name Diff(in Pixels) Image Type
vr-tests-react-components/Positioning.Positioning end.updated 2 times.chromium.png 70 Changed
vr-tests-react-components/Positioning.Positioning end.chromium.png 14 Changed
vr-tests-react-components/ProgressBar converged 3 screenshots
Image Name Diff(in Pixels) Image Type
vr-tests-react-components/ProgressBar converged.Indeterminate + thickness - Dark Mode.default.chromium.png 69 Changed
vr-tests-react-components/ProgressBar converged.Indeterminate + thickness - High Contrast.default.chromium.png 135 Changed
vr-tests-react-components/ProgressBar converged.Indeterminate + thickness.default.chromium.png 103 Changed
vr-tests-react-components/TagPicker 1 screenshots
Image Name Diff(in Pixels) Image Type
vr-tests-react-components/TagPicker.disabled - Dark Mode.chromium.png 658 Changed

There were 1 duplicate changes discarded. Check the build logs for more information.

"type": "minor",
"comment": "feat: expose react-menu base hooks",
"packageName": "@fluentui/react-menu",
"email": "vgenaev@gmail.com",
"dependentChangeType": "patch"
}
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,12 @@ export const Menu: React_2.FC<MenuProps>;
// @public
export const MENU_ENTER_EVENT = "fuimenuenter";

// @public (undocumented)
export type MenuBaseProps = Omit<MenuProps, 'surfaceMotion'>;

// @public (undocumented)
export type MenuBaseState = Omit<MenuState, 'surfaceMotion' | 'components'>;

// @public (undocumented)
export type MenuCheckedValueChangeData = {
checkedItems: string[];
Expand Down Expand Up @@ -167,6 +173,12 @@ export type MenuItemProps = Omit<ComponentProps<Partial<MenuItemSlots>>, 'conten
// @public
export const MenuItemRadio: ForwardRefComponent<MenuItemRadioProps>;

// @public
export type MenuItemRadioBaseProps = MenuItemRadioProps;

// @public
export type MenuItemRadioBaseState = MenuItemRadioState;

// @public (undocumented)
export const menuItemRadioClassNames: SlotClassNames<Omit<MenuItemSlots, 'submenuIndicator'>>;

Expand Down Expand Up @@ -482,6 +494,13 @@ export const useMenu_unstable: (props: MenuProps & {
};
}) => MenuState;

// @public
export const useMenuBase_unstable: (props: MenuBaseProps & {
safeZone?: boolean | {
timeout?: number;
};
}) => MenuBaseState;

// @public (undocumented)
export const useMenuContext_unstable: <T>(selector: ContextSelector<MenuContextValue, T>) => T;

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

// @public
export const useMenuItemBase_unstable: (props: MenuItemProps, ref: React_2.Ref<ARIAButtonElement<"div">>) => MenuItemState;

// @public
export const useMenuItemCheckbox_unstable: (props: MenuItemCheckboxProps, ref: React_2.Ref<ARIAButtonElement<"div">>) => MenuItemCheckboxState;

// @public
export const useMenuItemCheckboxBase_unstable: (props: MenuItemCheckboxProps, ref: React_2.Ref<ARIAButtonElement<"div">>) => MenuItemCheckboxState;

// @public (undocumented)
export const useMenuItemCheckboxStyles_unstable: (state: MenuItemCheckboxState) => MenuItemCheckboxState;

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

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

// @public
export const useMenuItemLinkStyles_unstable: (state: MenuItemLinkState) => MenuItemLinkState;

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

// @public
export const useMenuItemRadioBase_unstable: (props: MenuItemRadioBaseProps, ref: React_2.Ref<ARIAButtonElement<"div">>) => MenuItemRadioBaseState;

// @public (undocumented)
export const useMenuItemRadioStyles_unstable: (state: MenuItemRadioState) => void;

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

// @public
export const useMenuItemSwitchBase_unstable: (props: MenuItemSwitchProps, ref: React_2.Ref<HTMLDivElement>) => MenuItemSwitchState;

// @public
export const useMenuItemSwitchStyles_unstable: (state: MenuItemSwitchState) => MenuItemSwitchState;

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

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

// @public (undocumented)
export const useMenuListContext_unstable: <T>(selector: ContextSelector<MenuListContextValue, T>) => T;

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

// @public
export const useMenuPopoverBase_unstable: (props: MenuPopoverProps, ref: React_2.Ref<HTMLElement>) => MenuPopoverState;

// @public
export const useMenuPopoverStyles_unstable: (state: MenuPopoverState) => MenuPopoverState;

Expand All @@ -569,6 +609,14 @@ export const useMenuSplitGroupStyles_unstable: (state: MenuSplitGroupState) => M
// @public
export const useMenuTrigger_unstable: (props: MenuTriggerProps) => MenuTriggerState;

// @public
export const useMenuTriggerBase_unstable: (props: MenuTriggerProps, options?: UseMenuTriggerBaseOptions) => MenuTriggerState;

// @public
export type UseMenuTriggerBaseOptions = {
focusFirst?: () => void;
};

// @public (undocumented)
export const useMenuTriggerContext_unstable: () => boolean;

Expand Down
10 changes: 9 additions & 1 deletion packages/react-components/react-menu/library/src/Menu.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
export type {
MenuBaseProps,
MenuBaseState,
MenuContextValues,
MenuOpenChangeData,
MenuOpenEvent,
Expand All @@ -8,4 +10,10 @@ export type {
MenuSlots,
MenuState,
} from './components/Menu/index';
export { Menu, renderMenu_unstable, useMenuContextValues_unstable, useMenu_unstable } from './components/Menu/index';
export {
Menu,
renderMenu_unstable,
useMenuContextValues_unstable,
useMenuBase_unstable,
useMenu_unstable,
} from './components/Menu/index';
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ export {
MenuItemLink,
menuItemLinkClassNames,
renderMenuItemLink_unstable,
useMenuItemLinkBase_unstable,
useMenuItemLinkStyles_unstable,
useMenuItemLink_unstable,
} from './components/MenuItemLink/index';
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
export type { MenuItemRadioProps, MenuItemRadioState } from './components/MenuItemRadio/index';
export type {
MenuItemRadioBaseProps,
MenuItemRadioBaseState,
MenuItemRadioProps,
MenuItemRadioState,
} from './components/MenuItemRadio/index';
export {
MenuItemRadio,
menuItemRadioClassNames,
renderMenuItemRadio_unstable,
useMenuItemRadioBase_unstable,
useMenuItemRadioStyles_unstable,
useMenuItemRadio_unstable,
useMenuItemRadioBase_unstable,
} from './components/MenuItemRadio/index';
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ export {
MenuList,
menuListClassNames,
renderMenuList_unstable,
useMenuListBase_unstable,
useMenuListContextValues_unstable,
useMenuListStyles_unstable,
useMenuList_unstable,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ export {
MenuPopover,
menuPopoverClassNames,
renderMenuPopover_unstable,
useMenuPopoverBase_unstable,
useMenuPopoverStyles_unstable,
useMenuPopover_unstable,
} from './components/MenuPopover/index';
14 changes: 12 additions & 2 deletions packages/react-components/react-menu/library/src/MenuTrigger.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,12 @@
export type { MenuTriggerChildProps, MenuTriggerProps, MenuTriggerState } from './components/MenuTrigger/index';
export { MenuTrigger, renderMenuTrigger_unstable, useMenuTrigger_unstable } from './components/MenuTrigger/index';
export type {
MenuTriggerChildProps,
MenuTriggerProps,
MenuTriggerState,
UseMenuTriggerBaseOptions,
} from './components/MenuTrigger/index';
export {
MenuTrigger,
renderMenuTrigger_unstable,
useMenuTrigger_unstable,
useMenuTriggerBase_unstable,
} from './components/MenuTrigger/index';
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,10 @@ export type MenuState = ComponentState<InternalMenuSlots> &
safeZone?: React.ReactElement | null;
};

export type MenuBaseProps = Omit<MenuProps, 'surfaceMotion'>;

export type MenuBaseState = Omit<MenuState, 'surfaceMotion' | 'components'>;

export type MenuContextValues = {
menu: MenuContextValue;
};
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
export { Menu } from './Menu';
export type {
MenuBaseProps,
MenuBaseState,
MenuContextValues,
MenuOpenChangeData,
MenuOpenEvent,
Expand All @@ -10,5 +12,5 @@ export type {
MenuState,
} from './Menu.types';
export { renderMenu_unstable } from './renderMenu';
export { useMenu_unstable } from './useMenu';
export { useMenu_unstable, useMenuBase_unstable } from './useMenu';
export { useMenuContextValues_unstable } from './useMenuContextValues';
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,14 @@ import { useFocusFinders } from '@fluentui/react-tabster';
import { useMenuContext_unstable } from '../../contexts/menuContext';
import { MENU_SAFEZONE_TIMEOUT_EVENT, MENU_ENTER_EVENT, useOnMenuMouseEnter, useIsSubmenu } from '../../utils';
import { menuItemClassNames } from '../MenuItem/useMenuItemStyles.styles';
import type { MenuOpenChangeData, MenuOpenEvent, MenuProps, MenuState } from './Menu.types';
import type {
MenuBaseProps,
MenuBaseState,
MenuOpenChangeData,
MenuOpenEvent,
MenuProps,
MenuState,
} from './Menu.types';
import { MenuSurfaceMotion } from './MenuSurfaceMotion';

// If it's not possible to position the submenu in smaller viewports, try
Expand All @@ -50,6 +57,34 @@ const submenuFallbackPositions: PositioningShorthandValue[] = [
* @param props - props from this instance of Menu
*/
export const useMenu_unstable = (props: MenuProps & { safeZone?: boolean | { timeout?: number } }): MenuState => {
const { surfaceMotion, ...baseProps } = props;
const baseState = useMenuBase_unstable(baseProps);

return {
...baseState,
components: {
surfaceMotion: MenuSurfaceMotion,
},
surfaceMotion: presenceMotionSlot(surfaceMotion, {
elementType: MenuSurfaceMotion,
defaultProps: {
visible: baseState.open,
appear: true,
unmountOnExit: true,
},
}),
};
};

/**
* Base hook for Menu component, produces state required to render the component.
* It doesn't set any design-related slots specific to Menu such as `surfaceMotion`.
*
* @param props - props from this instance of Menu
*/
export const useMenuBase_unstable = (
props: MenuBaseProps & { safeZone?: boolean | { timeout?: number } },
): MenuBaseState => {
const isSubmenu = useIsSubmenu();
const {
hoverDelay = 500,
Expand Down Expand Up @@ -190,24 +225,13 @@ export const useMenu_unstable = (props: MenuProps & { safeZone?: boolean | { tim
mountNode,
triggerRef,
menuPopoverRef,
components: {
surfaceMotion: MenuSurfaceMotion,
},
openOnContext,
open,
setOpen,
checkedValues,
onCheckedValueChange,
persistOnItemClick,
safeZone: safeZoneHandle.elementToRender,
surfaceMotion: presenceMotionSlot(props.surfaceMotion, {
elementType: MenuSurfaceMotion,
defaultProps: {
visible: open,
appear: true,
unmountOnExit: true,
},
}),
};
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,6 @@ export const useMenuItem_unstable = (props: MenuItemProps, ref: React.Ref<ARIABu
/**
* Base hook for MenuItem component, produces state required to render the component.
* It doesn't set any design-related props specific to MenuItem such as submenu indicator icon.
*
* @internal
*/
export const useMenuItemBase_unstable = (
props: MenuItemProps,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,6 @@ export const useMenuItemCheckbox_unstable = (

/**
* Base hook for MenuItemCheckbox component, produces state required to render the component
*
* @internal
*/
export const useMenuItemCheckboxBase_unstable = (
props: MenuItemCheckboxProps,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
export { MenuItemLink } from './MenuItemLink';
export type { MenuItemLinkProps, MenuItemLinkSlots, MenuItemLinkState } from './MenuItemLink.types';
export { renderMenuItemLink_unstable } from './renderMenuItemLink';
export { useMenuItemLink_unstable } from './useMenuItemLink';
export { useMenuItemLinkBase_unstable, useMenuItemLink_unstable } from './useMenuItemLink';
export { menuItemLinkClassNames, useMenuItemLinkStyles_unstable } from './useMenuItemLinkStyles.styles';
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import type * as React from 'react';
import type { ExtractSlotProps, Slot } from '@fluentui/react-utilities';
import { getIntrinsicElementProps, slot } from '@fluentui/react-utilities';
import type { MenuItemLinkProps, MenuItemLinkState } from './MenuItemLink.types';
import { useMenuItem_unstable } from '../MenuItem/useMenuItem';
import { useMenuItemBase_unstable, useMenuItem_unstable } from '../MenuItem/useMenuItem';
import type { MenuItemProps } from '../MenuItem/MenuItem.types';

/**
Expand Down Expand Up @@ -43,3 +43,34 @@ export const useMenuItemLink_unstable = (
),
};
};

/**
* Base hook for MenuItemLink, mirrors `useMenuItemLink_unstable` but composes with
* `useMenuItemBase_unstable`.
*
* @param props - props from this instance of MenuItemLink
* @param ref - reference to root HTMLElement of MenuItemLink
*/
export const useMenuItemLinkBase_unstable = (
props: MenuItemLinkProps,
ref: React.Ref<HTMLAnchorElement>,
): MenuItemLinkState => {
const baseState = useMenuItemBase_unstable(props as MenuItemProps, null);
const _props = { ...props, ...(baseState.root as ExtractSlotProps<Slot<'a'>>), ref, tabIndex: props.tabIndex };

return {
...baseState,
components: {
// eslint-disable-next-line @typescript-eslint/no-deprecated
...baseState.components,
root: 'a',
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

will be still possible?

},
root: slot.always(
getIntrinsicElementProps('a', {
role: 'menuitem',
..._props,
}),
{ elementType: 'a' },
),
};
};
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,6 @@ export const useMenuItemRadio_unstable = (
/**
* Base hook for MenuItemRadio component, produces state required to render the component.
* It doesn't set any design-related props specific to MenuItemRadio.
*
* @internal
*/
export const useMenuItemRadioBase_unstable = (
props: MenuItemRadioBaseProps,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@ export const useMenuItemSwitch_unstable = (
* Base hook for MenuItemSwitch component, produces state required to render the component.
* It doesn't set any design-related props specific to MenuItemSwitch.
*
* @internal
* @param props - props from this instance of MenuItemSwitch
* @param ref - reference to root HTMLDivElement of MenuItemSwitch
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,6 @@ export type {
UninitializedMenuListState,
} from './MenuList.types';
export { renderMenuList_unstable } from './renderMenuList';
export { useMenuList_unstable } from './useMenuList';
export { useMenuList_unstable, useMenuListBase_unstable } from './useMenuList';
export { menuListClassNames, useMenuListStyles_unstable } from './useMenuListStyles.styles';
export { useMenuListContextValues_unstable } from './useMenuListContextValues';
Loading
Loading