better-mui-menu 1.0.8 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -67,16 +67,13 @@ var transitionConfig = {
67
67
  type: import_Fade.default,
68
68
  timeout: { enter: CLOSE_DELAY + 50, exit: CLOSE_DELAY + 50 }
69
69
  };
70
- var MenuItemContent = (0, import_material.styled)(import_material.Stack)(({ theme }) => ({
70
+ var DEFAULT_ELEVATION = 8;
71
+ var MenuItemContent = (0, import_material.styled)(import_material.Stack)({
71
72
  flexDirection: "row",
72
73
  alignItems: "center",
73
- gap: theme.spacing(1),
74
- fontSize: theme.typography.body1.fontSize,
75
- "& .MuiSvgIcon-root": {
76
- fontSize: theme.typography.body2.fontSize
77
- },
74
+ gap: "8px",
78
75
  padding: 0
79
- }));
76
+ });
80
77
 
81
78
  // src/Menu/NestedMenuItem.tsx
82
79
  var import_jsx_runtime2 = require("react/jsx-runtime");
@@ -90,6 +87,7 @@ var NestedMenuItem = (props) => {
90
87
  children,
91
88
  items,
92
89
  endIcon: _,
90
+ menuProps,
93
91
  ...menuItemProps
94
92
  } = props;
95
93
  const [subMenuAnchorEl, setSubMenuAnchorEl] = (0, import_react.useState)(null);
@@ -127,7 +125,7 @@ var NestedMenuItem = (props) => {
127
125
  const clonedOnClick = (event) => {
128
126
  childOnClick?.(event);
129
127
  handleClose();
130
- parentMenuClose();
128
+ parentMenuClose?.(event, "itemClick", menuItemId);
131
129
  };
132
130
  return (0, import_react.cloneElement)(child, { onClick: clonedOnClick });
133
131
  }
@@ -160,7 +158,8 @@ var NestedMenuItem = (props) => {
160
158
  startIcon: NestedMenuItemStartIcon,
161
159
  endIcon: NestedMenuItemEndIcon,
162
160
  parentMenuClose,
163
- items: entryItems
161
+ items: entryItems,
162
+ menuProps
164
163
  },
165
164
  entryKey
166
165
  );
@@ -168,7 +167,7 @@ var NestedMenuItem = (props) => {
168
167
  const handleItemClick = (event) => {
169
168
  onClick?.(event);
170
169
  handleClose();
171
- parentMenuClose();
170
+ parentMenuClose?.(event, "itemClick", entryId);
172
171
  };
173
172
  return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_MenuItem.default, { onClick: handleItemClick, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(MenuItemContent, { children: [
174
173
  NestedMenuItemStartIcon ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(NestedMenuItemStartIcon, {}) : null,
@@ -236,43 +235,34 @@ var NestedMenuItem = (props) => {
236
235
  if (isNodeInstance(e.relatedTarget) && menuItemRef.current?.contains(e.relatedTarget)) return;
237
236
  scheduleClose();
238
237
  },
239
- children: ({ TransitionProps }) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_Fade2.default, { ...TransitionProps, timeout: transitionConfig.timeout, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
240
- import_material2.Paper,
238
+ children: ({ TransitionProps }) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_Fade2.default, { ...TransitionProps, timeout: transitionConfig.timeout, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_material2.Paper, { elevation: menuProps.elevation, ...menuProps?.slotProps?.paper || {}, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
239
+ import_material2.MenuList,
241
240
  {
242
- elevation: 2,
243
- sx: {
244
- borderRadius: 1,
245
- bgcolor: "background.default"
246
- },
247
- children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
248
- import_material2.MenuList,
249
- {
250
- autoFocusItem: true,
251
- id: subMenuId,
252
- "aria-labelledby": menuItemId,
253
- role: "menu",
254
- onKeyDown: (e) => {
255
- if (e.key === "ArrowLeft") {
256
- const { nativeEvent } = e;
257
- if (nativeEvent.__nestedMenuArrowLeftHandled) {
258
- return;
259
- }
260
- if (!subMenuRef.current?.contains(e.target)) {
261
- return;
262
- }
263
- nativeEvent.__nestedMenuArrowLeftHandled = true;
264
- e.preventDefault();
265
- e.stopPropagation();
266
- nativeEvent.stopImmediatePropagation();
267
- handleClose();
268
- menuItemRef.current?.focus();
269
- }
270
- },
271
- children: renderedSubMenuItems
241
+ id: subMenuId,
242
+ "aria-labelledby": menuItemId,
243
+ role: "menu",
244
+ ...menuProps?.slotProps?.list || {},
245
+ autoFocusItem: true,
246
+ onKeyDown: (e) => {
247
+ if (e.key === "ArrowLeft") {
248
+ const { nativeEvent } = e;
249
+ if (nativeEvent.__nestedMenuArrowLeftHandled) {
250
+ return;
251
+ }
252
+ if (!subMenuRef.current?.contains(e.target)) {
253
+ return;
254
+ }
255
+ nativeEvent.__nestedMenuArrowLeftHandled = true;
256
+ e.preventDefault();
257
+ e.stopPropagation();
258
+ nativeEvent.stopImmediatePropagation();
259
+ handleClose();
260
+ menuItemRef.current?.focus();
272
261
  }
273
- )
262
+ },
263
+ children: renderedSubMenuItems
274
264
  }
275
- ) })
265
+ ) }) })
276
266
  }
277
267
  )
278
268
  ] });
