@aurora-ds/components 1.7.19 → 1.7.21

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/cjs/index.js CHANGED
@@ -3561,6 +3561,10 @@ const MENU_MIN_WIDTH_PX = 224;
3561
3561
  */
3562
3562
  const useMenuPosition = ({ anchorEl, open, menuRef, minWidth, gap = 4, placement = 'bottom', }) => {
3563
3563
  const [style, setStyle] = React.useState({});
3564
+ // Stays false until the rAF second pass has run with the real panel dimensions.
3565
+ // Keeps the panel invisible during the initial style={} state and the first
3566
+ // pass (menuHeight = 0) to prevent the position-jump flickering.
3567
+ const [isPositioned, setIsPositioned] = React.useState(false);
3564
3568
  const computePosition = React.useCallback(() => {
3565
3569
  if (!anchorEl) {
3566
3570
  return;
@@ -3641,14 +3645,19 @@ const useMenuPosition = ({ anchorEl, open, menuRef, minWidth, gap = 4, placement
3641
3645
  }
3642
3646
  else {
3643
3647
  setStyle({});
3648
+ setIsPositioned(false);
3644
3649
  }
3645
3650
  }, [open, computePosition]);
3646
- // Second pass: recompute after the panel renders to get actual height/width
3651
+ // Second pass: recompute after the panel renders to get actual height/width,
3652
+ // then mark as positioned so the panel becomes visible.
3647
3653
  React.useEffect(() => {
3648
3654
  if (!open) {
3649
3655
  return;
3650
3656
  }
3651
- const id = requestAnimationFrame(computePosition);
3657
+ const id = requestAnimationFrame(() => {
3658
+ computePosition();
3659
+ setIsPositioned(true);
3660
+ });
3652
3661
  return () => cancelAnimationFrame(id);
3653
3662
  }, [open, computePosition]);
3654
3663
  // Keep the menu glued to its anchor on scroll (nested containers) and resize.
@@ -3663,7 +3672,7 @@ const useMenuPosition = ({ anchorEl, open, menuRef, minWidth, gap = 4, placement
3663
3672
  window.removeEventListener('resize', computePosition);
3664
3673
  };
3665
3674
  }, [open, computePosition]);
3666
- return { style };
3675
+ return { style: { ...style, visibility: isPositioned ? 'visible' : 'hidden' } };
3667
3676
  };
3668
3677
 
3669
3678
  /** Custom DOM event fired on a submenu trigger item to request it opens. */
@@ -3987,7 +3996,7 @@ const HOVER_CLOSE_DELAY_MS = 160;
3987
3996
  * focus restoration, parent-keyboard pausing and the configurable close-on-click
3988
3997
  * behaviour.
3989
3998
  */
3990
- const useMenuItem = ({ ref, role, hasSubmenu, disabled, onClick, closeOnClick, }) => {
3999
+ const useMenuItem = ({ ref, role, hasSubmenu, disabled, onClick, closeOnClick, submenuTrigger = 'hover', }) => {
3991
4000
  const { setChildOpen, closeMenu } = React.useContext(MenuContext);
3992
4001
  const liRef = React.useRef(null);
3993
4002
  const mergedRef = useMergedRefs(ref, liRef);
@@ -4047,14 +4056,20 @@ const useMenuItem = ({ ref, role, hasSubmenu, disabled, onClick, closeOnClick, }
4047
4056
  return;
4048
4057
  }
4049
4058
  if (hasSubmenu) {
4050
- openSubmenu();
4059
+ if (submenuTrigger === 'click') {
4060
+ // Toggle: click again closes the submenu.
4061
+ setSubmenuOpen((prev) => !prev);
4062
+ }
4063
+ else {
4064
+ openSubmenu();
4065
+ }
4051
4066
  return;
4052
4067
  }
4053
4068
  onClick?.(event);
4054
4069
  if (shouldCloseOnClick) {
4055
4070
  closeMenu?.();
4056
4071
  }
4057
- }, [disabled, hasSubmenu, openSubmenu, onClick, shouldCloseOnClick, closeMenu]);
4072
+ }, [disabled, hasSubmenu, submenuTrigger, openSubmenu, onClick, shouldCloseOnClick, closeMenu]);
4058
4073
  return {
4059
4074
  liRef,
4060
4075
  mergedRef,
@@ -4064,6 +4079,7 @@ const useMenuItem = ({ ref, role, hasSubmenu, disabled, onClick, closeOnClick, }
4064
4079
  scheduleClose,
4065
4080
  clearTimers,
4066
4081
  closeSubmenu,
4082
+ submenuTrigger,
4067
4083
  };
4068
4084
  };
4069
4085
 
@@ -4138,13 +4154,14 @@ const MENU_ITEM_STYLES = theme.createStyles((theme) => {
4138
4154
  };
4139
4155
  }, { id: 'menu-item' });
4140
4156
 