@@ -280,7 +270,8 @@ var NestedMenuItem = (props) => {
280
270
 
281
271
  // src/Menu/index.tsx
282
272
  var import_jsx_runtime3 = require("react/jsx-runtime");
283
- function Menu({ anchorEl, open, onClose, items }) {
273
+ function Menu({ items, elevation = DEFAULT_ELEVATION, ...rest }) {
274
+ const menuProps = { elevation, ...rest };
284
275
  const generatedMenuId = (0, import_react2.useId)();
285
276
  const renderedMenuEntries = items.map((item, index) => {
286
277
  if (item.type === "divider") {
@@ -307,15 +298,16 @@ function Menu({ anchorEl, open, onClose, items }) {
307
298
  label: displayLabel,
308
299
  startIcon: StartIconComponent,
309
300
  endIcon: EndIconComponent,
310
- parentMenuClose: onClose,
311
- items: nestedItems
301
+ parentMenuClose: menuProps.onClose,
302
+ items: nestedItems,
303
+ menuProps
312
304
  },
313
305
  itemKey
314
306
  );
315
307
  }
316
308
  const handleItemClick = (event) => {
317
309
  onClick?.(event);
318
- onClose();
310
+ menuProps.onClose?.(event, "itemClick", entryId);
319
311
  };
320
312
  return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_MenuItem2.default, { onClick: handleItemClick, ...menuItemProps, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(MenuItemContent, { children: [
321
313
  StartIconComponent ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(StartIconComponent, {}) : null,
@@ -327,19 +319,9 @@ function Menu({ anchorEl, open, onClose, items }) {
327
319
  import_Menu.default,
328
320
  {
329
321
  "data-testid": "root-menu",
330
- anchorEl,
331
- open,
332
- onClose,
333
- onKeyDown: (e) => {
334
- if (e.key === "Escape" && open) onClose();
335
- },
336
- transitionDuration: transitionConfig.timeout,
337
- slots: { transition: transitionConfig.type },
338
- slotProps: {
339
- list: {
340
- "aria-labelledby": "icon-menu-button"
341
- }
342
- },
322
+ ...menuProps,
323
+ transitionDuration: menuProps.transitionDuration || transitionConfig.timeout,
324
+ slots: { transition: transitionConfig.type, ...menuProps.slots },
343
325
  children: renderedMenuEntries
344
326
  }
345
327
  );
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/Menu/index.tsx","../src/Menu/NestedMenuItem.tsx","../../../node_modules/@mui/icons-material/esm/utils/createSvgIcon.js","../../../node_modules/@mui/icons-material/esm/ArrowRight.js","../src/Menu/common.ts"],"sourcesContent":["import { Menu } from './Menu'\n\nexport type { MenuItem } from './Menu/types'\nexport default Menu\n","import MuiMenu from '@mui/material/Menu';\nimport Divider from '@mui/material/Divider';\nimport MuiMenuItem from '@mui/material/MenuItem';\nimport React, { useId } from 'react';\nimport { Typography } from '@mui/material';\nimport { NestedMenuItem } from './NestedMenuItem';\nimport type { MenuItem } from './types';\nimport { MenuItemContent, transitionConfig } from './common';\n\ntype Props = {\n anchorEl: null | HTMLElement;\n open: boolean;\n onClose: () => void;\n items: MenuItem[];\n};\n\nexport function Menu({ anchorEl, open, onClose, items }: Props) {\n const generatedMenuId = useId();\n\n const renderedMenuEntries = items.map((item, index) => {\n if (item.type === 'divider') {\n return <Divider key={`divider-${index}`} />;\n }\n\n const {\n type: _,\n items: nestedItems,\n startIcon: StartIconComponent,\n endIcon: EndIconComponent,\n label,\n onClick,\n id,\n ...menuItemProps\n } = item;\n const entryId = id ?? `${generatedMenuId}-entry-${index}`;\n const itemKey = `menu-item-id:${entryId}`;\n const displayLabel = label ?? entryId;\n\n if (nestedItems && nestedItems.length > 0) {\n return (\n <NestedMenuItem\n key={itemKey}\n id={entryId}\n label={displayLabel}\n startIcon={StartIconComponent}\n endIcon={EndIconComponent}\n parentMenuClose={onClose}\n items={nestedItems}\n />\n );\n }\n\n const handleItemClick = (event: React.MouseEvent<HTMLLIElement>) => {\n onClick?.(event);\n onClose();\n };\n\n return (\n <MuiMenuItem key={itemKey} onClick={handleItemClick} {...menuItemProps}>\n <MenuItemContent>\n {StartIconComponent ? <StartIconComponent /> : null}\n <Typography sx={{ flex: 1 }}>{displayLabel}</Typography>\n {EndIconComponent ? <EndIconComponent /> : null}\n </MenuItemContent>\n </MuiMenuItem>\n );\n });\n\n return (\n <MuiMenu\n data-testid='root-menu'\n anchorEl={anchorEl}\n open={open}\n onClose={onClose}\n onKeyDown={e => {\n if (e.key === 'Escape' && open) onClose();\n }}\n transitionDuration={transitionConfig.timeout}\n slots={{ transition: transitionConfig.type }}\n slotProps={{\n list: {\n 'aria-labelledby': 'icon-menu-button',\n },\n }}\n >\n {renderedMenuEntries}\n </MuiMenu>\n );\n}\n","import type { FC, ReactNode, MouseEvent, KeyboardEvent } from 'react';\nimport { Children, cloneElement, isValidElement, useCallback, useId, useRef, useState } from 'react';\nimport Fade from '@mui/material/Fade';\nimport type { MenuItemProps } from '@mui/material/MenuItem';\nimport MuiMenuItem from '@mui/material/MenuItem';\nimport Divider from '@mui/material/Divider';\nimport ArrowRightIcon from '@mui/icons-material/ArrowRight';\nimport type { SvgIconComponent } from '@mui/icons-material';\nimport { MenuList, Paper, Popper, Typography } from '@mui/material';\nimport type { MenuItem } from './types';\nimport { CLOSE_DELAY, MenuItemContent, transitionConfig } from './common';\n\ntype NestedMenuItemProps = MenuItemProps & {\n label: ReactNode;\n startIcon?: SvgIconComponent;\n endIcon?: SvgIconComponent;\n parentMenuClose: () => void;\n children?: ReactNode;\n items?: MenuItem[];\n};\n\nconst isNodeInstance = (target: EventTarget | null): target is Node => target instanceof Node;\n\nexport const NestedMenuItem: FC<NestedMenuItemProps> = props => {\n const {\n id: providedId,\n label,\n startIcon: StartIconComponent,\n parentMenuClose,\n children,\n items,\n endIcon: _,\n ...menuItemProps\n } = props;\n const [subMenuAnchorEl, setSubMenuAnchorEl] = useState<null | HTMLElement>(null);\n const open = Boolean(subMenuAnchorEl);\n const menuItemRef = useRef<HTMLLIElement>(null);\n const subMenuRef = useRef<HTMLDivElement>(null);\n const generatedId = useId();\n const menuItemId = providedId ?? `nested-menu-trigger-${generatedId}`;\n const subMenuId = `${menuItemId}-submenu`;\n\n const closeTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n\n const clearCloseTimer = useCallback(() => {\n if (closeTimerRef.current) {\n clearTimeout(closeTimerRef.current);\n closeTimerRef.current = null;\n }\n }, []);\n\n const handleClose = useCallback(() => {\n clearCloseTimer();\n setSubMenuAnchorEl(null);\n }, [clearCloseTimer]);\n\n const scheduleClose = useCallback(() => {\n clearCloseTimer();\n closeTimerRef.current = setTimeout(() => {\n handleClose();\n }, CLOSE_DELAY);\n }, [clearCloseTimer, handleClose]);\n\n const handleOpen = (event: MouseEvent<HTMLLIElement> | KeyboardEvent<HTMLLIElement>) => {\n clearCloseTimer();\n setSubMenuAnchorEl(event.currentTarget);\n };\n\n\n // eslint-disable-next-line react-hooks/refs\n const renderChildren = Children.map(children, child => {\n if (!isValidElement(child)) return child;\n\n // Ensure we only process MUI MenuItem children\n if (child.type === MuiMenuItem) {\n const childOnClick = (child.props as MenuItemProps).onClick;\n // Merge any user-defined click logic with the submenu closing behavior.\n const clonedOnClick = (event: MouseEvent<HTMLLIElement>) => {\n childOnClick?.(event);\n handleClose(); // Close the submenu\n parentMenuClose();\n };\n return cloneElement(child, { onClick: clonedOnClick } as Partial<MenuItemProps>);\n }\n return child;\n });\n\n const renderItemsFromData = () => {\n if (!items || items.length === 0) return null;\n\n return items.map((item, index) => {\n if (item.type === 'divider') {\n\n return <Divider key={`divider-${index}`} />;\n }\n\n const {\n type: __,\n items: entryItems,\n startIcon: NestedMenuItemStartIcon,\n endIcon: NestedMenuItemEndIcon,\n label: entryLabel,\n onClick,\n id,\n } = item;\n const entryId = id ?? `${menuItemId}-entry-${index}`;\n const entryKey = `nested-entry-${entryId}`;\n const entryLabelValue = entryLabel ?? entryId;\n\n if (entryItems && entryItems.length > 0) {\n return (\n <NestedMenuItem\n key={entryKey}\n id={entryId}\n label={entryLabelValue}\n startIcon={NestedMenuItemStartIcon}\n endIcon={NestedMenuItemEndIcon}\n parentMenuClose={parentMenuClose}\n items={entryItems}\n />\n );\n }\n\n const handleItemClick = (event: MouseEvent<HTMLLIElement>) => {\n onClick?.(event);\n handleClose();\n parentMenuClose();\n };\n\n return (\n <MuiMenuItem key={entryKey} onClick={handleItemClick}>\n <MenuItemContent>\n {NestedMenuItemStartIcon ? <NestedMenuItemStartIcon /> : null}\n <Typography sx={{ flex: 1 }}>{entryLabelValue}</Typography>\n {NestedMenuItemEndIcon ? <NestedMenuItemEndIcon /> : null}\n </MenuItemContent>\n </MuiMenuItem>\n );\n });\n };\n\n const renderedSubMenuItems = items && items.length > 0 ? renderItemsFromData() : renderChildren;\n\n return (\n <>\n <MuiMenuItem\n data-testid={`${menuItemId}-trigger`}\n id={menuItemId}\n ref={menuItemRef}\n onMouseEnter={handleOpen}\n onMouseLeave={e => {\n // CRITICAL FEATURE:\n // Checking whether cursor left the menu item onto the related menu. If so, do not close.\n // TODO(ege): There can be a timeout here before we execute closing to improve UX - in case user is not very precise with mouse.\n if (isNodeInstance(e.relatedTarget) && subMenuRef.current?.contains(e.relatedTarget)) return;\n // If the cursor leaves to anywhere else, close the submenu.\n scheduleClose();\n }}\n onKeyDown={e => {\n e.preventDefault();\n if (e.key === 'ArrowLeft') {\n handleClose();\n }\n if (e.key === 'ArrowRight' || e.key === 'Enter' || e.key === ' ') {\n handleOpen(e);\n }\n }}\n aria-haspopup='menu'\n aria-controls={subMenuId}\n aria-expanded={open ? 'true' : undefined}\n {...menuItemProps}\n >\n <MenuItemContent>\n {StartIconComponent ? <StartIconComponent /> : null}\n <Typography sx={{ flex: 1 }}>{label}</Typography>\n <ArrowRightIcon />\n </MenuItemContent>\n </MuiMenuItem>\n\n <Popper\n data-testid={`${menuItemId}-submenu`}\n open={open}\n ref={subMenuRef}\n anchorEl={subMenuAnchorEl}\n transition\n sx={{ zIndex: t => t.zIndex.modal + 1 }}\n placement='right-start'\n onKeyDown={e => {\n if (e.key === 'ArrowLeft') {\n e.preventDefault();\n handleClose();\n menuItemRef.current?.focus();\n }\n if (e.key === 'ArrowUp' || e.key === 'ArrowDown') {\n e.preventDefault();\n e.stopPropagation();\n }\n }}\n onMouseEnter={clearCloseTimer}\n onMouseLeave={e => {\n // CRITICAL FEATURE:\n // Checking whether cursor left the submenu onto the related trigger item. If so, do not close.\n // TODO(ege): There can be a timeout here before we execute closing to improve UX - in case user is not very precise with mouse.\n if (isNodeInstance(e.relatedTarget) && menuItemRef.current?.contains(e.relatedTarget)) return;\n // If the cursor leaves to anywhere else, close the submenu.\n scheduleClose();\n }}\n >\n {({ TransitionProps }) => (\n <Fade {...TransitionProps} timeout={transitionConfig.timeout}>\n <Paper\n elevation={2}\n sx={{\n borderRadius: 1,\n bgcolor: 'background.default',\n }}\n >\n <MenuList\n autoFocusItem\n id={subMenuId}\n aria-labelledby={menuItemId}\n role='menu'\n onKeyDown={e => {\n if (e.key === 'ArrowLeft') {\n const { nativeEvent } = e as KeyboardEvent<HTMLUListElement> & {\n nativeEvent: KeyboardEvent & {\n // our custom flag to avoid duplicate handling in nested menus\n __nestedMenuArrowLeftHandled?: boolean;\n };\n };\n if (nativeEvent.__nestedMenuArrowLeftHandled) {\n // return early if we have already handled this event in a nested menu\n // prevents duplicate logic when the browser bubbles the same keypress through multiple nodes\n return;\n }\n if (!subMenuRef.current?.contains(e.target as Node)) {\n // confirm the event’s target is still inside this submenu;\n // if the keypress originated elsewhere, we don’t continue so other menus can handle it\n return;\n }\n // Mark this event as handled to prevent parent menus from also processing it\n nativeEvent.__nestedMenuArrowLeftHandled = true;\n // preventDefault is needed so the browser doesn’t do its own “arrow left” behavior (like moving the text caret\n // or changing focus) while the menu is managing the navigation. Without this, the closed submenu or focused item\n // might jump unexpectedly even though the menu logic is running.\n e.preventDefault();\n // stopPropagation stops the event from bubbling up to parent DOM nodes that might also have onKeyDown, which could\n // otherwise fight the menu’s own logic or trigger duplicate navigation even though we guard with __nestedMenuArrowLeftHandled\n e.stopPropagation();\n // stopImmediatePropagation keeps any other keydown handlers registered on this same DOM node from running after ours.\n // This is preventing all submenus to close when pressing ArrowLeft in a, say, third level menu. With this, ArrowLeft will only\n // close the current submenu. The __nestedMenuArrowLeftHandled flag only guards against bubbling; this stopImmediatePropagation()\n // ensures no other handlers wired to the same node interfere once we decide to close and focus.\n nativeEvent.stopImmediatePropagation();\n // close the sub menu\n handleClose();\n // move focus back to the parent MenuItem, letting the user continue navigation up the menu hierarchy\n menuItemRef.current?.focus();\n }\n }}\n >\n {renderedSubMenuItems}\n </MenuList>\n </Paper>\n </Fade>\n )}\n </Popper>\n </>\n );\n};\n","'use client';\n\nexport { createSvgIcon as default } from '@mui/material/utils';","\"use client\";\n\nimport createSvgIcon from \"./utils/createSvgIcon.js\";\nimport { jsx as _jsx } from \"react/jsx-runtime\";\nexport default createSvgIcon(/*#__PURE__*/_jsx(\"path\", {\n d: \"m10 17 5-5-5-5z\"\n}), 'ArrowRight');","import { Stack, styled } from '@mui/material';\nimport Fade from '@mui/material/Fade';\n\nexport const CLOSE_DELAY = 50;\nexport const transitionConfig = {\n type: Fade,\n timeout: { enter: CLOSE_DELAY + 50, exit: CLOSE_DELAY + 50 },\n};\n\nexport const MenuItemContent = styled(Stack)(({ theme }) => ({\n flexDirection: 'row',\n alignItems: 'center',\n gap: theme.spacing(1),\n fontSize: theme.typography.body1.fontSize,\n '& .MuiSvgIcon-root': {\n fontSize: theme.typography.body2.fontSize,\n },\n padding: 0,\n}));\n"],"mappings":"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","names":["import_Divider","import_MenuItem","import_react","import_material","import_Fade","_jsx","import_material","Fade","import_jsx_runtime","MuiMenuItem","Divider","Fade","import_jsx_runtime","Divider","MuiMenuItem","MuiMenu"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/Menu/index.tsx","../src/Menu/NestedMenuItem.tsx","../../../node_modules/@mui/icons-material/esm/utils/createSvgIcon.js","../../../node_modules/@mui/icons-material/esm/ArrowRight.js","../src/Menu/common.ts"],"sourcesContent":["import { Menu } from './Menu'\n\nexport type { MenuItem } from './Menu/types'\nexport default Menu\n","import type { MenuProps } from '@mui/material/Menu';\nimport MuiMenu from '@mui/material/Menu';\nimport Divider from '@mui/material/Divider';\nimport MuiMenuItem from '@mui/material/MenuItem';\nimport React, { useId } from 'react';\nimport { Typography } from '@mui/material';\nimport { NestedMenuItem } from './NestedMenuItem';\nimport type { MenuItem } from './types';\nimport { DEFAULT_ELEVATION, MenuItemContent, transitionConfig } from './common';\n\nexport type Props = {\n items: MenuItem[];\n onClose?: (event: React.MouseEvent | React.KeyboardEvent, reason: 'itemClick' | 'escapeKeyDown' | 'backdropClick', menuItemId?: string\n ) => void;\n} & Omit<MenuProps, 'onClose'>;\n\nexport function Menu({ items, elevation = DEFAULT_ELEVATION, ...rest }: Props) {\n const menuProps: Omit<Props, 'items'> = { elevation, ...rest }; // setting the elevation for all nested menus here\n const generatedMenuId = useId();\n\n const renderedMenuEntries = items.map((item, index) => {\n if (item.type === 'divider') {\n return <Divider key={`divider-${index}`} />;\n }\n\n const {\n type: _,\n items: nestedItems,\n startIcon: StartIconComponent,\n endIcon: EndIconComponent,\n label,\n onClick,\n id,\n ...menuItemProps\n } = item;\n const entryId = id ?? `${generatedMenuId}-entry-${index}`;\n const itemKey = `menu-item-id:${entryId}`;\n const displayLabel = label ?? entryId;\n\n if (nestedItems && nestedItems.length > 0) {\n return (\n <NestedMenuItem\n key={itemKey}\n id={entryId}\n label={displayLabel}\n startIcon={StartIconComponent}\n endIcon={EndIconComponent}\n parentMenuClose={menuProps.onClose}\n items={nestedItems}\n menuProps={menuProps}\n />\n );\n }\n\n const handleItemClick = (event: React.MouseEvent<HTMLLIElement>) => {\n onClick?.(event);\n menuProps.onClose?.(event, \"itemClick\", entryId);\n };\n\n return (\n <MuiMenuItem key={itemKey} onClick={handleItemClick} {...menuItemProps}>\n <MenuItemContent>\n {StartIconComponent ? <StartIconComponent /> : null}\n <Typography sx={{ flex: 1 }}>{displayLabel}</Typography>\n {EndIconComponent ? <EndIconComponent /> : null}\n </MenuItemContent>\n </MuiMenuItem>\n );\n });\n\n return (\n <MuiMenu\n data-testid='root-menu'\n {...menuProps}\n transitionDuration={menuProps.transitionDuration || transitionConfig.timeout}\n slots={{ transition: transitionConfig.type, ...menuProps.slots }}\n >\n {renderedMenuEntries}\n </MuiMenu>\n );\n}\n","import type { FC, ReactNode, MouseEvent, KeyboardEvent } from 'react';\nimport { Children, cloneElement, isValidElement, useCallback, useId, useRef, useState } from 'react';\nimport Fade from '@mui/material/Fade';\nimport type { MenuItemProps } from '@mui/material/MenuItem';\nimport MuiMenuItem from '@mui/material/MenuItem';\nimport Divider from '@mui/material/Divider';\nimport ArrowRightIcon from '@mui/icons-material/ArrowRight';\nimport type { SvgIconComponent } from '@mui/icons-material';\nimport type { MenuListProps, MenuProps, PaperProps } from '@mui/material';\nimport { MenuList, Paper, Popper, Typography } from '@mui/material';\nimport type { MenuItem } from './types';\nimport { CLOSE_DELAY, MenuItemContent, transitionConfig } from './common';\nimport type { Props as BetterMenuProps } from '.';\n\ntype NestedMenuItemProps = MenuItemProps & {\n label: ReactNode;\n startIcon?: SvgIconComponent;\n endIcon?: SvgIconComponent;\n parentMenuClose: BetterMenuProps['onClose'];\n children?: ReactNode;\n items?: MenuItem[];\n menuProps: MenuProps;\n};\n\nconst isNodeInstance = (target: EventTarget | null): target is Node => target instanceof Node;\n\nexport const NestedMenuItem: FC<NestedMenuItemProps> = props => {\n const {\n id: providedId,\n label,\n startIcon: StartIconComponent,\n parentMenuClose,\n children,\n items,\n endIcon: _,\n menuProps,\n ...menuItemProps\n } = props;\n const [subMenuAnchorEl, setSubMenuAnchorEl] = useState<null | HTMLElement>(null);\n const open = Boolean(subMenuAnchorEl);\n const menuItemRef = useRef<HTMLLIElement>(null);\n const subMenuRef = useRef<HTMLDivElement>(null);\n const generatedId = useId();\n const menuItemId = providedId ?? `nested-menu-trigger-${generatedId}`;\n const subMenuId = `${menuItemId}-submenu`;\n\n const closeTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n\n const clearCloseTimer = useCallback(() => {\n if (closeTimerRef.current) {\n clearTimeout(closeTimerRef.current);\n closeTimerRef.current = null;\n }\n }, []);\n\n const handleClose = useCallback(() => {\n clearCloseTimer();\n setSubMenuAnchorEl(null);\n }, [clearCloseTimer]);\n\n const scheduleClose = useCallback(() => {\n clearCloseTimer();\n closeTimerRef.current = setTimeout(() => {\n handleClose();\n }, CLOSE_DELAY);\n }, [clearCloseTimer, handleClose]);\n\n const handleOpen = (event: MouseEvent<HTMLLIElement> | KeyboardEvent<HTMLLIElement>) => {\n clearCloseTimer();\n setSubMenuAnchorEl(event.currentTarget);\n };\n\n\n // eslint-disable-next-line react-hooks/refs\n const renderChildren = Children.map(children, child => {\n if (!isValidElement(child)) return child;\n\n // Ensure we only process MUI MenuItem children\n if (child.type === MuiMenuItem) {\n const childOnClick = (child.props as MenuItemProps).onClick;\n // Merge any user-defined click logic with the submenu closing behavior.\n const clonedOnClick = (event: MouseEvent<HTMLLIElement>) => {\n childOnClick?.(event);\n handleClose(); // Close the submenu\n parentMenuClose?.(event, \"itemClick\", menuItemId);\n };\n return cloneElement(child, { onClick: clonedOnClick } as Partial<MenuItemProps>);\n }\n return child;\n });\n\n const renderItemsFromData = () => {\n if (!items || items.length === 0) return null;\n\n return items.map((item, index) => {\n if (item.type === 'divider') {\n\n return <Divider key={`divider-${index}`} />;\n }\n\n const {\n type: __,\n items: entryItems,\n startIcon: NestedMenuItemStartIcon,\n endIcon: NestedMenuItemEndIcon,\n label: entryLabel,\n onClick,\n id,\n } = item;\n const entryId = id ?? `${menuItemId}-entry-${index}`;\n const entryKey = `nested-entry-${entryId}`;\n const entryLabelValue = entryLabel ?? entryId;\n\n if (entryItems && entryItems.length > 0) {\n return (\n <NestedMenuItem\n key={entryKey}\n id={entryId}\n label={entryLabelValue}\n startIcon={NestedMenuItemStartIcon}\n endIcon={NestedMenuItemEndIcon}\n parentMenuClose={parentMenuClose}\n items={entryItems}\n menuProps={menuProps}\n />\n );\n }\n\n const handleItemClick = (event: MouseEvent<HTMLLIElement>) => {\n onClick?.(event);\n handleClose();\n parentMenuClose?.(event, \"itemClick\", entryId);\n };\n\n return (\n <MuiMenuItem key={entryKey} onClick={handleItemClick}>\n <MenuItemContent>\n {NestedMenuItemStartIcon ? <NestedMenuItemStartIcon /> : null}\n <Typography sx={{ flex: 1 }}>{entryLabelValue}</Typography>\n {NestedMenuItemEndIcon ? <NestedMenuItemEndIcon /> : null}\n </MenuItemContent>\n </MuiMenuItem>\n );\n });\n };\n\n const renderedSubMenuItems = items && items.length > 0 ? renderItemsFromData() : renderChildren;\n\n return (\n <>\n <MuiMenuItem\n data-testid={`${menuItemId}-trigger`}\n id={menuItemId}\n ref={menuItemRef}\n onMouseEnter={handleOpen}\n onMouseLeave={e => {\n // CRITICAL FEATURE:\n // Checking whether cursor left the menu item onto the related menu. If so, do not close.\n if (isNodeInstance(e.relatedTarget) && subMenuRef.current?.contains(e.relatedTarget)) return;\n // If the cursor leaves to anywhere else, close the submenu.\n scheduleClose();\n }}\n onKeyDown={e => {\n e.preventDefault();\n if (e.key === 'ArrowLeft') {\n handleClose();\n }\n if (e.key === 'ArrowRight' || e.key === 'Enter' || e.key === ' ') {\n handleOpen(e);\n }\n }}\n aria-haspopup='menu'\n aria-controls={subMenuId}\n aria-expanded={open ? 'true' : undefined}\n {...menuItemProps}\n >\n <MenuItemContent>\n {StartIconComponent ? <StartIconComponent /> : null}\n <Typography sx={{ flex: 1 }}>{label}</Typography>\n <ArrowRightIcon />\n </MenuItemContent>\n </MuiMenuItem>\n\n {/**\n * CRITICAL FEATURE: Menu over Menu fails with focus management and keyboard navigations. \n * It is way more complex to make Menu to work compared to Popper. So, I made the decision to use Popper for submenus.\n * This way we can manage focus and keyboard navigation simpler, and we can also avoid some weird edge cases.\n * If you change this to regular Menu, you will realize that you need to add many custom JS logic to manage focus and keyboard navigation,\n * as well as to block Menu's internal logic.\n */}\n <Popper\n data-testid={`${menuItemId}-submenu`}\n open={open}\n ref={subMenuRef}\n anchorEl={subMenuAnchorEl}\n transition\n sx={{ zIndex: t => t.zIndex.modal + 1 }}\n placement='right-start'\n onKeyDown={e => {\n if (e.key === 'ArrowLeft') {\n e.preventDefault();\n handleClose();\n menuItemRef.current?.focus();\n }\n if (e.key === 'ArrowUp' || e.key === 'ArrowDown') {\n e.preventDefault();\n e.stopPropagation();\n }\n }}\n onMouseEnter={clearCloseTimer}\n onMouseLeave={e => {\n // CRITICAL FEATURE:\n // Checking whether cursor left the submenu onto the related trigger item. If so, do not close.\n if (isNodeInstance(e.relatedTarget) && menuItemRef.current?.contains(e.relatedTarget)) return;\n // If the cursor leaves to anywhere else, close the submenu.\n scheduleClose();\n }}\n >\n {({ TransitionProps }) => (\n <Fade {...TransitionProps} timeout={transitionConfig.timeout}>\n <Paper elevation={menuProps.elevation} {...(menuProps?.slotProps?.paper as PaperProps) || {}}>\n <MenuList\n id={subMenuId}\n aria-labelledby={menuItemId}\n role='menu'\n {...(menuProps?.slotProps?.list as MenuListProps) || {}}\n // What's under is not allowed to be overridden for now\n autoFocusItem\n onKeyDown={e => {\n if (e.key === 'ArrowLeft') {\n const { nativeEvent } = e as KeyboardEvent<HTMLUListElement> & {\n nativeEvent: KeyboardEvent & {\n // our custom flag to avoid duplicate handling in nested menus\n __nestedMenuArrowLeftHandled?: boolean;\n };\n };\n if (nativeEvent.__nestedMenuArrowLeftHandled) {\n // return early if we have already handled this event in a nested menu\n // prevents duplicate logic when the browser bubbles the same keypress through multiple nodes\n return;\n }\n if (!subMenuRef.current?.contains(e.target as Node)) {\n // confirm the event’s target is still inside this submenu;\n // if the keypress originated elsewhere, we don’t continue so other menus can handle it\n return;\n }\n // Mark this event as handled to prevent parent menus from also processing it\n nativeEvent.__nestedMenuArrowLeftHandled = true;\n // preventDefault is needed so the browser doesn’t do its own “arrow left” behavior (like moving the text caret\n // or changing focus) while the menu is managing the navigation. Without this, the closed submenu or focused item\n // might jump unexpectedly even though the menu logic is running.\n e.preventDefault();\n // stopPropagation stops the event from bubbling up to parent DOM nodes that might also have onKeyDown, which could\n // otherwise fight the menu’s own logic or trigger duplicate navigation even though we guard with __nestedMenuArrowLeftHandled\n e.stopPropagation();\n // stopImmediatePropagation keeps any other keydown handlers registered on this same DOM node from running after ours.\n // This is preventing all submenus to close when pressing ArrowLeft in a, say, third level menu. With this, ArrowLeft will only\n // close the current submenu. The __nestedMenuArrowLeftHandled flag only guards against bubbling; this stopImmediatePropagation()\n // ensures no other handlers wired to the same node interfere once we decide to close and focus.\n nativeEvent.stopImmediatePropagation();\n // close the sub menu\n handleClose();\n // move focus back to the parent MenuItem, letting the user continue navigation up the menu hierarchy\n menuItemRef.current?.focus();\n }\n }}\n >\n {renderedSubMenuItems}\n </MenuList>\n </Paper>\n </Fade>\n )}\n </Popper>\n </>\n );\n};\n","'use client';\n\nexport { createSvgIcon as default } from '@mui/material/utils';","\"use client\";\n\nimport createSvgIcon from \"./utils/createSvgIcon.js\";\nimport { jsx as _jsx } from \"react/jsx-runtime\";\nexport default createSvgIcon(/*#__PURE__*/_jsx(\"path\", {\n d: \"m10 17 5-5-5-5z\"\n}), 'ArrowRight');","import { Stack, styled } from '@mui/material';\nimport Fade from '@mui/material/Fade';\n\nexport const CLOSE_DELAY = 50;\nexport const transitionConfig = {\n type: Fade,\n timeout: { enter: CLOSE_DELAY + 50, exit: CLOSE_DELAY + 50 },\n};\nexport const DEFAULT_ELEVATION = 8; // this is also what MUI menu uses as default\n\nexport const MenuItemContent = styled(Stack)({\n flexDirection: 'row',\n alignItems: 'center',\n gap: '8px',\n padding: 0,\n});\n"],"mappings":"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","names":["import_Divider","import_MenuItem","import_react","import_material","import_Fade","_jsx","import_material","Fade","import_jsx_runtime","MuiMenuItem","Divider","Fade","import_jsx_runtime","Divider","MuiMenuItem","MuiMenu"]}
package/dist/index.d.cts CHANGED
@@ -1,5 +1,6 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
- import { ReactNode } from 'react';
2
+ import { MenuProps } from '@mui/material/Menu';
3
+ import React, { ReactNode } from 'react';
3
4
  import { MenuItemProps } from '@mui/material/MenuItem';
4
5
  import { SvgIconComponent } from '@mui/icons-material';
5
6
 
@@ -16,11 +17,9 @@ type MenuItemBase = {
16
17
  type MenuItem = MenuItemBase & Omit<MenuItemProps, 'children'>;
17
18
 
18
19
  type Props = {
19
- anchorEl: null | HTMLElement;
20
- open: boolean;
21
- onClose: () => void;
22
20
  items: MenuItem[];
23
- };
24
- declare function Menu({ anchorEl, open, onClose, items }: Props): react_jsx_runtime.JSX.Element;
21
+ onClose?: (event: React.MouseEvent | React.KeyboardEvent, reason: 'itemClick' | 'escapeKeyDown' | 'backdropClick', menuItemId?: string) => void;
22
+ } & Omit<MenuProps, 'onClose'>;
23
+ declare function Menu({ items, elevation, ...rest }: Props): react_jsx_runtime.JSX.Element;
25
24
 
26
25
  export { type MenuItem, Menu as default };
package/dist/index.d.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
- import { ReactNode } from 'react';
2
+ import { MenuProps } from '@mui/material/Menu';
3
+ import React, { ReactNode } from 'react';
3
4
  import { MenuItemProps } from '@mui/material/MenuItem';
4
5
  import { SvgIconComponent } from '@mui/icons-material';
5
6
 
@@ -16,11 +17,9 @@ type MenuItemBase = {
16
17
  type MenuItem = MenuItemBase & Omit<MenuItemProps, 'children'>;
17
18
 
18
19
  type Props = {
19
- anchorEl: null | HTMLElement;
20
- open: boolean;
21
- onClose: () => void;
22
20
  items: MenuItem[];
23
- };
24
- declare function Menu({ anchorEl, open, onClose, items }: Props): react_jsx_runtime.JSX.Element;
21
+ onClose?: (event: React.MouseEvent | React.KeyboardEvent, reason: 'itemClick' | 'escapeKeyDown' | 'backdropClick', menuItemId?: string) => void;
22
+ } & Omit<MenuProps, 'onClose'>;
23
+ declare function Menu({ items, elevation, ...rest }: Props): react_jsx_runtime.JSX.Element;
25
24
 
26
25
  export { type MenuItem, Menu as default };
package/dist/index.js CHANGED
@@ -31,16 +31,13 @@ var transitionConfig = {
31
31
  type: Fade,
32
32
  timeout: { enter: CLOSE_DELAY + 50, exit: CLOSE_DELAY + 50 }
33
33
  };
34
- var MenuItemContent = styled(Stack)(({ theme }) => ({
34
+ var DEFAULT_ELEVATION = 8;
35
+ var MenuItemContent = styled(Stack)({
35
36
  flexDirection: "row",
36
37
  alignItems: "center",
37
- gap: theme.spacing(1),
38
- fontSize: theme.typography.body1.fontSize,
39
- "& .MuiSvgIcon-root": {
40
- fontSize: theme.typography.body2.fontSize
41
- },
38
+ gap: "8px",
42
39
  padding: 0
43
- }));
40
+ });
44
41
 
45
42
  // src/Menu/NestedMenuItem.tsx
46
43
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
@@ -54,6 +51,7 @@ var NestedMenuItem = (props) => {
54
51
  children,
55
52
  items,
56
53
  endIcon: _,
54
+ menuProps,
57
55
  ...menuItemProps
58
56
  } = props;
59
57
  const [subMenuAnchorEl, setSubMenuAnchorEl] = useState(null);
@@ -91,7 +89,7 @@ var NestedMenuItem = (props) => {
91
89
  const clonedOnClick = (event) => {
92
90
  childOnClick?.(event);
93
91
  handleClose();
94
- parentMenuClose();
92
+ parentMenuClose?.(event, "itemClick", menuItemId);
95
93
  };
96
94
  return cloneElement(child, { onClick: clonedOnClick });
97
95
  }
@@ -124,7 +122,8 @@ var NestedMenuItem = (props) => {
124
122
  startIcon: NestedMenuItemStartIcon,
125
123
  endIcon: NestedMenuItemEndIcon,
126
124
  parentMenuClose,
127
- items: entryItems
125
+ items: entryItems,
126
+ menuProps
128
127
  },
129
128
  entryKey
130
129
  );
@@ -132,7 +131,7 @@ var NestedMenuItem = (props) => {
132
131
  const handleItemClick = (event) => {
133
132
  onClick?.(event);
134
133
  handleClose();
135
- parentMenuClose();
134
+ parentMenuClose?.(event, "itemClick", entryId);
136
135
  };
137
136
  return /* @__PURE__ */ jsx(MuiMenuItem, { onClick: handleItemClick, children: /* @__PURE__ */ jsxs(MenuItemContent, { children: [
138
137
  NestedMenuItemStartIcon ? /* @__PURE__ */ jsx(NestedMenuItemStartIcon, {}) : null,
@@ -200,43 +199,34 @@ var NestedMenuItem = (props) => {
200
199
  if (isNodeInstance(e.relatedTarget) && menuItemRef.current?.contains(e.relatedTarget)) return;
201
200
  scheduleClose();
202
201
  },
203
- children: ({ TransitionProps }) => /* @__PURE__ */ jsx(Fade2, { ...TransitionProps, timeout: transitionConfig.timeout, children: /* @__PURE__ */ jsx(
204
- Paper,
202
+ children: ({ TransitionProps }) => /* @__PURE__ */ jsx(Fade2, { ...TransitionProps, timeout: transitionConfig.timeout, children: /* @__PURE__ */ jsx(Paper, { elevation: menuProps.elevation, ...menuProps?.slotProps?.paper || {}, children: /* @__PURE__ */ jsx(
203
+ MenuList,
205
204
  {
206
- elevation: 2,
207
- sx: {
208
- borderRadius: 1,
209
- bgcolor: "background.default"
210
- },
211
- children: /* @__PURE__ */ jsx(
212
- MenuList,
213
- {
214
- autoFocusItem: true,
215
- id: subMenuId,
216
- "aria-labelledby": menuItemId,
217
- role: "menu",
218
- onKeyDown: (e) => {
219
- if (e.key === "ArrowLeft") {
220
- const { nativeEvent } = e;
221
- if (nativeEvent.__nestedMenuArrowLeftHandled) {
222
- return;
223
- }
224
- if (!subMenuRef.current?.contains(e.target)) {
225
- return;
226
- }
227
- nativeEvent.__nestedMenuArrowLeftHandled = true;
228
- e.preventDefault();
229
- e.stopPropagation();
230
- nativeEvent.stopImmediatePropagation();
231
- handleClose();
232
- menuItemRef.current?.focus();
233
- }
234
- },
235
- children: renderedSubMenuItems
205
+ id: subMenuId,
206
+ "aria-labelledby": menuItemId,
207
+ role: "menu",
208
+ ...menuProps?.slotProps?.list || {},
209
+ autoFocusItem: true,
210
+ onKeyDown: (e) => {
211
+ if (e.key === "ArrowLeft") {
212
+ const { nativeEvent } = e;
213
+ if (nativeEvent.__nestedMenuArrowLeftHandled) {
214
+ return;
215
+ }
216
+ if (!subMenuRef.current?.contains(e.target)) {
217
+ return;
218
+ }
219
+ nativeEvent.__nestedMenuArrowLeftHandled = true;
220
+ e.preventDefault();
221
+ e.stopPropagation();
222
+ nativeEvent.stopImmediatePropagation();
223
+ handleClose();
224
+ menuItemRef.current?.focus();
236
225
  }
237
- )
226
+ },
227
+ children: renderedSubMenuItems
238
228
  }
239
- ) })
229
+ ) }) })
240
230
  }
241
231
  )
242
232
  ] });
@@ -244,7 +234,8 @@ var NestedMenuItem = (props) => {
244
234
 
245
235
  // src/Menu/index.tsx
246
236
  import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
247
- function Menu({ anchorEl, open, onClose, items }) {
237
+ function Menu({ items, elevation = DEFAULT_ELEVATION, ...rest }) {
238
+ const menuProps = { elevation, ...rest };
248
239
  const generatedMenuId = useId2();
249
240
  const renderedMenuEntries = items.map((item, index) => {
250
241
  if (item.type === "divider") {
@@ -271,15 +262,16 @@ function Menu({ anchorEl, open, onClose, items }) {
271
262
  label: displayLabel,
272
263
  startIcon: StartIconComponent,
273
264
  endIcon: EndIconComponent,
274
- parentMenuClose: onClose,
275
- items: nestedItems
265
+ parentMenuClose: menuProps.onClose,
266
+ items: nestedItems,
267
+ menuProps
276
268
  },
277
269
  itemKey
278
270
  );
279
271
  }
280
272
  const handleItemClick = (event) => {
281
273
  onClick?.(event);
282
- onClose();
274
+ menuProps.onClose?.(event, "itemClick", entryId);
283
275
  };
284
276
  return /* @__PURE__ */ jsx2(MuiMenuItem2, { onClick: handleItemClick, ...menuItemProps, children: /* @__PURE__ */ jsxs2(MenuItemContent, { children: [
285
277
  StartIconComponent ? /* @__PURE__ */ jsx2(StartIconComponent, {}) : null,
@@ -291,19 +283,9 @@ function Menu({ anchorEl, open, onClose, items }) {
291
283
  MuiMenu,
292
284
  {
293
285
  "data-testid": "root-menu",
294
- anchorEl,
295
- open,
296
- onClose,
297
- onKeyDown: (e) => {
298
- if (e.key === "Escape" && open) onClose();
299
- },
300
- transitionDuration: transitionConfig.timeout,
301
- slots: { transition: transitionConfig.type },
302
- slotProps: {
303
- list: {
304
- "aria-labelledby": "icon-menu-button"
305
- }
306
- },
286
+ ...menuProps,
287
+ transitionDuration: menuProps.transitionDuration || transitionConfig.timeout,
288
+ slots: { transition: transitionConfig.type, ...menuProps.slots },
307
289
  children: renderedMenuEntries
308
290
  }
309
291
  );
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/Menu/index.tsx","../src/Menu/NestedMenuItem.tsx","../../../node_modules/@mui/icons-material/esm/utils/createSvgIcon.js","../../../node_modules/@mui/icons-material/esm/ArrowRight.js","../src/Menu/common.ts","../src/index.ts"],"sourcesContent":["import MuiMenu from '@mui/material/Menu';\nimport Divider from '@mui/material/Divider';\nimport MuiMenuItem from '@mui/material/MenuItem';\nimport React, { useId } from 'react';\nimport { Typography } from '@mui/material';\nimport { NestedMenuItem } from './NestedMenuItem';\nimport type { MenuItem } from './types';\nimport { MenuItemContent, transitionConfig } from './common';\n\ntype Props = {\n anchorEl: null | HTMLElement;\n open: boolean;\n onClose: () => void;\n items: MenuItem[];\n};\n\nexport function Menu({ anchorEl, open, onClose, items }: Props) {\n const generatedMenuId = useId();\n\n const renderedMenuEntries = items.map((item, index) => {\n if (item.type === 'divider') {\n return <Divider key={`divider-${index}`} />;\n }\n\n const {\n type: _,\n items: nestedItems,\n startIcon: StartIconComponent,\n endIcon: EndIconComponent,\n label,\n onClick,\n id,\n ...menuItemProps\n } = item;\n const entryId = id ?? `${generatedMenuId}-entry-${index}`;\n const itemKey = `menu-item-id:${entryId}`;\n const displayLabel = label ?? entryId;\n\n if (nestedItems && nestedItems.length > 0) {\n return (\n <NestedMenuItem\n key={itemKey}\n id={entryId}\n label={displayLabel}\n startIcon={StartIconComponent}\n endIcon={EndIconComponent}\n parentMenuClose={onClose}\n items={nestedItems}\n />\n );\n }\n\n const handleItemClick = (event: React.MouseEvent<HTMLLIElement>) => {\n onClick?.(event);\n onClose();\n };\n\n return (\n <MuiMenuItem key={itemKey} onClick={handleItemClick} {...menuItemProps}>\n <MenuItemContent>\n {StartIconComponent ? <StartIconComponent /> : null}\n <Typography sx={{ flex: 1 }}>{displayLabel}</Typography>\n {EndIconComponent ? <EndIconComponent /> : null}\n </MenuItemContent>\n </MuiMenuItem>\n );\n });\n\n return (\n <MuiMenu\n data-testid='root-menu'\n anchorEl={anchorEl}\n open={open}\n onClose={onClose}\n onKeyDown={e => {\n if (e.key === 'Escape' && open) onClose();\n }}\n transitionDuration={transitionConfig.timeout}\n slots={{ transition: transitionConfig.type }}\n slotProps={{\n list: {\n 'aria-labelledby': 'icon-menu-button',\n },\n }}\n >\n {renderedMenuEntries}\n </MuiMenu>\n );\n}\n","import type { FC, ReactNode, MouseEvent, KeyboardEvent } from 'react';\nimport { Children, cloneElement, isValidElement, useCallback, useId, useRef, useState } from 'react';\nimport Fade from '@mui/material/Fade';\nimport type { MenuItemProps } from '@mui/material/MenuItem';\nimport MuiMenuItem from '@mui/material/MenuItem';\nimport Divider from '@mui/material/Divider';\nimport ArrowRightIcon from '@mui/icons-material/ArrowRight';\nimport type { SvgIconComponent } from '@mui/icons-material';\nimport { MenuList, Paper, Popper, Typography } from '@mui/material';\nimport type { MenuItem } from './types';\nimport { CLOSE_DELAY, MenuItemContent, transitionConfig } from './common';\n\ntype NestedMenuItemProps = MenuItemProps & {\n label: ReactNode;\n startIcon?: SvgIconComponent;\n endIcon?: SvgIconComponent;\n parentMenuClose: () => void;\n children?: ReactNode;\n items?: MenuItem[];\n};\n\nconst isNodeInstance = (target: EventTarget | null): target is Node => target instanceof Node;\n\nexport const NestedMenuItem: FC<NestedMenuItemProps> = props => {\n const {\n id: providedId,\n label,\n startIcon: StartIconComponent,\n parentMenuClose,\n children,\n items,\n endIcon: _,\n ...menuItemProps\n } = props;\n const [subMenuAnchorEl, setSubMenuAnchorEl] = useState<null | HTMLElement>(null);\n const open = Boolean(subMenuAnchorEl);\n const menuItemRef = useRef<HTMLLIElement>(null);\n const subMenuRef = useRef<HTMLDivElement>(null);\n const generatedId = useId();\n const menuItemId = providedId ?? `nested-menu-trigger-${generatedId}`;\n const subMenuId = `${menuItemId}-submenu`;\n\n const closeTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n\n const clearCloseTimer = useCallback(() => {\n if (closeTimerRef.current) {\n clearTimeout(closeTimerRef.current);\n closeTimerRef.current = null;\n }\n }, []);\n\n const handleClose = useCallback(() => {\n clearCloseTimer();\n setSubMenuAnchorEl(null);\n }, [clearCloseTimer]);\n\n const scheduleClose = useCallback(() => {\n clearCloseTimer();\n closeTimerRef.current = setTimeout(() => {\n handleClose();\n }, CLOSE_DELAY);\n }, [clearCloseTimer, handleClose]);\n\n const handleOpen = (event: MouseEvent<HTMLLIElement> | KeyboardEvent<HTMLLIElement>) => {\n clearCloseTimer();\n setSubMenuAnchorEl(event.currentTarget);\n };\n\n\n // eslint-disable-next-line react-hooks/refs\n const renderChildren = Children.map(children, child => {\n if (!isValidElement(child)) return child;\n\n // Ensure we only process MUI MenuItem children\n if (child.type === MuiMenuItem) {\n const childOnClick = (child.props as MenuItemProps).onClick;\n // Merge any user-defined click logic with the submenu closing behavior.\n const clonedOnClick = (event: MouseEvent<HTMLLIElement>) => {\n childOnClick?.(event);\n handleClose(); // Close the submenu\n parentMenuClose();\n };\n return cloneElement(child, { onClick: clonedOnClick } as Partial<MenuItemProps>);\n }\n return child;\n });\n\n const renderItemsFromData = () => {\n if (!items || items.length === 0) return null;\n\n return items.map((item, index) => {\n if (item.type === 'divider') {\n\n return <Divider key={`divider-${index}`} />;\n }\n\n const {\n type: __,\n items: entryItems,\n startIcon: NestedMenuItemStartIcon,\n endIcon: NestedMenuItemEndIcon,\n label: entryLabel,\n onClick,\n id,\n } = item;\n const entryId = id ?? `${menuItemId}-entry-${index}`;\n const entryKey = `nested-entry-${entryId}`;\n const entryLabelValue = entryLabel ?? entryId;\n\n if (entryItems && entryItems.length > 0) {\n return (\n <NestedMenuItem\n key={entryKey}\n id={entryId}\n label={entryLabelValue}\n startIcon={NestedMenuItemStartIcon}\n endIcon={NestedMenuItemEndIcon}\n parentMenuClose={parentMenuClose}\n items={entryItems}\n />\n );\n }\n\n const handleItemClick = (event: MouseEvent<HTMLLIElement>) => {\n onClick?.(event);\n handleClose();\n parentMenuClose();\n };\n\n return (\n <MuiMenuItem key={entryKey} onClick={handleItemClick}>\n <MenuItemContent>\n {NestedMenuItemStartIcon ? <NestedMenuItemStartIcon /> : null}\n <Typography sx={{ flex: 1 }}>{entryLabelValue}</Typography>\n {NestedMenuItemEndIcon ? <NestedMenuItemEndIcon /> : null}\n </MenuItemContent>\n </MuiMenuItem>\n );\n });\n };\n\n const renderedSubMenuItems = items && items.length > 0 ? renderItemsFromData() : renderChildren;\n\n return (\n <>\n <MuiMenuItem\n data-testid={`${menuItemId}-trigger`}\n id={menuItemId}\n ref={menuItemRef}\n onMouseEnter={handleOpen}\n onMouseLeave={e => {\n // CRITICAL FEATURE:\n // Checking whether cursor left the menu item onto the related menu. If so, do not close.\n // TODO(ege): There can be a timeout here before we execute closing to improve UX - in case user is not very precise with mouse.\n if (isNodeInstance(e.relatedTarget) && subMenuRef.current?.contains(e.relatedTarget)) return;\n // If the cursor leaves to anywhere else, close the submenu.\n scheduleClose();\n }}\n onKeyDown={e => {\n e.preventDefault();\n if (e.key === 'ArrowLeft') {\n handleClose();\n }\n if (e.key === 'ArrowRight' || e.key === 'Enter' || e.key === ' ') {\n handleOpen(e);\n }\n }}\n aria-haspopup='menu'\n aria-controls={subMenuId}\n aria-expanded={open ? 'true' : undefined}\n {...menuItemProps}\n >\n <MenuItemContent>\n {StartIconComponent ? <StartIconComponent /> : null}\n <Typography sx={{ flex: 1 }}>{label}</Typography>\n <ArrowRightIcon />\n </MenuItemContent>\n </MuiMenuItem>\n\n <Popper\n data-testid={`${menuItemId}-submenu`}\n open={open}\n ref={subMenuRef}\n anchorEl={subMenuAnchorEl}\n transition\n sx={{ zIndex: t => t.zIndex.modal + 1 }}\n placement='right-start'\n onKeyDown={e => {\n if (e.key === 'ArrowLeft') {\n e.preventDefault();\n handleClose();\n menuItemRef.current?.focus();\n }\n if (e.key === 'ArrowUp' || e.key === 'ArrowDown') {\n e.preventDefault();\n e.stopPropagation();\n }\n }}\n onMouseEnter={clearCloseTimer}\n onMouseLeave={e => {\n // CRITICAL FEATURE:\n // Checking whether cursor left the submenu onto the related trigger item. If so, do not close.\n // TODO(ege): There can be a timeout here before we execute closing to improve UX - in case user is not very precise with mouse.\n if (isNodeInstance(e.relatedTarget) && menuItemRef.current?.contains(e.relatedTarget)) return;\n // If the cursor leaves to anywhere else, close the submenu.\n scheduleClose();\n }}\n >\n {({ TransitionProps }) => (\n <Fade {...TransitionProps} timeout={transitionConfig.timeout}>\n <Paper\n elevation={2}\n sx={{\n borderRadius: 1,\n bgcolor: 'background.default',\n }}\n >\n <MenuList\n autoFocusItem\n id={subMenuId}\n aria-labelledby={menuItemId}\n role='menu'\n onKeyDown={e => {\n if (e.key === 'ArrowLeft') {\n const { nativeEvent } = e as KeyboardEvent<HTMLUListElement> & {\n nativeEvent: KeyboardEvent & {\n // our custom flag to avoid duplicate handling in nested menus\n __nestedMenuArrowLeftHandled?: boolean;\n };\n };\n if (nativeEvent.__nestedMenuArrowLeftHandled) {\n // return early if we have already handled this event in a nested menu\n // prevents duplicate logic when the browser bubbles the same keypress through multiple nodes\n return;\n }\n if (!subMenuRef.current?.contains(e.target as Node)) {\n // confirm the event’s target is still inside this submenu;\n // if the keypress originated elsewhere, we don’t continue so other menus can handle it\n return;\n }\n // Mark this event as handled to prevent parent menus from also processing it\n nativeEvent.__nestedMenuArrowLeftHandled = true;\n // preventDefault is needed so the browser doesn’t do its own “arrow left” behavior (like moving the text caret\n // or changing focus) while the menu is managing the navigation. Without this, the closed submenu or focused item\n // might jump unexpectedly even though the menu logic is running.\n e.preventDefault();\n // stopPropagation stops the event from bubbling up to parent DOM nodes that might also have onKeyDown, which could\n // otherwise fight the menu’s own logic or trigger duplicate navigation even though we guard with __nestedMenuArrowLeftHandled\n e.stopPropagation();\n // stopImmediatePropagation keeps any other keydown handlers registered on this same DOM node from running after ours.\n // This is preventing all submenus to close when pressing ArrowLeft in a, say, third level menu. With this, ArrowLeft will only\n // close the current submenu. The __nestedMenuArrowLeftHandled flag only guards against bubbling; this stopImmediatePropagation()\n // ensures no other handlers wired to the same node interfere once we decide to close and focus.\n nativeEvent.stopImmediatePropagation();\n // close the sub menu\n handleClose();\n // move focus back to the parent MenuItem, letting the user continue navigation up the menu hierarchy\n menuItemRef.current?.focus();\n }\n }}\n >\n {renderedSubMenuItems}\n </MenuList>\n </Paper>\n </Fade>\n )}\n </Popper>\n </>\n );\n};\n","'use client';\n\nexport { createSvgIcon as default } from '@mui/material/utils';","\"use client\";\n\nimport createSvgIcon from \"./utils/createSvgIcon.js\";\nimport { jsx as _jsx } from \"react/jsx-runtime\";\nexport default createSvgIcon(/*#__PURE__*/_jsx(\"path\", {\n d: \"m10 17 5-5-5-5z\"\n}), 'ArrowRight');","import { Stack, styled } from '@mui/material';\nimport Fade from '@mui/material/Fade';\n\nexport const CLOSE_DELAY = 50;\nexport const transitionConfig = {\n type: Fade,\n timeout: { enter: CLOSE_DELAY + 50, exit: CLOSE_DELAY + 50 },\n};\n\nexport const MenuItemContent = styled(Stack)(({ theme }) => ({\n flexDirection: 'row',\n alignItems: 'center',\n gap: theme.spacing(1),\n fontSize: theme.typography.body1.fontSize,\n '& .MuiSvgIcon-root': {\n fontSize: theme.typography.body2.fontSize,\n },\n padding: 0,\n}));\n","import { Menu } from './Menu'\n\nexport type { MenuItem } from './Menu/types'\nexport default Menu\n"],"mappings":"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","names":["Divider","MuiMenuItem","useId","Typography","Fade","Fade","jsx","jsxs","useId","Divider","MuiMenuItem","Typography"]}
1
+ {"version":3,"sources":["../src/Menu/index.tsx","../src/Menu/NestedMenuItem.tsx","../../../node_modules/@mui/icons-material/esm/utils/createSvgIcon.js","../../../node_modules/@mui/icons-material/esm/ArrowRight.js","../src/Menu/common.ts","../src/index.ts"],"sourcesContent":["import type { MenuProps } from '@mui/material/Menu';\nimport MuiMenu from '@mui/material/Menu';\nimport Divider from '@mui/material/Divider';\nimport MuiMenuItem from '@mui/material/MenuItem';\nimport React, { useId } from 'react';\nimport { Typography } from '@mui/material';\nimport { NestedMenuItem } from './NestedMenuItem';\nimport type { MenuItem } from './types';\nimport { DEFAULT_ELEVATION, MenuItemContent, transitionConfig } from './common';\n\nexport type Props = {\n items: MenuItem[];\n onClose?: (event: React.MouseEvent | React.KeyboardEvent, reason: 'itemClick' | 'escapeKeyDown' | 'backdropClick', menuItemId?: string\n ) => void;\n} & Omit<MenuProps, 'onClose'>;\n\nexport function Menu({ items, elevation = DEFAULT_ELEVATION, ...rest }: Props) {\n const menuProps: Omit<Props, 'items'> = { elevation, ...rest }; // setting the elevation for all nested menus here\n const generatedMenuId = useId();\n\n const renderedMenuEntries = items.map((item, index) => {\n if (item.type === 'divider') {\n return <Divider key={`divider-${index}`} />;\n }\n\n const {\n type: _,\n items: nestedItems,\n startIcon: StartIconComponent,\n endIcon: EndIconComponent,\n label,\n onClick,\n id,\n ...menuItemProps\n } = item;\n const entryId = id ?? `${generatedMenuId}-entry-${index}`;\n const itemKey = `menu-item-id:${entryId}`;\n const displayLabel = label ?? entryId;\n\n if (nestedItems && nestedItems.length > 0) {\n return (\n <NestedMenuItem\n key={itemKey}\n id={entryId}\n label={displayLabel}\n startIcon={StartIconComponent}\n endIcon={EndIconComponent}\n parentMenuClose={menuProps.onClose}\n items={nestedItems}\n menuProps={menuProps}\n />\n );\n }\n\n const handleItemClick = (event: React.MouseEvent<HTMLLIElement>) => {\n onClick?.(event);\n menuProps.onClose?.(event, \"itemClick\", entryId);\n };\n\n return (\n <MuiMenuItem key={itemKey} onClick={handleItemClick} {...menuItemProps}>\n <MenuItemContent>\n {StartIconComponent ? <StartIconComponent /> : null}\n <Typography sx={{ flex: 1 }}>{displayLabel}</Typography>\n {EndIconComponent ? <EndIconComponent /> : null}\n </MenuItemContent>\n </MuiMenuItem>\n );\n });\n\n return (\n <MuiMenu\n data-testid='root-menu'\n {...menuProps}\n transitionDuration={menuProps.transitionDuration || transitionConfig.timeout}\n slots={{ transition: transitionConfig.type, ...menuProps.slots }}\n >\n {renderedMenuEntries}\n </MuiMenu>\n );\n}\n","import type { FC, ReactNode, MouseEvent, KeyboardEvent } from 'react';\nimport { Children, cloneElement, isValidElement, useCallback, useId, useRef, useState } from 'react';\nimport Fade from '@mui/material/Fade';\nimport type { MenuItemProps } from '@mui/material/MenuItem';\nimport MuiMenuItem from '@mui/material/MenuItem';\nimport Divider from '@mui/material/Divider';\nimport ArrowRightIcon from '@mui/icons-material/ArrowRight';\nimport type { SvgIconComponent } from '@mui/icons-material';\nimport type { MenuListProps, MenuProps, PaperProps } from '@mui/material';\nimport { MenuList, Paper, Popper, Typography } from '@mui/material';\nimport type { MenuItem } from './types';\nimport { CLOSE_DELAY, MenuItemContent, transitionConfig } from './common';\nimport type { Props as BetterMenuProps } from '.';\n\ntype NestedMenuItemProps = MenuItemProps & {\n label: ReactNode;\n startIcon?: SvgIconComponent;\n endIcon?: SvgIconComponent;\n parentMenuClose: BetterMenuProps['onClose'];\n children?: ReactNode;\n items?: MenuItem[];\n menuProps: MenuProps;\n};\n\nconst isNodeInstance = (target: EventTarget | null): target is Node => target instanceof Node;\n\nexport const NestedMenuItem: FC<NestedMenuItemProps> = props => {\n const {\n id: providedId,\n label,\n startIcon: StartIconComponent,\n parentMenuClose,\n children,\n items,\n endIcon: _,\n menuProps,\n ...menuItemProps\n } = props;\n const [subMenuAnchorEl, setSubMenuAnchorEl] = useState<null | HTMLElement>(null);\n const open = Boolean(subMenuAnchorEl);\n const menuItemRef = useRef<HTMLLIElement>(null);\n const subMenuRef = useRef<HTMLDivElement>(null);\n const generatedId = useId();\n const menuItemId = providedId ?? `nested-menu-trigger-${generatedId}`;\n const subMenuId = `${menuItemId}-submenu`;\n\n const closeTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n\n const clearCloseTimer = useCallback(() => {\n if (closeTimerRef.current) {\n clearTimeout(closeTimerRef.current);\n closeTimerRef.current = null;\n }\n }, []);\n\n const handleClose = useCallback(() => {\n clearCloseTimer();\n setSubMenuAnchorEl(null);\n }, [clearCloseTimer]);\n\n const scheduleClose = useCallback(() => {\n clearCloseTimer();\n closeTimerRef.current = setTimeout(() => {\n handleClose();\n }, CLOSE_DELAY);\n }, [clearCloseTimer, handleClose]);\n\n const handleOpen = (event: MouseEvent<HTMLLIElement> | KeyboardEvent<HTMLLIElement>) => {\n clearCloseTimer();\n setSubMenuAnchorEl(event.currentTarget);\n };\n\n\n // eslint-disable-next-line react-hooks/refs\n const renderChildren = Children.map(children, child => {\n if (!isValidElement(child)) return child;\n\n // Ensure we only process MUI MenuItem children\n if (child.type === MuiMenuItem) {\n const childOnClick = (child.props as MenuItemProps).onClick;\n // Merge any user-defined click logic with the submenu closing behavior.\n const clonedOnClick = (event: MouseEvent<HTMLLIElement>) => {\n childOnClick?.(event);\n handleClose(); // Close the submenu\n parentMenuClose?.(event, \"itemClick\", menuItemId);\n };\n return cloneElement(child, { onClick: clonedOnClick } as Partial<MenuItemProps>);\n }\n return child;\n });\n\n const renderItemsFromData = () => {\n if (!items || items.length === 0) return null;\n\n return items.map((item, index) => {\n if (item.type === 'divider') {\n\n return <Divider key={`divider-${index}`} />;\n }\n\n const {\n type: __,\n items: entryItems,\n startIcon: NestedMenuItemStartIcon,\n endIcon: NestedMenuItemEndIcon,\n label: entryLabel,\n onClick,\n id,\n } = item;\n const entryId = id ?? `${menuItemId}-entry-${index}`;\n const entryKey = `nested-entry-${entryId}`;\n const entryLabelValue = entryLabel ?? entryId;\n\n if (entryItems && entryItems.length > 0) {\n return (\n <NestedMenuItem\n key={entryKey}\n id={entryId}\n label={entryLabelValue}\n startIcon={NestedMenuItemStartIcon}\n endIcon={NestedMenuItemEndIcon}\n parentMenuClose={parentMenuClose}\n items={entryItems}\n menuProps={menuProps}\n />\n );\n }\n\n const handleItemClick = (event: MouseEvent<HTMLLIElement>) => {\n onClick?.(event);\n handleClose();\n parentMenuClose?.(event, \"itemClick\", entryId);\n };\n\n return (\n <MuiMenuItem key={entryKey} onClick={handleItemClick}>\n <MenuItemContent>\n {NestedMenuItemStartIcon ? <NestedMenuItemStartIcon /> : null}\n <Typography sx={{ flex: 1 }}>{entryLabelValue}</Typography>\n {NestedMenuItemEndIcon ? <NestedMenuItemEndIcon /> : null}\n </MenuItemContent>\n </MuiMenuItem>\n );\n });\n };\n\n const renderedSubMenuItems = items && items.length > 0 ? renderItemsFromData() : renderChildren;\n\n return (\n <>\n <MuiMenuItem\n data-testid={`${menuItemId}-trigger`}\n id={menuItemId}\n ref={menuItemRef}\n onMouseEnter={handleOpen}\n onMouseLeave={e => {\n // CRITICAL FEATURE:\n // Checking whether cursor left the menu item onto the related menu. If so, do not close.\n if (isNodeInstance(e.relatedTarget) && subMenuRef.current?.contains(e.relatedTarget)) return;\n // If the cursor leaves to anywhere else, close the submenu.\n scheduleClose();\n }}\n onKeyDown={e => {\n e.preventDefault();\n if (e.key === 'ArrowLeft') {\n handleClose();\n }\n if (e.key === 'ArrowRight' || e.key === 'Enter' || e.key === ' ') {\n handleOpen(e);\n }\n }}\n aria-haspopup='menu'\n aria-controls={subMenuId}\n aria-expanded={open ? 'true' : undefined}\n {...menuItemProps}\n >\n <MenuItemContent>\n {StartIconComponent ? <StartIconComponent /> : null}\n <Typography sx={{ flex: 1 }}>{label}</Typography>\n <ArrowRightIcon />\n </MenuItemContent>\n </MuiMenuItem>\n\n {/**\n * CRITICAL FEATURE: Menu over Menu fails with focus management and keyboard navigations. \n * It is way more complex to make Menu to work compared to Popper. So, I made the decision to use Popper for submenus.\n * This way we can manage focus and keyboard navigation simpler, and we can also avoid some weird edge cases.\n * If you change this to regular Menu, you will realize that you need to add many custom JS logic to manage focus and keyboard navigation,\n * as well as to block Menu's internal logic.\n */}\n <Popper\n data-testid={`${menuItemId}-submenu`}\n open={open}\n ref={subMenuRef}\n anchorEl={subMenuAnchorEl}\n transition\n sx={{ zIndex: t => t.zIndex.modal + 1 }}\n placement='right-start'\n onKeyDown={e => {\n if (e.key === 'ArrowLeft') {\n e.preventDefault();\n handleClose();\n menuItemRef.current?.focus();\n }\n if (e.key === 'ArrowUp' || e.key === 'ArrowDown') {\n e.preventDefault();\n e.stopPropagation();\n }\n }}\n onMouseEnter={clearCloseTimer}\n onMouseLeave={e => {\n // CRITICAL FEATURE:\n // Checking whether cursor left the submenu onto the related trigger item. If so, do not close.\n if (isNodeInstance(e.relatedTarget) && menuItemRef.current?.contains(e.relatedTarget)) return;\n // If the cursor leaves to anywhere else, close the submenu.\n scheduleClose();\n }}\n >\n {({ TransitionProps }) => (\n <Fade {...TransitionProps} timeout={transitionConfig.timeout}>\n <Paper elevation={menuProps.elevation} {...(menuProps?.slotProps?.paper as PaperProps) || {}}>\n <MenuList\n id={subMenuId}\n aria-labelledby={menuItemId}\n role='menu'\n {...(menuProps?.slotProps?.list as MenuListProps) || {}}\n // What's under is not allowed to be overridden for now\n autoFocusItem\n onKeyDown={e => {\n if (e.key === 'ArrowLeft') {\n const { nativeEvent } = e as KeyboardEvent<HTMLUListElement> & {\n nativeEvent: KeyboardEvent & {\n // our custom flag to avoid duplicate handling in nested menus\n __nestedMenuArrowLeftHandled?: boolean;\n };\n };\n if (nativeEvent.__nestedMenuArrowLeftHandled) {\n // return early if we have already handled this event in a nested menu\n // prevents duplicate logic when the browser bubbles the same keypress through multiple nodes\n return;\n }\n if (!subMenuRef.current?.contains(e.target as Node)) {\n // confirm the event’s target is still inside this submenu;\n // if the keypress originated elsewhere, we don’t continue so other menus can handle it\n return;\n }\n // Mark this event as handled to prevent parent menus from also processing it\n nativeEvent.__nestedMenuArrowLeftHandled = true;\n // preventDefault is needed so the browser doesn’t do its own “arrow left” behavior (like moving the text caret\n // or changing focus) while the menu is managing the navigation. Without this, the closed submenu or focused item\n // might jump unexpectedly even though the menu logic is running.\n e.preventDefault();\n // stopPropagation stops the event from bubbling up to parent DOM nodes that might also have onKeyDown, which could\n // otherwise fight the menu’s own logic or trigger duplicate navigation even though we guard with __nestedMenuArrowLeftHandled\n e.stopPropagation();\n // stopImmediatePropagation keeps any other keydown handlers registered on this same DOM node from running after ours.\n // This is preventing all submenus to close when pressing ArrowLeft in a, say, third level menu. With this, ArrowLeft will only\n // close the current submenu. The __nestedMenuArrowLeftHandled flag only guards against bubbling; this stopImmediatePropagation()\n // ensures no other handlers wired to the same node interfere once we decide to close and focus.\n nativeEvent.stopImmediatePropagation();\n // close the sub menu\n handleClose();\n // move focus back to the parent MenuItem, letting the user continue navigation up the menu hierarchy\n menuItemRef.current?.focus();\n }\n }}\n >\n {renderedSubMenuItems}\n </MenuList>\n </Paper>\n </Fade>\n )}\n </Popper>\n </>\n );\n};\n","'use client';\n\nexport { createSvgIcon as default } from '@mui/material/utils';","\"use client\";\n\nimport createSvgIcon from \"./utils/createSvgIcon.js\";\nimport { jsx as _jsx } from \"react/jsx-runtime\";\nexport default createSvgIcon(/*#__PURE__*/_jsx(\"path\", {\n d: \"m10 17 5-5-5-5z\"\n}), 'ArrowRight');","import { Stack, styled } from '@mui/material';\nimport Fade from '@mui/material/Fade';\n\nexport const CLOSE_DELAY = 50;\nexport const transitionConfig = {\n type: Fade,\n timeout: { enter: CLOSE_DELAY + 50, exit: CLOSE_DELAY + 50 },\n};\nexport const DEFAULT_ELEVATION = 8; // this is also what MUI menu uses as default\n\nexport const MenuItemContent = styled(Stack)({\n flexDirection: 'row',\n alignItems: 'center',\n gap: '8px',\n padding: 0,\n});\n","import { Menu } from './Menu'\n\nexport type { MenuItem } from './Menu/types'\nexport default Menu\n"],"mappings":"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","names":["Divider","MuiMenuItem","useId","Typography","Fade","Fade","jsx","jsxs","useId","Divider","MuiMenuItem","Typography"]}
package/package.json CHANGED
@@ -9,7 +9,7 @@
9
9
  "bugs": {
10
10
  "url": "https://github.com/eggei/better-mui-menu/issues"
11
11
  },
12
- "version": "1.0.8",
12
+ "version": "1.1.0",
13
13
  "type": "module",
14
14
  "sideEffects": false,
15
15
  "files": [