4141
- const MenuItem = ({ ref, label, icon, iconColor, role = 'menuitem', checked, selected, focused, disabled, size = 'default', closeOnClick, submenu, submenuPlacement = 'right', onClick, ...rest }) => {
4157
+ const MenuItem = ({ ref, label, icon, iconColor, role = 'menuitem', checked, selected, focused, disabled, size = 'default', closeOnClick, submenu, submenuTrigger = 'click', submenuPlacement = 'right', onClick, ...rest }) => {
4142
4158
  const hasSubmenu = submenu !== undefined;
4143
4159
  const isCheckable = role === 'menuitemcheckbox' || role === 'menuitemradio';
4144
4160
  const isOption = role === 'option';
4145
4161
  const isHighlighted = isCheckable ? Boolean(checked) : Boolean(selected);
4146
- const { liRef, mergedRef, submenuOpen, handleClick, scheduleOpen, scheduleClose, clearTimers, closeSubmenu, } = useMenuItem({ ref, role, hasSubmenu, disabled, onClick, closeOnClick });
4147
- return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsxs("li", { ref: mergedRef, role: role, "aria-checked": isCheckable ? Boolean(checked) : undefined, "aria-selected": isOption ? Boolean(selected) : undefined, "aria-disabled": disabled, "aria-haspopup": hasSubmenu ? 'menu' : undefined, "aria-expanded": hasSubmenu ? submenuOpen : undefined, "data-selected": isHighlighted || undefined, "data-focused": focused || undefined, "data-disabled": disabled || undefined, className: MENU_ITEM_STYLES.root({ size }), onClick: handleClick, onMouseEnter: hasSubmenu && !disabled ? scheduleOpen : undefined, onMouseLeave: hasSubmenu ? scheduleClose : undefined, ...rest, children: [isCheckable && (jsxRuntime.jsxs("span", { className: MENU_ITEM_STYLES.indicator, "aria-hidden": true, children: [checked && role === 'menuitemcheckbox' && (jsxRuntime.jsx(Icon, { icon: CheckIcon, size: size === 'default' ? 'sm' : 'md', strokeColor: 'primaryMain' })), checked && role === 'menuitemradio' && (jsxRuntime.jsx("span", { className: MENU_ITEM_STYLES.radioDot }))] })), icon !== undefined && (jsxRuntime.jsx(Icon, { icon: icon, size: 'sm', strokeColor: iconColor ?? (isHighlighted ? 'primaryMain' : 'textSecondary') })), jsxRuntime.jsx(Text, { variant: 'span', fontSize: 'sm', className: MENU_ITEM_STYLES.label, children: label }), hasSubmenu && (jsxRuntime.jsx("span", { className: MENU_ITEM_STYLES.submenuChevron, "aria-hidden": true, children: jsxRuntime.jsx(Icon, { icon: ChevronRightIcon, size: 'sm', strokeColor: 'textTertiary' }) }))] }), hasSubmenu && (jsxRuntime.jsx(MenuPanel, { open: submenuOpen, onClose: () => closeSubmenu(true), onArrowLeft: () => closeSubmenu(true), anchorEl: liRef.current, placement: submenuPlacement, isSubmenu: true, "aria-label": label, onMouseEnter: clearTimers, onMouseLeave: scheduleClose, children: submenu }))] }));
4162
+ const { liRef, mergedRef, submenuOpen, handleClick, scheduleOpen, scheduleClose, clearTimers, closeSubmenu, } = useMenuItem({ ref, role, hasSubmenu, disabled, onClick, closeOnClick, submenuTrigger });
4163
+ const isHoverTrigger = submenuTrigger === 'hover';
4164
+ return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsxs("li", { ref: mergedRef, role: role, "aria-checked": isCheckable ? Boolean(checked) : undefined, "aria-selected": isOption ? Boolean(selected) : undefined, "aria-disabled": disabled, "aria-haspopup": hasSubmenu ? 'menu' : undefined, "aria-expanded": hasSubmenu ? submenuOpen : undefined, "data-selected": isHighlighted || undefined, "data-focused": focused || undefined, "data-disabled": disabled || undefined, className: MENU_ITEM_STYLES.root({ size }), onClick: handleClick, onMouseEnter: hasSubmenu && !disabled && isHoverTrigger ? scheduleOpen : undefined, onMouseLeave: hasSubmenu && isHoverTrigger ? scheduleClose : undefined, ...rest, children: [isCheckable && (jsxRuntime.jsxs("span", { className: MENU_ITEM_STYLES.indicator, "aria-hidden": true, children: [checked && role === 'menuitemcheckbox' && (jsxRuntime.jsx(Icon, { icon: CheckIcon, size: size === 'default' ? 'sm' : 'md', strokeColor: 'primaryMain' })), checked && role === 'menuitemradio' && (jsxRuntime.jsx("span", { className: MENU_ITEM_STYLES.radioDot }))] })), icon !== undefined && (jsxRuntime.jsx(Icon, { icon: icon, size: 'sm', strokeColor: iconColor ?? (isHighlighted ? 'primaryMain' : 'textSecondary') })), jsxRuntime.jsx(Text, { variant: 'span', fontSize: 'sm', className: MENU_ITEM_STYLES.label, children: label }), hasSubmenu && (jsxRuntime.jsx("span", { className: MENU_ITEM_STYLES.submenuChevron, "aria-hidden": true, children: jsxRuntime.jsx(Icon, { icon: ChevronRightIcon, size: 'sm', strokeColor: 'textTertiary' }) }))] }), hasSubmenu && (jsxRuntime.jsx(MenuPanel, { open: submenuOpen, onClose: () => closeSubmenu(true), onArrowLeft: () => closeSubmenu(true), anchorEl: liRef.current, placement: submenuPlacement, isSubmenu: true, "aria-label": label, onMouseEnter: isHoverTrigger ? clearTimers : undefined, onMouseLeave: isHoverTrigger ? scheduleClose : undefined, children: submenu }))] }));
4148
4165
  };
4149
4166
  MenuItem.displayName = 'MenuItem';
4150
4167