@salt-ds/core 1.73.0 → 1.75.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.
Files changed (127) hide show
  1. package/CHANGELOG.md +83 -0
  2. package/css/salt-core.css +283 -50
  3. package/dist-cjs/dialog/Dialog.css.js +1 -1
  4. package/dist-cjs/drawer/Drawer.css.js +1 -1
  5. package/dist-cjs/drawer/Drawer.js +54 -6
  6. package/dist-cjs/drawer/Drawer.js.map +1 -1
  7. package/dist-cjs/drawer/DrawerContext.js +2 -0
  8. package/dist-cjs/drawer/DrawerContext.js.map +1 -1
  9. package/dist-cjs/drawer/DrawerFooter.css.js +1 -1
  10. package/dist-cjs/drawer/DrawerHeader.css.js +1 -1
  11. package/dist-cjs/drawer/DrawerHeader.js +6 -3
  12. package/dist-cjs/drawer/DrawerHeader.js.map +1 -1
  13. package/dist-cjs/drawer/internal/DrawerResizeGuide.css.js +6 -0
  14. package/dist-cjs/drawer/internal/DrawerResizeGuide.css.js.map +1 -0
  15. package/dist-cjs/drawer/internal/DrawerResizeGuide.js +44 -0
  16. package/dist-cjs/drawer/internal/DrawerResizeGuide.js.map +1 -0
  17. package/dist-cjs/drawer/internal/DrawerResizeHandle.css.js +6 -0
  18. package/dist-cjs/drawer/internal/DrawerResizeHandle.css.js.map +1 -0
  19. package/dist-cjs/drawer/internal/DrawerResizeHandle.js +43 -0
  20. package/dist-cjs/drawer/internal/DrawerResizeHandle.js.map +1 -0
  21. package/dist-cjs/drawer/internal/useDrawerResize.js +519 -0
  22. package/dist-cjs/drawer/internal/useDrawerResize.js.map +1 -0
  23. package/dist-cjs/interactable-card/InteractableCard.js +2 -1
  24. package/dist-cjs/interactable-card/InteractableCard.js.map +1 -1
  25. package/dist-cjs/link-button/LinkButton.css.js +1 -1
  26. package/dist-cjs/mega-menu/useMegaMenuNavigation.js +11 -20
  27. package/dist-cjs/mega-menu/useMegaMenuNavigation.js.map +1 -1
  28. package/dist-cjs/menu/MenuAlignmentContext.js +55 -0
  29. package/dist-cjs/menu/MenuAlignmentContext.js.map +1 -0
  30. package/dist-cjs/menu/MenuBase.js +9 -3
  31. package/dist-cjs/menu/MenuBase.js.map +1 -1
  32. package/dist-cjs/menu/MenuGroup.js +42 -3
  33. package/dist-cjs/menu/MenuGroup.js.map +1 -1
  34. package/dist-cjs/menu/MenuGroupContext.js +27 -0
  35. package/dist-cjs/menu/MenuGroupContext.js.map +1 -0
  36. package/dist-cjs/menu/MenuItem.css.js +1 -1
  37. package/dist-cjs/menu/MenuItem.js +176 -50
  38. package/dist-cjs/menu/MenuItem.js.map +1 -1
  39. package/dist-cjs/menu/MenuPanel.js +12 -3
  40. package/dist-cjs/menu/MenuPanel.js.map +1 -1
  41. package/dist-cjs/menu/MenuPanelContext.js +3 -1
  42. package/dist-cjs/menu/MenuPanelContext.js.map +1 -1
  43. package/dist-cjs/pill-input/PillInput.css.js +1 -1
  44. package/dist-cjs/semantic-icon-provider/SemanticIconProvider.js +2 -2
  45. package/dist-cjs/semantic-icon-provider/SemanticIconProvider.js.map +1 -1
  46. package/dist-cjs/stepper/Step.js +12 -1
  47. package/dist-cjs/stepper/Step.js.map +1 -1
  48. package/dist-cjs/stepper/internal/StepConnector.css.js +1 -1
  49. package/dist-cjs/stepper/internal/StepText.css.js +1 -1
  50. package/dist-cjs/stepper/internal/StepText.js +4 -1
  51. package/dist-cjs/stepper/internal/StepText.js.map +1 -1
  52. package/dist-cjs/stepper/internal/hasActiveStep.js +12 -0
  53. package/dist-cjs/stepper/internal/hasActiveStep.js.map +1 -0
  54. package/dist-cjs/toggle-button/ToggleButton.css.js +1 -1
  55. package/dist-cjs/tree/TreeNodeTrigger.css.js +1 -1
  56. package/dist-cjs/tree/TreeNodeTrigger.js +1 -2
  57. package/dist-cjs/tree/TreeNodeTrigger.js.map +1 -1
  58. package/dist-es/dialog/Dialog.css.js +1 -1
  59. package/dist-es/drawer/Drawer.css.js +1 -1
  60. package/dist-es/drawer/Drawer.js +54 -6
  61. package/dist-es/drawer/Drawer.js.map +1 -1
  62. package/dist-es/drawer/DrawerContext.js +2 -0
  63. package/dist-es/drawer/DrawerContext.js.map +1 -1
  64. package/dist-es/drawer/DrawerFooter.css.js +1 -1
  65. package/dist-es/drawer/DrawerHeader.css.js +1 -1
  66. package/dist-es/drawer/DrawerHeader.js +6 -3
  67. package/dist-es/drawer/DrawerHeader.js.map +1 -1
  68. package/dist-es/drawer/internal/DrawerResizeGuide.css.js +4 -0
  69. package/dist-es/drawer/internal/DrawerResizeGuide.css.js.map +1 -0
  70. package/dist-es/drawer/internal/DrawerResizeGuide.js +42 -0
  71. package/dist-es/drawer/internal/DrawerResizeGuide.js.map +1 -0
  72. package/dist-es/drawer/internal/DrawerResizeHandle.css.js +4 -0
  73. package/dist-es/drawer/internal/DrawerResizeHandle.css.js.map +1 -0
  74. package/dist-es/drawer/internal/DrawerResizeHandle.js +41 -0
  75. package/dist-es/drawer/internal/DrawerResizeHandle.js.map +1 -0
  76. package/dist-es/drawer/internal/useDrawerResize.js +517 -0
  77. package/dist-es/drawer/internal/useDrawerResize.js.map +1 -0
  78. package/dist-es/interactable-card/InteractableCard.js +2 -1
  79. package/dist-es/interactable-card/InteractableCard.js.map +1 -1
  80. package/dist-es/link-button/LinkButton.css.js +1 -1
  81. package/dist-es/mega-menu/useMegaMenuNavigation.js +11 -20
  82. package/dist-es/mega-menu/useMegaMenuNavigation.js.map +1 -1
  83. package/dist-es/menu/MenuAlignmentContext.js +50 -0
  84. package/dist-es/menu/MenuAlignmentContext.js.map +1 -0
  85. package/dist-es/menu/MenuBase.js +9 -3
  86. package/dist-es/menu/MenuBase.js.map +1 -1
  87. package/dist-es/menu/MenuGroup.js +44 -5
  88. package/dist-es/menu/MenuGroup.js.map +1 -1
  89. package/dist-es/menu/MenuGroupContext.js +23 -0
  90. package/dist-es/menu/MenuGroupContext.js.map +1 -0
  91. package/dist-es/menu/MenuItem.css.js +1 -1
  92. package/dist-es/menu/MenuItem.js +177 -51
  93. package/dist-es/menu/MenuItem.js.map +1 -1
  94. package/dist-es/menu/MenuPanel.js +12 -3
  95. package/dist-es/menu/MenuPanel.js.map +1 -1
  96. package/dist-es/menu/MenuPanelContext.js +3 -1
  97. package/dist-es/menu/MenuPanelContext.js.map +1 -1
  98. package/dist-es/pill-input/PillInput.css.js +1 -1
  99. package/dist-es/semantic-icon-provider/SemanticIconProvider.js +3 -3
  100. package/dist-es/semantic-icon-provider/SemanticIconProvider.js.map +1 -1
  101. package/dist-es/stepper/Step.js +12 -1
  102. package/dist-es/stepper/Step.js.map +1 -1
  103. package/dist-es/stepper/internal/StepConnector.css.js +1 -1
  104. package/dist-es/stepper/internal/StepText.css.js +1 -1
  105. package/dist-es/stepper/internal/StepText.js +4 -1
  106. package/dist-es/stepper/internal/StepText.js.map +1 -1
  107. package/dist-es/stepper/internal/hasActiveStep.js +10 -0
  108. package/dist-es/stepper/internal/hasActiveStep.js.map +1 -0
  109. package/dist-es/toggle-button/ToggleButton.css.js +1 -1
  110. package/dist-es/tree/TreeNodeTrigger.css.js +1 -1
  111. package/dist-es/tree/TreeNodeTrigger.js +1 -2
  112. package/dist-es/tree/TreeNodeTrigger.js.map +1 -1
  113. package/dist-types/drawer/Drawer.d.ts +6 -0
  114. package/dist-types/drawer/DrawerContext.d.ts +3 -0
  115. package/dist-types/drawer/DrawerHeader.d.ts +1 -1
  116. package/dist-types/drawer/internal/DrawerResizeGuide.d.ts +7 -0
  117. package/dist-types/drawer/internal/DrawerResizeHandle.d.ts +8 -0
  118. package/dist-types/drawer/internal/index.d.ts +3 -0
  119. package/dist-types/drawer/internal/useDrawerResize.d.ts +34 -0
  120. package/dist-types/menu/MenuAlignmentContext.d.ts +14 -0
  121. package/dist-types/menu/MenuGroup.d.ts +26 -4
  122. package/dist-types/menu/MenuGroupContext.d.ts +10 -0
  123. package/dist-types/menu/MenuItem.d.ts +4 -0
  124. package/dist-types/menu/MenuPanelContext.d.ts +2 -0
  125. package/dist-types/stepper/internal/StepText.d.ts +1 -1
  126. package/dist-types/stepper/internal/hasActiveStep.d.ts +2 -0
  127. package/package.json +2 -2
@@ -1 +1 @@
1
- {"version":3,"file":"InteractableCard.js","sources":["../src/interactable-card/InteractableCard.tsx"],"sourcesContent":["import { useComponentCssInjection } from \"@salt-ds/styles\";\nimport { useWindow } from \"@salt-ds/window\";\nimport { clsx } from \"clsx\";\nimport {\n type ComponentPropsWithoutRef,\n forwardRef,\n type MouseEvent,\n type SyntheticEvent,\n useRef,\n} from \"react\";\nimport { hasCardSection } from \"../card/hasCardSection\";\nimport {\n capitalize,\n makePrefixer,\n useControlled,\n useForkRef,\n useIsomorphicLayoutEffect,\n} from \"../utils\";\nimport interactableCardCss from \"./InteractableCard.css\";\nimport {\n type InteractableCardValue,\n useInteractableCardGroup,\n} from \"./InteractableCardGroupContext\";\nimport { useInteractableCard } from \"./useInteractableCard\";\n\nconst withBaseName = makePrefixer(\"saltInteractableCard\");\n\nexport interface InteractableCardProps extends ComponentPropsWithoutRef<\"div\"> {\n /**\n * If provided an accent is shown in the specified position.\n */\n accent?: \"bottom\" | \"top\" | \"left\" | \"right\";\n /**\n * Visual elevation.\n */\n elevation?: \"flat\" | \"raised\";\n /**\n * Border color strength.\n */\n borderColor?: \"strong\" | \"subtle\" | \"none\";\n /**\n * @deprecated since 1.23.0. Use the `accent` prop instead.\n */\n accentPlacement?: \"bottom\" | \"top\" | \"left\" | \"right\";\n /**\n * If `true`, the card will be disabled.\n */\n disabled?: boolean;\n /**\n * Callback fired when the selection changes.\n * @param event\n */\n onChange?: (event: SyntheticEvent<HTMLDivElement>) => void;\n /**\n * Styling variant; defaults to \"primary\".\n */\n variant?: \"primary\" | \"secondary\" | \"tertiary\";\n /**\n * Value of card (for selectable use case).\n */\n value?: InteractableCardValue;\n}\n\nexport const InteractableCard = forwardRef<\n HTMLDivElement,\n InteractableCardProps\n>(function InteractableCard(props, ref) {\n const {\n accent,\n accentPlacement,\n borderColor,\n children,\n className,\n disabled: disabledProp,\n elevation = \"raised\",\n variant = \"primary\",\n value,\n onBlur,\n onChange,\n onClick,\n onKeyUp,\n onKeyDown,\n ...rest\n } = props;\n\n const targetWindow = useWindow();\n useComponentCssInjection({\n testId: \"salt-interactable-card\",\n css: interactableCardCss,\n window: targetWindow,\n });\n\n const interactableCardGroup = useInteractableCardGroup();\n\n const interactableCardGroupSelected =\n interactableCardGroup?.isSelected(value);\n\n const disabled = interactableCardGroup?.disabled || disabledProp;\n\n const [selected, setSelected] = useControlled({\n controlled: interactableCardGroupSelected,\n default: Boolean(false),\n name: \"InteractableCard\",\n state: \"selected\",\n });\n\n const role = interactableCardGroup\n ? interactableCardGroup.multiSelect\n ? \"checkbox\"\n : \"radio\"\n : \"button\";\n\n const isMultiselect = interactableCardGroup?.multiSelect;\n\n const isFirstChild = interactableCardGroup?.isFirstChild(value);\n\n const ariaChecked =\n role === \"radio\" || role === \"checkbox\" ? selected : undefined;\n\n const accentValue = accent || accentPlacement;\n\n const handleClick = (event: MouseEvent<HTMLDivElement>) => {\n if (disabled) {\n return;\n }\n\n if (interactableCardGroup) {\n interactableCardGroup.select(event, value);\n setSelected(!selected);\n }\n onChange?.(event);\n onClick?.(event);\n };\n\n // Disabled cards omit tabIndex so they can't receive focus, matching native disabled controls.\n let tabIndex: number | undefined;\n\n if (disabled) {\n tabIndex = undefined;\n } else if (interactableCardGroup) {\n if (isMultiselect) {\n tabIndex = 0; // All items focusable in multi-select\n } else {\n // Single select: only the selected card, or the first enabled card when no enabled card is selected, is focusable\n tabIndex = selected ? 0 : -1;\n // Fall back to the value for custom providers without hasEnabledSelection.\n const hasEnabledSelection =\n interactableCardGroup.hasEnabledSelection ??\n Boolean(interactableCardGroup.value);\n if (!hasEnabledSelection && isFirstChild) {\n tabIndex = 0;\n }\n }\n } else {\n tabIndex = 0;\n }\n\n const cardRef = useRef<HTMLDivElement>(null);\n const handleRef = useForkRef(ref, cardRef);\n const registerCard = interactableCardGroup?.registerCard;\n\n useIsomorphicLayoutEffect(() => {\n if (!disabled && cardRef.current && registerCard) {\n return registerCard(value, cardRef.current);\n }\n }, [disabled, registerCard, value]);\n\n const { active, cardProps } = useInteractableCard({\n disabled,\n onKeyUp,\n onKeyDown,\n onBlur,\n onClick,\n });\n\n const sectioned = hasCardSection(children);\n\n return (\n // biome-ignore lint/a11y/useAriaPropsSupportedByRole: Biome can't detect the role provided by the role variable. aria-checked is only used when the role is appropriate.\n // biome-ignore lint/a11y/useKeyWithClickEvents: Keyboard event handlers are provided by cardProps.\n <div\n {...cardProps}\n role={role}\n aria-checked={ariaChecked}\n aria-disabled={disabled}\n data-value={value}\n className={clsx(\n withBaseName(),\n withBaseName(variant),\n borderColor && withBaseName(`borderColor${capitalize(borderColor)}`),\n {\n [withBaseName(\"accent\")]: accentValue,\n [withBaseName(`accent${capitalize(accentValue ?? \"\")}`)]: accentValue,\n [withBaseName(elevation || \"\")]: elevation,\n [withBaseName(\"active\")]: role === \"button\" && active,\n [withBaseName(\"disabled\")]: disabled,\n [withBaseName(\"selected\")]: selected,\n [withBaseName(\"sectioned\")]: sectioned,\n },\n className,\n )}\n {...rest}\n onClick={handleClick}\n ref={handleRef}\n tabIndex={tabIndex}\n >\n {children}\n </div>\n );\n});\n"],"names":["makePrefixer","forwardRef","InteractableCard","useWindow","useComponentCssInjection","interactableCardCss","useInteractableCardGroup","useControlled","useRef","useForkRef","useIsomorphicLayoutEffect","useInteractableCard","hasCardSection","jsx","clsx","capitalize"],"mappings":"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"}
1
+ {"version":3,"file":"InteractableCard.js","sources":["../src/interactable-card/InteractableCard.tsx"],"sourcesContent":["import { useComponentCssInjection } from \"@salt-ds/styles\";\nimport { useWindow } from \"@salt-ds/window\";\nimport { clsx } from \"clsx\";\nimport {\n type ComponentPropsWithoutRef,\n forwardRef,\n type MouseEvent,\n type SyntheticEvent,\n useRef,\n} from \"react\";\nimport { hasCardSection } from \"../card/hasCardSection\";\nimport {\n capitalize,\n makePrefixer,\n useControlled,\n useForkRef,\n useIsomorphicLayoutEffect,\n} from \"../utils\";\nimport interactableCardCss from \"./InteractableCard.css\";\nimport {\n type InteractableCardValue,\n useInteractableCardGroup,\n} from \"./InteractableCardGroupContext\";\nimport { useInteractableCard } from \"./useInteractableCard\";\n\nconst withBaseName = makePrefixer(\"saltInteractableCard\");\n\nexport interface InteractableCardProps extends ComponentPropsWithoutRef<\"div\"> {\n /**\n * If provided an accent is shown in the specified position.\n */\n accent?: \"bottom\" | \"top\" | \"left\" | \"right\";\n /**\n * Visual elevation.\n */\n elevation?: \"flat\" | \"raised\";\n /**\n * Border color strength.\n */\n borderColor?: \"strong\" | \"subtle\" | \"none\";\n /**\n * @deprecated since 1.23.0. Use the `accent` prop instead.\n */\n accentPlacement?: \"bottom\" | \"top\" | \"left\" | \"right\";\n /**\n * If `true`, the card will be disabled.\n */\n disabled?: boolean;\n /**\n * Callback fired when the selection changes.\n * @param event\n */\n onChange?: (event: SyntheticEvent<HTMLDivElement>) => void;\n /**\n * Styling variant; defaults to \"primary\".\n */\n variant?: \"primary\" | \"secondary\" | \"tertiary\";\n /**\n * Value of card (for selectable use case).\n */\n value?: InteractableCardValue;\n}\n\nexport const InteractableCard = forwardRef<\n HTMLDivElement,\n InteractableCardProps\n>(function InteractableCard(props, ref) {\n const {\n accent,\n accentPlacement,\n borderColor,\n children,\n className,\n disabled: disabledProp,\n elevation = \"raised\",\n variant = \"primary\",\n value,\n onBlur,\n onChange,\n onClick,\n onKeyUp,\n onKeyDown,\n tabIndex: tabIndexProp,\n ...rest\n } = props;\n\n const targetWindow = useWindow();\n useComponentCssInjection({\n testId: \"salt-interactable-card\",\n css: interactableCardCss,\n window: targetWindow,\n });\n\n const interactableCardGroup = useInteractableCardGroup();\n\n const interactableCardGroupSelected =\n interactableCardGroup?.isSelected(value);\n\n const disabled = interactableCardGroup?.disabled || disabledProp;\n\n const [selected, setSelected] = useControlled({\n controlled: interactableCardGroupSelected,\n default: Boolean(false),\n name: \"InteractableCard\",\n state: \"selected\",\n });\n\n const role = interactableCardGroup\n ? interactableCardGroup.multiSelect\n ? \"checkbox\"\n : \"radio\"\n : \"button\";\n\n const isMultiselect = interactableCardGroup?.multiSelect;\n\n const isFirstChild = interactableCardGroup?.isFirstChild(value);\n\n const ariaChecked =\n role === \"radio\" || role === \"checkbox\" ? selected : undefined;\n\n const accentValue = accent || accentPlacement;\n\n const handleClick = (event: MouseEvent<HTMLDivElement>) => {\n if (disabled) {\n return;\n }\n\n if (interactableCardGroup) {\n interactableCardGroup.select(event, value);\n setSelected(!selected);\n }\n onChange?.(event);\n onClick?.(event);\n };\n\n // Disabled cards omit tabIndex so they can't receive focus, matching native disabled controls.\n let tabIndex: number | undefined;\n\n if (disabled) {\n tabIndex = undefined;\n } else if (interactableCardGroup) {\n if (isMultiselect) {\n tabIndex = 0; // All items focusable in multi-select\n } else {\n // Single select: only the selected card, or the first enabled card when no enabled card is selected, is focusable\n tabIndex = selected ? 0 : -1;\n // Fall back to the value for custom providers without hasEnabledSelection.\n const hasEnabledSelection =\n interactableCardGroup.hasEnabledSelection ??\n Boolean(interactableCardGroup.value);\n if (!hasEnabledSelection && isFirstChild) {\n tabIndex = 0;\n }\n }\n } else {\n tabIndex = 0;\n }\n\n const cardRef = useRef<HTMLDivElement>(null);\n const handleRef = useForkRef(ref, cardRef);\n const registerCard = interactableCardGroup?.registerCard;\n\n useIsomorphicLayoutEffect(() => {\n if (!disabled && cardRef.current && registerCard) {\n return registerCard(value, cardRef.current);\n }\n }, [disabled, registerCard, value]);\n\n const { active, cardProps } = useInteractableCard({\n disabled,\n onKeyUp,\n onKeyDown,\n onBlur,\n onClick,\n });\n\n const sectioned = hasCardSection(children);\n\n return (\n // biome-ignore lint/a11y/useAriaPropsSupportedByRole: Biome can't detect the role provided by the role variable. aria-checked is only used when the role is appropriate.\n // biome-ignore lint/a11y/useKeyWithClickEvents: Keyboard event handlers are provided by cardProps.\n <div\n {...cardProps}\n role={role}\n aria-checked={ariaChecked}\n aria-disabled={disabled}\n data-value={value}\n className={clsx(\n withBaseName(),\n withBaseName(variant),\n borderColor && withBaseName(`borderColor${capitalize(borderColor)}`),\n {\n [withBaseName(\"accent\")]: accentValue,\n [withBaseName(`accent${capitalize(accentValue ?? \"\")}`)]: accentValue,\n [withBaseName(elevation || \"\")]: elevation,\n [withBaseName(\"active\")]: role === \"button\" && active,\n [withBaseName(\"disabled\")]: disabled,\n [withBaseName(\"selected\")]: selected,\n [withBaseName(\"sectioned\")]: sectioned,\n },\n className,\n )}\n {...rest}\n onClick={handleClick}\n ref={handleRef}\n tabIndex={tabIndexProp ?? tabIndex}\n >\n {children}\n </div>\n );\n});\n"],"names":["makePrefixer","forwardRef","InteractableCard","useWindow","useComponentCssInjection","interactableCardCss","useInteractableCardGroup","useControlled","useRef","useForkRef","useIsomorphicLayoutEffect","useInteractableCard","hasCardSection","jsx","clsx","capitalize"],"mappings":"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"}
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var css_248z = ".saltLinkButton {\n --linkButton-borderWidth: var(--salt-size-fixed-100);\n\n align-items: var(--saltLinkButton-alignItems, center);\n appearance: none;\n background: var(--saltLinkButton-background, var(--linkButton-background));\n border-color: var(--saltLinkButton-borderColor, var(--linkButton-borderColor, transparent));\n border-style: var(--saltLinkButton-borderStyle, solid);\n border-width: var(--saltLinkButton-borderWidth, var(--linkButton-borderWidth));\n border-radius: var(--saltLinkButton-borderRadius, var(--salt-palette-corner-weak, 0));\n color: var(--saltLinkButton-text-color, var(--linkButton-text-color));\n display: inline-flex;\n gap: var(--salt-spacing-50);\n justify-content: var(--saltLinkButton-justifyContent, center);\n font-size: var(--saltLinkButton-fontSize, var(--salt-text-fontSize));\n font-family: var(--saltLinkButton-fontFamily, var(--salt-text-action-fontFamily));\n line-height: var(--saltLinkButton-lineHeight, var(--salt-text-lineHeight));\n letter-spacing: var(--saltLinkButton-letterSpacing, var(--salt-text-action-letterSpacing));\n text-transform: var(--saltLinkButton-textTransform, var(--salt-text-action-textTransform));\n padding: 0 var(--saltLinkButton-padding, calc(var(--salt-spacing-100) - var(--saltLinkButton-borderWidth, var(--linkButton-borderWidth))));\n margin: var(--saltLinkButton-margin, 0);\n height: var(--saltLinkButton-height, var(--salt-size-base));\n min-width: var(--saltLinkButton-minWidth, unset);\n position: relative;\n text-align: var(--saltLinkButton-textAlign, var(--salt-text-action-textAlign));\n text-decoration: var(--linkButton-textDecoration, var(--salt-typography-textDecoration-underline));\n text-underline-offset: var(--salt-spacing-fixed-200);\n transition: none;\n width: var(--saltLinkButton-width, auto);\n -webkit-appearance: none;\n -webkit-tap-highlight-color: transparent;\n /* Styles applied to align children*/\n font-weight: var(--saltLinkButton-fontWeight, var(--salt-text-action-fontWeight));\n}\n\n.saltLinkButton-underlineDefault {\n --linkButton-textDecoration: var(--salt-typography-textDecoration-underline);\n --linkButton-textDecoration-hover: var(--salt-typography-textDecoration-none);\n --linkButton-textDecoration-focus: var(--linkButton-textDecoration-hover);\n}\n\n.saltLinkButton-underlineNever {\n --linkButton-textDecoration: var(--salt-typography-textDecoration-none);\n --linkButton-textDecoration-hover: var(--salt-typography-textDecoration-none);\n --linkButton-textDecoration-focus: var(--salt-typography-textDecoration-none);\n}\n\n/* Class for ADA content - visually hidden but accessible to screen readers.\n Uses clip-path and prevents user selection so the text isn't included\n when users copy the link button's visible content. */\n.saltLinkButton-externalLinkADA {\n position: absolute;\n width: 1px;\n height: 1px;\n padding: 0;\n margin: -1px;\n overflow: hidden;\n clip: rect(0, 0, 0, 0);\n clip-path: inset(50%);\n white-space: nowrap;\n border: 0;\n user-select: none;\n -webkit-user-select: none;\n}\n\n@media (hover: hover) {\n /* Pseudo-class applied to the root element on hover when LinkButton is not active or disabled */\n .saltLinkButton:hover {\n background: var(--saltLinkButton-background-hover, var(--linkButton-background-hover));\n color: var(--saltLinkButton-text-color-hover, var(--linkButton-text-color-hover));\n border-color: var(--saltLinkButton-borderColor-hover, var(--linkButton-borderColor-hover));\n cursor: var(--salt-cursor-hover);\n text-decoration: var(--linkButton-textDecoration-hover, var(--salt-typography-textDecoration-none));\n }\n}\n\n/* Pseudo-class applied to the root element on focus */\n.saltLinkButton:focus-visible {\n outline: var(--salt-focused-outline);\n\n background: var(--saltLinkButton-background-hover, var(--linkButton-background-hover));\n color: var(--saltLinkButton-text-color-hover, var(--linkButton-text-color-hover));\n border-color: var(--saltLinkButton-borderColor-hover, var(--linkButton-borderColor-hover));\n text-decoration: var(--linkButton-textDecoration-focus, var(--salt-typography-textDecoration-none));\n}\n\n/* Pseudo-class applied to the root element when LinkButton is active */\n.saltLinkButton.saltLinkButton-active:focus-visible,\n.saltLinkButton:focus-visible:active,\n.saltLinkButton:active,\n.saltLinkButton.saltLinkButton-active {\n background: var(--saltLinkButton-background-active, var(--linkButton-background-active));\n color: var(--saltLinkButton-text-color-active, var(--linkButton-text-color-active));\n border-color: var(--saltLinkButton-borderColor-active, var(--linkButton-borderColor-active));\n cursor: var(--salt-cursor-active);\n}\n\n.saltLinkButton-neutral {\n --linkButton-text-color: var(--salt-actionable-subtle-foreground);\n --linkButton-text-color-hover: var(--salt-actionable-subtle-foreground-hover);\n --linkButton-text-color-active: var(--salt-actionable-subtle-foreground-active);\n --linkButton-background: var(--salt-actionable-subtle-background);\n --linkButton-background-hover: var(--salt-actionable-subtle-background-hover);\n --linkButton-background-active: var(--salt-actionable-subtle-background-active);\n --linkButton-borderColor: var(--salt-actionable-subtle-borderColor);\n --linkButton-borderColor-hover: var(--salt-actionable-subtle-borderColor-hover);\n --linkButton-borderColor-active: var(--salt-actionable-subtle-borderColor-active);\n}\n\n.saltLinkButton-accented {\n --linkButton-text-color: var(--salt-actionable-accented-subtle-foreground);\n --linkButton-text-color-hover: var(--salt-actionable-accented-subtle-foreground-hover);\n --linkButton-text-color-active: var(--salt-actionable-accented-subtle-foreground-active);\n --linkButton-background: var(--salt-actionable-accented-subtle-background);\n --linkButton-background-hover: var(--salt-actionable-accented-subtle-background-hover);\n --linkButton-background-active: var(--salt-actionable-accented-subtle-background-active);\n --linkButton-borderColor: var(--salt-actionable-accented-subtle-borderColor);\n --linkButton-borderColor-hover: var(--salt-actionable-accented-subtle-borderColor-hover);\n --linkButton-borderColor-active: var(--salt-actionable-accented-subtle-borderColor-active);\n}\n";
3
+ var css_248z = ".saltLinkButton {\n --linkButton-borderWidth: var(--salt-size-fixed-100);\n\n align-items: var(--saltLinkButton-alignItems, center);\n appearance: none;\n background: var(--saltLinkButton-background, var(--linkButton-background));\n border-color: var(--saltLinkButton-borderColor, var(--linkButton-borderColor, transparent));\n border-style: var(--saltLinkButton-borderStyle, solid);\n border-width: var(--saltLinkButton-borderWidth, var(--linkButton-borderWidth));\n border-radius: var(--saltLinkButton-borderRadius, var(--salt-palette-corner-weak, 0));\n box-sizing: border-box;\n color: var(--saltLinkButton-text-color, var(--linkButton-text-color));\n display: inline-flex;\n gap: var(--salt-spacing-50);\n justify-content: var(--saltLinkButton-justifyContent, center);\n font-size: var(--saltLinkButton-fontSize, var(--salt-text-fontSize));\n font-family: var(--saltLinkButton-fontFamily, var(--salt-text-action-fontFamily));\n line-height: var(--saltLinkButton-lineHeight, var(--salt-text-lineHeight));\n letter-spacing: var(--saltLinkButton-letterSpacing, var(--salt-text-action-letterSpacing));\n text-transform: var(--saltLinkButton-textTransform, var(--salt-text-action-textTransform));\n padding: 0 var(--saltLinkButton-padding, calc(var(--salt-spacing-100) - var(--saltLinkButton-borderWidth, var(--linkButton-borderWidth))));\n margin: var(--saltLinkButton-margin, 0);\n height: var(--saltLinkButton-height, var(--salt-size-base));\n min-width: var(--saltLinkButton-minWidth, unset);\n position: relative;\n text-align: var(--saltLinkButton-textAlign, var(--salt-text-action-textAlign));\n text-decoration: var(--linkButton-textDecoration, var(--salt-typography-textDecoration-underline));\n text-underline-offset: var(--salt-spacing-fixed-200);\n transition: none;\n width: var(--saltLinkButton-width, auto);\n -webkit-appearance: none;\n -webkit-tap-highlight-color: transparent;\n /* Styles applied to align children*/\n font-weight: var(--saltLinkButton-fontWeight, var(--salt-text-action-fontWeight));\n}\n\n.saltLinkButton-underlineDefault {\n --linkButton-textDecoration: var(--salt-typography-textDecoration-underline);\n --linkButton-textDecoration-hover: var(--salt-typography-textDecoration-none);\n --linkButton-textDecoration-focus: var(--linkButton-textDecoration-hover);\n}\n\n.saltLinkButton-underlineNever {\n --linkButton-textDecoration: var(--salt-typography-textDecoration-none);\n --linkButton-textDecoration-hover: var(--salt-typography-textDecoration-none);\n --linkButton-textDecoration-focus: var(--salt-typography-textDecoration-none);\n}\n\n/* Class for ADA content - visually hidden but accessible to screen readers.\n Uses clip-path and prevents user selection so the text isn't included\n when users copy the link button's visible content. */\n.saltLinkButton-externalLinkADA {\n position: absolute;\n width: 1px;\n height: 1px;\n padding: 0;\n margin: -1px;\n overflow: hidden;\n clip: rect(0, 0, 0, 0);\n clip-path: inset(50%);\n white-space: nowrap;\n border: 0;\n user-select: none;\n -webkit-user-select: none;\n}\n\n@media (hover: hover) {\n /* Pseudo-class applied to the root element on hover when LinkButton is not active or disabled */\n .saltLinkButton:hover {\n background: var(--saltLinkButton-background-hover, var(--linkButton-background-hover));\n color: var(--saltLinkButton-text-color-hover, var(--linkButton-text-color-hover));\n border-color: var(--saltLinkButton-borderColor-hover, var(--linkButton-borderColor-hover));\n cursor: var(--salt-cursor-hover);\n text-decoration: var(--linkButton-textDecoration-hover, var(--salt-typography-textDecoration-none));\n }\n}\n\n/* Pseudo-class applied to the root element on focus */\n.saltLinkButton:focus-visible {\n outline: var(--salt-focused-outline);\n\n background: var(--saltLinkButton-background-hover, var(--linkButton-background-hover));\n color: var(--saltLinkButton-text-color-hover, var(--linkButton-text-color-hover));\n border-color: var(--saltLinkButton-borderColor-hover, var(--linkButton-borderColor-hover));\n text-decoration: var(--linkButton-textDecoration-focus, var(--salt-typography-textDecoration-none));\n}\n\n/* Pseudo-class applied to the root element when LinkButton is active */\n.saltLinkButton.saltLinkButton-active:focus-visible,\n.saltLinkButton:focus-visible:active,\n.saltLinkButton:active,\n.saltLinkButton.saltLinkButton-active {\n background: var(--saltLinkButton-background-active, var(--linkButton-background-active));\n color: var(--saltLinkButton-text-color-active, var(--linkButton-text-color-active));\n border-color: var(--saltLinkButton-borderColor-active, var(--linkButton-borderColor-active));\n cursor: var(--salt-cursor-active);\n}\n\n.saltLinkButton-neutral {\n --linkButton-text-color: var(--salt-actionable-subtle-foreground);\n --linkButton-text-color-hover: var(--salt-actionable-subtle-foreground-hover);\n --linkButton-text-color-active: var(--salt-actionable-subtle-foreground-active);\n --linkButton-background: var(--salt-actionable-subtle-background);\n --linkButton-background-hover: var(--salt-actionable-subtle-background-hover);\n --linkButton-background-active: var(--salt-actionable-subtle-background-active);\n --linkButton-borderColor: var(--salt-actionable-subtle-borderColor);\n --linkButton-borderColor-hover: var(--salt-actionable-subtle-borderColor-hover);\n --linkButton-borderColor-active: var(--salt-actionable-subtle-borderColor-active);\n}\n\n.saltLinkButton-accented {\n --linkButton-text-color: var(--salt-actionable-accented-subtle-foreground);\n --linkButton-text-color-hover: var(--salt-actionable-accented-subtle-foreground-hover);\n --linkButton-text-color-active: var(--salt-actionable-accented-subtle-foreground-active);\n --linkButton-background: var(--salt-actionable-accented-subtle-background);\n --linkButton-background-hover: var(--salt-actionable-accented-subtle-background-hover);\n --linkButton-background-active: var(--salt-actionable-accented-subtle-background-active);\n --linkButton-borderColor: var(--salt-actionable-accented-subtle-borderColor);\n --linkButton-borderColor-hover: var(--salt-actionable-accented-subtle-borderColor-hover);\n --linkButton-borderColor-active: var(--salt-actionable-accented-subtle-borderColor-active);\n}\n";
4
4
 
5
5
  module.exports = css_248z;
6
6
  //# sourceMappingURL=LinkButton.css.js.map
@@ -6,7 +6,7 @@ const COLUMN_SELECTOR = "[data-mega-menu-column]";
6
6
  const ACTIONS_SELECTOR = "[data-mega-menu-actions]";
7
7
  const FOCUSABLE_SELECTOR = 'a[href], button:not([disabled]), [tabindex]:not([tabindex="-1"])';
8
8
  const SELF_CONSUMING_SELECTOR = 'input, textarea, select, [contenteditable], [role="combobox"], [role="listbox"], [role="slider"], [role="spinbutton"], [role="textbox"]';
9
- const HIDDEN_ANCESTOR_SELECTOR = '[aria-hidden="true"], [inert]';
9
+ const HIDDEN_ANCESTOR_SELECTOR = '[aria-hidden="true"], [inert], [data-floating-ui-focus-guard]';
10
10
  function queryFocusables(root) {
11
11
  return Array.from(
12
12
  root.querySelectorAll(FOCUSABLE_SELECTOR)
@@ -194,27 +194,18 @@ function handleArrow(key, cell, panel, context) {
194
194
  }
195
195
  return false;
196
196
  }
197
- function focusNextAfterPanel(context, panel) {
197
+ function findNextAfterPanel(context, panel) {
198
198
  var _a;
199
199
  const reference = context.elements.reference;
200
200
  const refFocusable = firstFocusable(reference) ?? reference;
201
201
  const nextLi = (_a = refFocusable == null ? void 0 : refFocusable.closest("li")) == null ? void 0 : _a.nextElementSibling;
202
202
  const nextSibling = nextLi instanceof HTMLElement ? firstFocusable(nextLi) : null;
203
- const nextOutside = nextSibling || (() => {
204
- const allFocusable = queryFocusables(
205
- panel.ownerDocument.documentElement
206
- ).filter((el) => !panel.contains(el));
207
- const idx = refFocusable ? allFocusable.indexOf(refFocusable) : -1;
208
- return idx >= 0 ? allFocusable[idx + 1] : void 0;
209
- })();
210
- if (nextOutside) {
211
- const view = panel.ownerDocument.defaultView;
212
- view == null ? void 0 : view.requestAnimationFrame(() => {
213
- view == null ? void 0 : view.requestAnimationFrame(() => {
214
- nextOutside.focus();
215
- });
216
- });
217
- }
203
+ if (nextSibling) return nextSibling;
204
+ const allFocusable = queryFocusables(
205
+ panel.ownerDocument.documentElement
206
+ ).filter((el) => !panel.contains(el));
207
+ const idx = refFocusable ? allFocusable.indexOf(refFocusable) : -1;
208
+ return idx >= 0 ? allFocusable[idx + 1] : void 0;
218
209
  }
219
210
  function useMegaMenuNavigation(context, props = {}) {
220
211
  const { enabled = true } = props;
@@ -226,7 +217,7 @@ function useMegaMenuNavigation(context, props = {}) {
226
217
  return {
227
218
  floating: {
228
219
  onKeyDown(event) {
229
- var _a, _b;
220
+ var _a, _b, _c;
230
221
  if (!open) return;
231
222
  const panel = event.currentTarget;
232
223
  const target = event.target;
@@ -248,10 +239,10 @@ function useMegaMenuNavigation(context, props = {}) {
248
239
  (_a = allCells[linearIndex - 1]) == null ? void 0 : _a.focus();
249
240
  }
250
241
  } else if (linearIndex === allCells.length - 1) {
242
+ (_b = findNextAfterPanel(context, panel)) == null ? void 0 : _b.focus();
251
243
  onOpenChange(false);
252
- focusNextAfterPanel(context, panel);
253
244
  } else {
254
- (_b = allCells[linearIndex + 1]) == null ? void 0 : _b.focus();
245
+ (_c = allCells[linearIndex + 1]) == null ? void 0 : _c.focus();
255
246
  }
256
247
  return;
257
248
  }
@@ -1 +1 @@
1
- {"version":3,"file":"useMegaMenuNavigation.js","sources":["../src/mega-menu/useMegaMenuNavigation.ts"],"sourcesContent":["import type { ElementProps, FloatingRootContext } from \"@floating-ui/react\";\nimport { useMemo } from \"react\";\n\nconst COLUMN_SELECTOR = \"[data-mega-menu-column]\";\nconst ACTIONS_SELECTOR = \"[data-mega-menu-actions]\";\n\nexport const FOCUSABLE_SELECTOR =\n 'a[href], button:not([disabled]), [tabindex]:not([tabindex=\"-1\"])';\n\n// Controls that own the arrow keys (caret, option lists, steppers); the engine\n// leaves their keys alone when focus is inside one.\nconst SELF_CONSUMING_SELECTOR =\n 'input, textarea, select, [contenteditable], [role=\"combobox\"], [role=\"listbox\"], [role=\"slider\"], [role=\"spinbutton\"], [role=\"textbox\"]';\n\n// aria-hidden / inert subtrees are out of the focus order; filtered by ancestor\n// lookup since `:not()` cannot match on an ancestor.\nconst HIDDEN_ANCESTOR_SELECTOR = '[aria-hidden=\"true\"], [inert]';\n\nfunction queryFocusables(root: HTMLElement): HTMLElement[] {\n return Array.from(\n root.querySelectorAll<HTMLElement>(FOCUSABLE_SELECTOR),\n ).filter((el) => !el.closest(HIDDEN_ANCESTOR_SELECTOR));\n}\n\nfunction firstFocusable(root: HTMLElement | null): HTMLElement | null {\n return root ? (queryFocusables(root)[0] ?? null) : null;\n}\n\ninterface NavModel {\n /** Columns (`data-mega-menu-column`) in DOM order, each with ≥1 cell. */\n columns: HTMLElement[];\n /** Full-width actions row; the bottom of the center area. */\n actions: HTMLElement[];\n}\n\n/** Build the navigation model from the panel DOM at keypress time. */\nfunction buildModel(panel: HTMLElement): NavModel {\n const columns = Array.from(\n panel.querySelectorAll<HTMLElement>(COLUMN_SELECTOR),\n ).filter((el) => queryFocusables(el).length > 0);\n\n const actions = Array.from(\n panel.querySelectorAll<HTMLElement>(ACTIONS_SELECTOR),\n ).filter((el) => queryFocusables(el).length > 0);\n\n return { columns, actions };\n}\n\nfunction focusTrigger(context: FloatingRootContext) {\n const reference = context.elements.reference as HTMLElement | null;\n (firstFocusable(reference) ?? reference)?.focus();\n}\n\n/** Exit to the next nav-bar trigger and close. Returns false when there is none. */\nfunction focusNextTriggerAndClose(context: FloatingRootContext): boolean {\n const reference = context.elements.reference as HTMLElement | null;\n const trigger = firstFocusable(reference) ?? reference;\n const li = trigger?.closest(\"li\");\n const next =\n li?.nextElementSibling instanceof HTMLElement\n ? firstFocusable(li.nextElementSibling)\n : null;\n if (next) {\n context.onOpenChange(false);\n next.focus();\n return true;\n }\n return false;\n}\n\n/** True when the grid has collapsed to one stacked column (small viewport). */\nfunction columnsStacked(columns: HTMLElement[]): boolean {\n if (columns.length < 2) return false;\n const first = columns[0].getBoundingClientRect();\n const second = columns[1].getBoundingClientRect();\n return second.top >= first.bottom - 1;\n}\n\n/** Stacked layout: all arrows degrade to prev/next over every cell. */\nfunction handleLinear(\n key: string,\n cell: HTMLElement,\n panel: HTMLElement,\n context: FloatingRootContext,\n): boolean {\n const cells = queryFocusables(panel);\n const index = cells.indexOf(cell);\n if (index === -1) return false;\n\n switch (key) {\n case \"ArrowDown\":\n case \"ArrowRight\": {\n if (index < cells.length - 1) {\n cells[index + 1].focus();\n }\n return true;\n }\n case \"ArrowUp\":\n case \"ArrowLeft\": {\n if (index > 0) {\n cells[index - 1].focus();\n } else {\n focusTrigger(context);\n }\n return true;\n }\n case \"Home\": {\n cells[0]?.focus();\n return true;\n }\n case \"End\": {\n cells[cells.length - 1]?.focus();\n return true;\n }\n default:\n return false;\n }\n}\n\n/** Arrow/Home/End movement from `cell`. Returns `true` when the key was consumed. */\nfunction handleArrow(\n key: string,\n cell: HTMLElement,\n panel: HTMLElement,\n context: FloatingRootContext,\n): boolean {\n const { columns, actions } = buildModel(panel);\n\n if (columnsStacked(columns)) {\n return handleLinear(key, cell, panel, context);\n }\n\n const column = cell.closest<HTMLElement>(COLUMN_SELECTOR);\n const actionsEl = cell.closest<HTMLElement>(ACTIONS_SELECTOR);\n\n if (column) {\n const colIndex = columns.indexOf(column);\n const cells = queryFocusables(column);\n const rowIndex = cells.indexOf(cell);\n\n switch (key) {\n case \"ArrowDown\": {\n if (rowIndex < cells.length - 1) {\n cells[rowIndex + 1].focus();\n } else if (colIndex < columns.length - 1) {\n firstFocusable(columns[colIndex + 1])?.focus();\n } else if (actions.length > 0) {\n firstFocusable(actions[0])?.focus();\n } else {\n focusNextTriggerAndClose(context);\n }\n return true;\n }\n case \"ArrowUp\": {\n if (rowIndex > 0) {\n cells[rowIndex - 1].focus();\n } else {\n focusTrigger(context);\n }\n return true;\n }\n case \"ArrowRight\": {\n if (colIndex < columns.length - 1) {\n firstFocusable(columns[colIndex + 1])?.focus();\n return true;\n }\n // Right border column: exit to the next trigger and close if available\n if (\n rowIndex === cells.length - 1 &&\n focusNextTriggerAndClose(context)\n ) {\n return true;\n }\n // Wrap to the current trigger and keep the menu open,\n // mirroring Left in the first column.\n focusTrigger(context);\n return true;\n }\n case \"ArrowLeft\": {\n if (colIndex > 0) {\n firstFocusable(columns[colIndex - 1])?.focus();\n } else {\n focusTrigger(context);\n }\n return true;\n }\n case \"Home\": {\n cells[0]?.focus();\n return true;\n }\n case \"End\": {\n cells[cells.length - 1]?.focus();\n return true;\n }\n default:\n return false;\n }\n }\n\n if (actionsEl) {\n const cells = queryFocusables(actionsEl);\n const index = cells.indexOf(cell);\n\n switch (key) {\n case \"ArrowRight\": {\n if (index < cells.length - 1) {\n cells[index + 1].focus();\n } else if (!focusNextTriggerAndClose(context)) {\n // Last action with no next trigger: wrap to the current trigger.\n focusTrigger(context);\n }\n return true;\n }\n case \"ArrowLeft\": {\n if (index > 0) {\n cells[index - 1].focus();\n } else if (cell === firstFocusable(panel)) {\n focusTrigger(context);\n }\n return true;\n }\n case \"ArrowUp\": {\n if (columns.length > 0) {\n const lastColumnCells = queryFocusables(columns[columns.length - 1]);\n lastColumnCells[lastColumnCells.length - 1]?.focus();\n } else {\n focusTrigger(context);\n }\n return true;\n }\n case \"ArrowDown\": {\n if (index === cells.length - 1) {\n focusNextTriggerAndClose(context);\n }\n return true;\n }\n case \"Home\": {\n cells[0]?.focus();\n return true;\n }\n case \"End\": {\n cells[cells.length - 1]?.focus();\n return true;\n }\n default:\n return false;\n }\n }\n\n return false;\n}\n\n/** Focus the first document-focusable after the panel, once it has unmounted. */\nfunction focusNextAfterPanel(context: FloatingRootContext, panel: HTMLElement) {\n const reference = context.elements.reference as HTMLElement | null;\n const refFocusable = firstFocusable(reference) ?? reference;\n\n const nextLi = refFocusable?.closest(\"li\")?.nextElementSibling;\n const nextSibling =\n nextLi instanceof HTMLElement ? firstFocusable(nextLi) : null;\n\n const nextOutside =\n nextSibling ||\n (() => {\n const allFocusable = queryFocusables(\n panel.ownerDocument.documentElement,\n ).filter((el) => !panel.contains(el));\n const idx = refFocusable ? allFocusable.indexOf(refFocusable) : -1;\n return idx >= 0 ? allFocusable[idx + 1] : undefined;\n })();\n\n if (nextOutside) {\n const view = panel.ownerDocument.defaultView;\n view?.requestAnimationFrame(() => {\n view?.requestAnimationFrame(() => {\n nextOutside.focus();\n });\n });\n }\n}\n\nexport interface UseMegaMenuNavigationProps {\n /**\n * Whether the interaction is enabled.\n * @default true\n */\n enabled?: boolean;\n}\n\n/**\n * Floating-ui interaction hook for mega menu keyboard navigation. Handles keys\n * on the panel only; the trigger keys are owned by `MegaMenuTrigger`.\n */\nexport function useMegaMenuNavigation(\n context: FloatingRootContext,\n props: UseMegaMenuNavigationProps = {},\n): ElementProps {\n const { enabled = true } = props;\n const { open, onOpenChange } = context;\n\n return useMemo(() => {\n if (!enabled) {\n return {};\n }\n\n return {\n floating: {\n onKeyDown(event: React.KeyboardEvent) {\n if (!open) return;\n\n const panel = event.currentTarget as HTMLElement;\n const target = event.target as HTMLElement;\n const { key } = event;\n\n const isArrowOrEdge =\n key === \"ArrowUp\" ||\n key === \"ArrowDown\" ||\n key === \"ArrowLeft\" ||\n key === \"ArrowRight\" ||\n key === \"Home\" ||\n key === \"End\";\n\n // A self-consuming control keeps its own navigation keys.\n if (isArrowOrEdge && target.closest(SELF_CONSUMING_SELECTOR)) {\n return;\n }\n\n const cell = target.closest<HTMLElement>(FOCUSABLE_SELECTOR);\n\n // Tab walks every cell in layout order; the panel is portaled, so the\n // boundary transitions are handled manually.\n if (key === \"Tab\") {\n const allCells = queryFocusables(panel);\n const linearIndex = cell ? allCells.indexOf(cell) : -1;\n if (linearIndex === -1) return;\n event.preventDefault();\n if (event.shiftKey) {\n if (linearIndex === 0) {\n focusTrigger(context);\n } else {\n allCells[linearIndex - 1]?.focus();\n }\n } else if (linearIndex === allCells.length - 1) {\n onOpenChange(false);\n focusNextAfterPanel(context, panel);\n } else {\n allCells[linearIndex + 1]?.focus();\n }\n return;\n }\n\n if (!cell || !isArrowOrEdge) return;\n\n if (handleArrow(key, cell, panel, context)) {\n event.preventDefault();\n }\n },\n },\n };\n }, [enabled, open, context, onOpenChange]);\n}\n\n/** Focus the first navigable item inside a mega menu panel, retrying until rendered. */\nexport function focusFirstItem(panel: HTMLElement, attempt = 0): void {\n const firstItem = firstFocusable(panel);\n\n if (firstItem) {\n firstItem.focus();\n return;\n }\n\n const view = panel.ownerDocument.defaultView;\n if (attempt < 3 && view) {\n view.requestAnimationFrame(() => focusFirstItem(panel, attempt + 1));\n }\n}\n"],"names":["useMemo"],"mappings":"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"}
1
+ {"version":3,"file":"useMegaMenuNavigation.js","sources":["../src/mega-menu/useMegaMenuNavigation.ts"],"sourcesContent":["import type { ElementProps, FloatingRootContext } from \"@floating-ui/react\";\nimport { useMemo } from \"react\";\n\nconst COLUMN_SELECTOR = \"[data-mega-menu-column]\";\nconst ACTIONS_SELECTOR = \"[data-mega-menu-actions]\";\n\nexport const FOCUSABLE_SELECTOR =\n 'a[href], button:not([disabled]), [tabindex]:not([tabindex=\"-1\"])';\n\n// Controls that own the arrow keys (caret, option lists, steppers); the engine\n// leaves their keys alone when focus is inside one.\nconst SELF_CONSUMING_SELECTOR =\n 'input, textarea, select, [contenteditable], [role=\"combobox\"], [role=\"listbox\"], [role=\"slider\"], [role=\"spinbutton\"], [role=\"textbox\"]';\n\n// aria-hidden / inert subtrees are out of the focus order; filtered by ancestor\n// lookup since `:not()` cannot match on an ancestor. Floating UI focus guards\n// are only aria-hidden outside Safari, so they are excluded explicitly.\nconst HIDDEN_ANCESTOR_SELECTOR =\n '[aria-hidden=\"true\"], [inert], [data-floating-ui-focus-guard]';\n\nfunction queryFocusables(root: HTMLElement): HTMLElement[] {\n return Array.from(\n root.querySelectorAll<HTMLElement>(FOCUSABLE_SELECTOR),\n ).filter((el) => !el.closest(HIDDEN_ANCESTOR_SELECTOR));\n}\n\nfunction firstFocusable(root: HTMLElement | null): HTMLElement | null {\n return root ? (queryFocusables(root)[0] ?? null) : null;\n}\n\ninterface NavModel {\n /** Columns (`data-mega-menu-column`) in DOM order, each with ≥1 cell. */\n columns: HTMLElement[];\n /** Full-width actions row; the bottom of the center area. */\n actions: HTMLElement[];\n}\n\n/** Build the navigation model from the panel DOM at keypress time. */\nfunction buildModel(panel: HTMLElement): NavModel {\n const columns = Array.from(\n panel.querySelectorAll<HTMLElement>(COLUMN_SELECTOR),\n ).filter((el) => queryFocusables(el).length > 0);\n\n const actions = Array.from(\n panel.querySelectorAll<HTMLElement>(ACTIONS_SELECTOR),\n ).filter((el) => queryFocusables(el).length > 0);\n\n return { columns, actions };\n}\n\nfunction focusTrigger(context: FloatingRootContext) {\n const reference = context.elements.reference as HTMLElement | null;\n (firstFocusable(reference) ?? reference)?.focus();\n}\n\n/** Exit to the next nav-bar trigger and close. Returns false when there is none. */\nfunction focusNextTriggerAndClose(context: FloatingRootContext): boolean {\n const reference = context.elements.reference as HTMLElement | null;\n const trigger = firstFocusable(reference) ?? reference;\n const li = trigger?.closest(\"li\");\n const next =\n li?.nextElementSibling instanceof HTMLElement\n ? firstFocusable(li.nextElementSibling)\n : null;\n if (next) {\n context.onOpenChange(false);\n next.focus();\n return true;\n }\n return false;\n}\n\n/** True when the grid has collapsed to one stacked column (small viewport). */\nfunction columnsStacked(columns: HTMLElement[]): boolean {\n if (columns.length < 2) return false;\n const first = columns[0].getBoundingClientRect();\n const second = columns[1].getBoundingClientRect();\n return second.top >= first.bottom - 1;\n}\n\n/** Stacked layout: all arrows degrade to prev/next over every cell. */\nfunction handleLinear(\n key: string,\n cell: HTMLElement,\n panel: HTMLElement,\n context: FloatingRootContext,\n): boolean {\n const cells = queryFocusables(panel);\n const index = cells.indexOf(cell);\n if (index === -1) return false;\n\n switch (key) {\n case \"ArrowDown\":\n case \"ArrowRight\": {\n if (index < cells.length - 1) {\n cells[index + 1].focus();\n }\n return true;\n }\n case \"ArrowUp\":\n case \"ArrowLeft\": {\n if (index > 0) {\n cells[index - 1].focus();\n } else {\n focusTrigger(context);\n }\n return true;\n }\n case \"Home\": {\n cells[0]?.focus();\n return true;\n }\n case \"End\": {\n cells[cells.length - 1]?.focus();\n return true;\n }\n default:\n return false;\n }\n}\n\n/** Arrow/Home/End movement from `cell`. Returns `true` when the key was consumed. */\nfunction handleArrow(\n key: string,\n cell: HTMLElement,\n panel: HTMLElement,\n context: FloatingRootContext,\n): boolean {\n const { columns, actions } = buildModel(panel);\n\n if (columnsStacked(columns)) {\n return handleLinear(key, cell, panel, context);\n }\n\n const column = cell.closest<HTMLElement>(COLUMN_SELECTOR);\n const actionsEl = cell.closest<HTMLElement>(ACTIONS_SELECTOR);\n\n if (column) {\n const colIndex = columns.indexOf(column);\n const cells = queryFocusables(column);\n const rowIndex = cells.indexOf(cell);\n\n switch (key) {\n case \"ArrowDown\": {\n if (rowIndex < cells.length - 1) {\n cells[rowIndex + 1].focus();\n } else if (colIndex < columns.length - 1) {\n firstFocusable(columns[colIndex + 1])?.focus();\n } else if (actions.length > 0) {\n firstFocusable(actions[0])?.focus();\n } else {\n focusNextTriggerAndClose(context);\n }\n return true;\n }\n case \"ArrowUp\": {\n if (rowIndex > 0) {\n cells[rowIndex - 1].focus();\n } else {\n focusTrigger(context);\n }\n return true;\n }\n case \"ArrowRight\": {\n if (colIndex < columns.length - 1) {\n firstFocusable(columns[colIndex + 1])?.focus();\n return true;\n }\n // Right border column: exit to the next trigger and close if available\n if (\n rowIndex === cells.length - 1 &&\n focusNextTriggerAndClose(context)\n ) {\n return true;\n }\n // Wrap to the current trigger and keep the menu open,\n // mirroring Left in the first column.\n focusTrigger(context);\n return true;\n }\n case \"ArrowLeft\": {\n if (colIndex > 0) {\n firstFocusable(columns[colIndex - 1])?.focus();\n } else {\n focusTrigger(context);\n }\n return true;\n }\n case \"Home\": {\n cells[0]?.focus();\n return true;\n }\n case \"End\": {\n cells[cells.length - 1]?.focus();\n return true;\n }\n default:\n return false;\n }\n }\n\n if (actionsEl) {\n const cells = queryFocusables(actionsEl);\n const index = cells.indexOf(cell);\n\n switch (key) {\n case \"ArrowRight\": {\n if (index < cells.length - 1) {\n cells[index + 1].focus();\n } else if (!focusNextTriggerAndClose(context)) {\n // Last action with no next trigger: wrap to the current trigger.\n focusTrigger(context);\n }\n return true;\n }\n case \"ArrowLeft\": {\n if (index > 0) {\n cells[index - 1].focus();\n } else if (cell === firstFocusable(panel)) {\n focusTrigger(context);\n }\n return true;\n }\n case \"ArrowUp\": {\n if (columns.length > 0) {\n const lastColumnCells = queryFocusables(columns[columns.length - 1]);\n lastColumnCells[lastColumnCells.length - 1]?.focus();\n } else {\n focusTrigger(context);\n }\n return true;\n }\n case \"ArrowDown\": {\n if (index === cells.length - 1) {\n focusNextTriggerAndClose(context);\n }\n return true;\n }\n case \"Home\": {\n cells[0]?.focus();\n return true;\n }\n case \"End\": {\n cells[cells.length - 1]?.focus();\n return true;\n }\n default:\n return false;\n }\n }\n\n return false;\n}\n\n/** The first document-focusable after the trigger, outside the panel. */\nfunction findNextAfterPanel(\n context: FloatingRootContext,\n panel: HTMLElement,\n): HTMLElement | undefined {\n const reference = context.elements.reference as HTMLElement | null;\n const refFocusable = firstFocusable(reference) ?? reference;\n\n const nextLi = refFocusable?.closest(\"li\")?.nextElementSibling;\n const nextSibling =\n nextLi instanceof HTMLElement ? firstFocusable(nextLi) : null;\n if (nextSibling) return nextSibling;\n\n const allFocusable = queryFocusables(\n panel.ownerDocument.documentElement,\n ).filter((el) => !panel.contains(el));\n const idx = refFocusable ? allFocusable.indexOf(refFocusable) : -1;\n return idx >= 0 ? allFocusable[idx + 1] : undefined;\n}\n\nexport interface UseMegaMenuNavigationProps {\n /**\n * Whether the interaction is enabled.\n * @default true\n */\n enabled?: boolean;\n}\n\n/**\n * Floating-ui interaction hook for mega menu keyboard navigation. Handles keys\n * on the panel only; the trigger keys are owned by `MegaMenuTrigger`.\n */\nexport function useMegaMenuNavigation(\n context: FloatingRootContext,\n props: UseMegaMenuNavigationProps = {},\n): ElementProps {\n const { enabled = true } = props;\n const { open, onOpenChange } = context;\n\n return useMemo(() => {\n if (!enabled) {\n return {};\n }\n\n return {\n floating: {\n onKeyDown(event: React.KeyboardEvent) {\n if (!open) return;\n\n const panel = event.currentTarget as HTMLElement;\n const target = event.target as HTMLElement;\n const { key } = event;\n\n const isArrowOrEdge =\n key === \"ArrowUp\" ||\n key === \"ArrowDown\" ||\n key === \"ArrowLeft\" ||\n key === \"ArrowRight\" ||\n key === \"Home\" ||\n key === \"End\";\n\n // A self-consuming control keeps its own navigation keys.\n if (isArrowOrEdge && target.closest(SELF_CONSUMING_SELECTOR)) {\n return;\n }\n\n const cell = target.closest<HTMLElement>(FOCUSABLE_SELECTOR);\n\n // Tab walks every cell in layout order; the panel is portaled, so the\n // boundary transitions are handled manually.\n if (key === \"Tab\") {\n const allCells = queryFocusables(panel);\n const linearIndex = cell ? allCells.indexOf(cell) : -1;\n if (linearIndex === -1) return;\n event.preventDefault();\n if (event.shiftKey) {\n if (linearIndex === 0) {\n focusTrigger(context);\n } else {\n allCells[linearIndex - 1]?.focus();\n }\n } else if (linearIndex === allCells.length - 1) {\n // Focus before closing: floating-ui skips returnFocus when focus\n // has already left the panel, so the trigger never flashes focus.\n findNextAfterPanel(context, panel)?.focus();\n onOpenChange(false);\n } else {\n allCells[linearIndex + 1]?.focus();\n }\n return;\n }\n\n if (!cell || !isArrowOrEdge) return;\n\n if (handleArrow(key, cell, panel, context)) {\n event.preventDefault();\n }\n },\n },\n };\n }, [enabled, open, context, onOpenChange]);\n}\n\n/** Focus the first navigable item inside a mega menu panel, retrying until rendered. */\nexport function focusFirstItem(panel: HTMLElement, attempt = 0): void {\n const firstItem = firstFocusable(panel);\n\n if (firstItem) {\n firstItem.focus();\n return;\n }\n\n const view = panel.ownerDocument.defaultView;\n if (attempt < 3 && view) {\n view.requestAnimationFrame(() => focusFirstItem(panel, attempt + 1));\n }\n}\n"],"names":["useMemo"],"mappings":"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"}
@@ -0,0 +1,55 @@
1
+ 'use strict';
2
+
3
+ var React = require('react');
4
+ var createContext = require('../utils/createContext.js');
5
+ require('clsx');
6
+ require('react/jsx-runtime');
7
+ require('../utils/useFloatingUI/useFloatingUI.js');
8
+ require('../utils/useId.js');
9
+ require('../salt-provider/SaltProvider.js');
10
+ require('../viewport/ViewportProvider.js');
11
+
12
+ const MenuAlignmentContext = createContext.createContext(
13
+ "MenuAlignmentContext",
14
+ {
15
+ reserveIconSpace: false,
16
+ reserveSelectionIconSpace: false,
17
+ registerIcon: () => () => void 0,
18
+ registerSelectionIcon: () => () => void 0
19
+ }
20
+ );
21
+ function useSlotRegistry() {
22
+ const [count, setCount] = React.useState(0);
23
+ const register = React.useCallback(() => {
24
+ setCount((current) => current + 1);
25
+ return () => setCount((current) => current - 1);
26
+ }, []);
27
+ return [count > 0, register];
28
+ }
29
+ function useMenuAlignmentScope() {
30
+ const [reserveIconSpace, registerIcon] = useSlotRegistry();
31
+ const [reserveSelectionIconSpace, registerSelectionIcon] = useSlotRegistry();
32
+ return React.useMemo(
33
+ () => ({
34
+ reserveIconSpace,
35
+ reserveSelectionIconSpace,
36
+ registerIcon,
37
+ registerSelectionIcon
38
+ }),
39
+ [
40
+ reserveIconSpace,
41
+ reserveSelectionIconSpace,
42
+ registerIcon,
43
+ registerSelectionIcon
44
+ ]
45
+ );
46
+ }
47
+ function useMenuAlignment() {
48
+ return React.useContext(MenuAlignmentContext);
49
+ }
50
+
51
+ exports.MenuAlignmentContext = MenuAlignmentContext;
52
+ exports.useMenuAlignment = useMenuAlignment;
53
+ exports.useMenuAlignmentScope = useMenuAlignmentScope;
54
+ exports.useSlotRegistry = useSlotRegistry;
55
+ //# sourceMappingURL=MenuAlignmentContext.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MenuAlignmentContext.js","sources":["../src/menu/MenuAlignmentContext.ts"],"sourcesContent":["import { useCallback, useContext, useMemo, useState } from \"react\";\nimport { createContext } from \"../utils\";\n\n/**\n * The leading slots that items in one alignment scope reserve for each other.\n * Each `MenuGroup` is a scope, and items outside a group share their `MenuPanel`'s scope.\n */\nexport interface MenuAlignmentContextValue {\n reserveIconSpace: boolean;\n reserveSelectionIconSpace: boolean;\n registerIcon: () => () => void;\n registerSelectionIcon: () => () => void;\n}\n\nexport const MenuAlignmentContext = createContext<MenuAlignmentContextValue>(\n \"MenuAlignmentContext\",\n {\n reserveIconSpace: false,\n reserveSelectionIconSpace: false,\n registerIcon: () => () => undefined,\n registerSelectionIcon: () => () => undefined,\n },\n);\n\nexport function useSlotRegistry() {\n const [count, setCount] = useState(0);\n const register = useCallback(() => {\n setCount((current) => current + 1);\n return () => setCount((current) => current - 1);\n }, []);\n return [count > 0, register] as const;\n}\n\nexport function useMenuAlignmentScope(): MenuAlignmentContextValue {\n const [reserveIconSpace, registerIcon] = useSlotRegistry();\n const [reserveSelectionIconSpace, registerSelectionIcon] = useSlotRegistry();\n return useMemo(\n () => ({\n reserveIconSpace,\n reserveSelectionIconSpace,\n registerIcon,\n registerSelectionIcon,\n }),\n [\n reserveIconSpace,\n reserveSelectionIconSpace,\n registerIcon,\n registerSelectionIcon,\n ],\n );\n}\n\nexport function useMenuAlignment() {\n return useContext(MenuAlignmentContext);\n}\n"],"names":["createContext","useState","useCallback","useMemo","useContext"],"mappings":";;;;;;;;;;;AAcO,MAAM,oBAAA,GAAuBA,2BAAA;AAAA,EAClC,sBAAA;AAAA,EACA;AAAA,IACE,gBAAA,EAAkB,KAAA;AAAA,IAClB,yBAAA,EAA2B,KAAA;AAAA,IAC3B,YAAA,EAAc,MAAM,MAAM,MAAA;AAAA,IAC1B,qBAAA,EAAuB,MAAM,MAAM;AAAA;AAEvC;AAEO,SAAS,eAAA,GAAkB;AAChC,EAAA,MAAM,CAAC,KAAA,EAAO,QAAQ,CAAA,GAAIC,eAAS,CAAC,CAAA;AACpC,EAAA,MAAM,QAAA,GAAWC,kBAAY,MAAM;AACjC,IAAA,QAAA,CAAS,CAAC,OAAA,KAAY,OAAA,GAAU,CAAC,CAAA;AACjC,IAAA,OAAO,MAAM,QAAA,CAAS,CAAC,OAAA,KAAY,UAAU,CAAC,CAAA;AAAA,EAChD,CAAA,EAAG,EAAE,CAAA;AACL,EAAA,OAAO,CAAC,KAAA,GAAQ,CAAA,EAAG,QAAQ,CAAA;AAC7B;AAEO,SAAS,qBAAA,GAAmD;AACjE,EAAA,MAAM,CAAC,gBAAA,EAAkB,YAAY,CAAA,GAAI,eAAA,EAAgB;AACzD,EAAA,MAAM,CAAC,yBAAA,EAA2B,qBAAqB,CAAA,GAAI,eAAA,EAAgB;AAC3E,EAAA,OAAOC,aAAA;AAAA,IACL,OAAO;AAAA,MACL,gBAAA;AAAA,MACA,yBAAA;AAAA,MACA,YAAA;AAAA,MACA;AAAA,KACF,CAAA;AAAA,IACA;AAAA,MACE,gBAAA;AAAA,MACA,yBAAA;AAAA,MACA,YAAA;AAAA,MACA;AAAA;AACF,GACF;AACF;AAEO,SAAS,gBAAA,GAAmB;AACjC,EAAA,OAAOC,iBAAW,oBAAoB,CAAA;AACxC;;;;;;;"}
@@ -11,6 +11,7 @@ require('../utils/useId.js');
11
11
  require('../salt-provider/SaltProvider.js');
12
12
  require('../viewport/ViewportProvider.js');
13
13
  var MenuContext = require('./MenuContext.js');
14
+ var MenuGroupContext = require('./MenuGroupContext.js');
14
15
 
15
16
  function MenuBase(props) {
16
17
  const {
@@ -42,10 +43,14 @@ function MenuBase(props) {
42
43
  const [focusInside, setFocusInside] = React.useState(false);
43
44
  const [triggerDisabled, setTriggerDisabled] = React.useState(false);
44
45
  const isNested = parentId != null;
46
+ const handleOpenChange = (newOpen) => {
47
+ if (newOpen && triggerDisabled) return;
48
+ setOpen(newOpen);
49
+ };
45
50
  const { x, y, strategy, elements, refs, context } = useFloatingUI.useFloatingUI({
46
51
  nodeId,
47
52
  open: openState,
48
- onOpenChange: setOpen,
53
+ onOpenChange: handleOpenChange,
49
54
  strategy: !getVirtualElement ? "absolute" : "fixed",
50
55
  placement: placement ?? (isNested || getVirtualElement ? "right-start" : "bottom-start"),
51
56
  middleware: [
@@ -86,7 +91,8 @@ function MenuBase(props) {
86
91
  listRef: elementsRef,
87
92
  activeIndex,
88
93
  nested: isNested,
89
- onNavigate: setActiveIndex
94
+ onNavigate: setActiveIndex,
95
+ disabledIndices: (index) => elementsRef.current[index] == null
90
96
  })
91
97
  ]
92
98
  );
@@ -129,7 +135,7 @@ function MenuBase(props) {
129
135
  triggerDisabled,
130
136
  setTriggerDisabled
131
137
  },
132
- children
138
+ children: /* @__PURE__ */ jsxRuntime.jsx(MenuGroupContext.MenuGroupContext.Provider, { value: MenuGroupContext.defaultMenuGroupContextValue, children })
133
139
  }
134
140
  ) });
135
141
  }
@@ -1 +1 @@
1
- {"version":3,"file":"MenuBase.js","sources":["../src/menu/MenuBase.tsx"],"sourcesContent":["import {\n FloatingNode,\n flip,\n limitShift,\n offset,\n type ReferenceType,\n safePolygon,\n shift,\n size,\n useClick,\n useDismiss,\n useFloatingNodeId,\n useFloatingParentNodeId,\n useFloatingTree,\n useHover,\n useInteractions,\n useListNavigation,\n useRole,\n} from \"@floating-ui/react\";\nimport {\n type ReactNode,\n useCallback,\n useEffect,\n useRef,\n useState,\n} from \"react\";\nimport {\n type UseFloatingUIProps,\n useControlled,\n useFloatingUI,\n useIsomorphicLayoutEffect,\n} from \"../utils\";\nimport { MenuContext } from \"./MenuContext\";\n\nexport interface MenuBaseProps {\n children?: ReactNode;\n /**\n * Display or hide the component.\n */\n open?: boolean;\n /**\n * If true, the menu will be open by default.\n */\n defaultOpen?: boolean;\n /**\n * Callback function triggered when open state changes.\n */\n onOpenChange?: (newOpen: boolean) => void;\n /**\n * Set the placement of the Menu component relative to the trigger element. Defaults to `bottom-start` if it's the root menu or `right-start` if it's nested.\n */\n placement?: UseFloatingUIProps[\"placement\"];\n /**\n * Function that returns a [virtual element](https://floating-ui.com/docs/virtual-elements). If this is provided, it will override MenuTrigger.\n */\n getVirtualElement?: () => ReferenceType | null;\n}\n\nexport function MenuBase(props: MenuBaseProps) {\n const {\n children,\n defaultOpen,\n open,\n onOpenChange,\n placement,\n getVirtualElement,\n } = props;\n const parentId = useFloatingParentNodeId();\n const nodeId = useFloatingNodeId();\n const tree = useFloatingTree();\n const elementsRef = useRef<(HTMLDivElement | null)[]>([]);\n\n const [openState, setOpenState] = useControlled({\n controlled: open,\n default: Boolean(defaultOpen),\n name: \"ListControl\",\n state: \"open\",\n });\n\n const setOpen = useCallback(\n (newOpen: boolean) => {\n setOpenState(newOpen);\n onOpenChange?.(newOpen);\n },\n [onOpenChange],\n );\n\n const [activeIndex, setActiveIndex] = useState<number | null>(null);\n const [focusInside, setFocusInside] = useState(false);\n const [triggerDisabled, setTriggerDisabled] = useState(false);\n\n const isNested = parentId != null;\n\n const { x, y, strategy, elements, refs, context } = useFloatingUI({\n nodeId,\n open: openState,\n onOpenChange: setOpen,\n strategy: !getVirtualElement ? \"absolute\" : \"fixed\",\n placement:\n placement ??\n (isNested || getVirtualElement ? \"right-start\" : \"bottom-start\"),\n middleware: [\n // Align the nested menu by shifting it by var(--salt-spacing-fixed-100)\n offset(\n isNested ? { crossAxis: -1, mainAxis: 2 } : !getVirtualElement ? 1 : 0,\n ),\n flip({}),\n shift({ limiter: limitShift() }),\n size({\n apply({ elements, availableHeight }) {\n Object.assign(elements.floating.style, {\n maxHeight: `${availableHeight}px`,\n });\n },\n }),\n ],\n });\n\n useIsomorphicLayoutEffect(() => {\n if (getVirtualElement) {\n refs.setPositionReference(getVirtualElement());\n }\n }, [getVirtualElement, refs]);\n\n const { getReferenceProps, getFloatingProps, getItemProps } = useInteractions(\n [\n useHover(context, {\n enabled: isNested && !focusInside && !triggerDisabled,\n handleClose: safePolygon({ blockPointerEvents: true }),\n }),\n useClick(context, {\n event: \"mousedown\",\n toggle: !isNested,\n ignoreMouse: isNested,\n }),\n useRole(context, { role: \"menu\" }),\n useDismiss(context, { bubbles: true }),\n useListNavigation(context, {\n listRef: elementsRef,\n activeIndex,\n nested: isNested,\n onNavigate: setActiveIndex,\n }),\n ],\n );\n\n const getPanelPosition = () => ({\n top: y ?? 0,\n left: x ?? 0,\n position: strategy,\n width: elements.floating?.offsetWidth,\n height: elements.floating?.offsetHeight,\n });\n\n useEffect(() => {\n if (!tree) return;\n\n function handleItemClick() {\n setOpen(false);\n }\n\n tree.events.on(\"click\", handleItemClick);\n\n return () => {\n tree.events.off(\"click\", handleItemClick);\n };\n }, [tree, setOpen]);\n\n return (\n <FloatingNode id={nodeId}>\n <MenuContext.Provider\n value={{\n openState,\n getReferenceProps,\n getFloatingProps,\n refs,\n getPanelPosition,\n getItemProps,\n activeIndex,\n context,\n elementsRef,\n focusInside,\n setFocusInside,\n isNested,\n triggerDisabled,\n setTriggerDisabled,\n }}\n >\n {children}\n </MenuContext.Provider>\n </FloatingNode>\n );\n}\n"],"names":["useFloatingParentNodeId","useFloatingNodeId","useFloatingTree","useRef","useControlled","useCallback","useState","useFloatingUI","offset","flip","shift","limitShift","size","elements","useIsomorphicLayoutEffect","useInteractions","useHover","safePolygon","useClick","useRole","useDismiss","useListNavigation","useEffect","jsx","FloatingNode","MenuContext"],"mappings":"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"}
1
+ {"version":3,"file":"MenuBase.js","sources":["../src/menu/MenuBase.tsx"],"sourcesContent":["import {\n FloatingNode,\n flip,\n limitShift,\n offset,\n type ReferenceType,\n safePolygon,\n shift,\n size,\n useClick,\n useDismiss,\n useFloatingNodeId,\n useFloatingParentNodeId,\n useFloatingTree,\n useHover,\n useInteractions,\n useListNavigation,\n useRole,\n} from \"@floating-ui/react\";\nimport {\n type ReactNode,\n useCallback,\n useEffect,\n useRef,\n useState,\n} from \"react\";\nimport {\n type UseFloatingUIProps,\n useControlled,\n useFloatingUI,\n useIsomorphicLayoutEffect,\n} from \"../utils\";\nimport { MenuContext } from \"./MenuContext\";\nimport {\n defaultMenuGroupContextValue,\n MenuGroupContext,\n} from \"./MenuGroupContext\";\n\nexport interface MenuBaseProps {\n children?: ReactNode;\n /**\n * Display or hide the component.\n */\n open?: boolean;\n /**\n * If true, the menu will be open by default.\n */\n defaultOpen?: boolean;\n /**\n * Callback function triggered when open state changes.\n */\n onOpenChange?: (newOpen: boolean) => void;\n /**\n * Set the placement of the Menu component relative to the trigger element. Defaults to `bottom-start` if it's the root menu or `right-start` if it's nested.\n */\n placement?: UseFloatingUIProps[\"placement\"];\n /**\n * Function that returns a [virtual element](https://floating-ui.com/docs/virtual-elements). If this is provided, it will override MenuTrigger.\n */\n getVirtualElement?: () => ReferenceType | null;\n}\n\nexport function MenuBase(props: MenuBaseProps) {\n const {\n children,\n defaultOpen,\n open,\n onOpenChange,\n placement,\n getVirtualElement,\n } = props;\n const parentId = useFloatingParentNodeId();\n const nodeId = useFloatingNodeId();\n const tree = useFloatingTree();\n const elementsRef = useRef<(HTMLDivElement | null)[]>([]);\n\n const [openState, setOpenState] = useControlled({\n controlled: open,\n default: Boolean(defaultOpen),\n name: \"ListControl\",\n state: \"open\",\n });\n\n const setOpen = useCallback(\n (newOpen: boolean) => {\n setOpenState(newOpen);\n onOpenChange?.(newOpen);\n },\n [onOpenChange],\n );\n\n const [activeIndex, setActiveIndex] = useState<number | null>(null);\n const [focusInside, setFocusInside] = useState(false);\n const [triggerDisabled, setTriggerDisabled] = useState(false);\n\n const isNested = parentId != null;\n\n const handleOpenChange = (newOpen: boolean) => {\n if (newOpen && triggerDisabled) return;\n setOpen(newOpen);\n };\n\n const { x, y, strategy, elements, refs, context } = useFloatingUI({\n nodeId,\n open: openState,\n onOpenChange: handleOpenChange,\n strategy: !getVirtualElement ? \"absolute\" : \"fixed\",\n placement:\n placement ??\n (isNested || getVirtualElement ? \"right-start\" : \"bottom-start\"),\n middleware: [\n // Align the nested menu by shifting it by var(--salt-spacing-fixed-100)\n offset(\n isNested ? { crossAxis: -1, mainAxis: 2 } : !getVirtualElement ? 1 : 0,\n ),\n flip({}),\n shift({ limiter: limitShift() }),\n size({\n apply({ elements, availableHeight }) {\n Object.assign(elements.floating.style, {\n maxHeight: `${availableHeight}px`,\n });\n },\n }),\n ],\n });\n\n useIsomorphicLayoutEffect(() => {\n if (getVirtualElement) {\n refs.setPositionReference(getVirtualElement());\n }\n }, [getVirtualElement, refs]);\n\n const { getReferenceProps, getFloatingProps, getItemProps } = useInteractions(\n [\n useHover(context, {\n enabled: isNested && !focusInside && !triggerDisabled,\n handleClose: safePolygon({ blockPointerEvents: true }),\n }),\n useClick(context, {\n event: \"mousedown\",\n toggle: !isNested,\n ignoreMouse: isNested,\n }),\n useRole(context, { role: \"menu\" }),\n useDismiss(context, { bubbles: true }),\n useListNavigation(context, {\n listRef: elementsRef,\n activeIndex,\n nested: isNested,\n onNavigate: setActiveIndex,\n disabledIndices: (index) => elementsRef.current[index] == null,\n }),\n ],\n );\n\n const getPanelPosition = () => ({\n top: y ?? 0,\n left: x ?? 0,\n position: strategy,\n width: elements.floating?.offsetWidth,\n height: elements.floating?.offsetHeight,\n });\n\n useEffect(() => {\n if (!tree) return;\n\n function handleItemClick() {\n setOpen(false);\n }\n\n tree.events.on(\"click\", handleItemClick);\n\n return () => {\n tree.events.off(\"click\", handleItemClick);\n };\n }, [tree, setOpen]);\n\n return (\n <FloatingNode id={nodeId}>\n <MenuContext.Provider\n value={{\n openState,\n getReferenceProps,\n getFloatingProps,\n refs,\n getPanelPosition,\n getItemProps,\n activeIndex,\n context,\n elementsRef,\n focusInside,\n setFocusInside,\n isNested,\n triggerDisabled,\n setTriggerDisabled,\n }}\n >\n <MenuGroupContext.Provider value={defaultMenuGroupContextValue}>\n {children}\n </MenuGroupContext.Provider>\n </MenuContext.Provider>\n </FloatingNode>\n );\n}\n"],"names":["useFloatingParentNodeId","useFloatingNodeId","useFloatingTree","useRef","useControlled","useCallback","useState","useFloatingUI","offset","flip","shift","limitShift","size","elements","useIsomorphicLayoutEffect","useInteractions","useHover","safePolygon","useClick","useRole","useDismiss","useListNavigation","useEffect","jsx","FloatingNode","MenuContext","MenuGroupContext","defaultMenuGroupContextValue"],"mappings":"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"}
@@ -10,12 +10,23 @@ require('../utils/useFloatingUI/useFloatingUI.js');
10
10
  var useId = require('../utils/useId.js');
11
11
  require('../salt-provider/SaltProvider.js');
12
12
  require('../viewport/ViewportProvider.js');
13
+ var MenuAlignmentContext = require('./MenuAlignmentContext.js');
13
14
  var MenuGroup$1 = require('./MenuGroup.css.js');
15
+ var MenuGroupContext = require('./MenuGroupContext.js');
14
16
 
15
17
  const withBaseName = makePrefixer.makePrefixer("saltMenuGroup");
18
+ const noSelection = [];
16
19
  const MenuGroup = React.forwardRef(
17
20
  function MenuGroup2(props, ref) {
18
- const { className, children, label, ...rest } = props;
21
+ const {
22
+ className,
23
+ children,
24
+ label,
25
+ onSelectionChange,
26
+ selected: selectedProp = noSelection,
27
+ selectionVariant,
28
+ ...rest
29
+ } = props;
19
30
  const targetWindow = window.useWindow();
20
31
  styles.useComponentCssInjection({
21
32
  testId: "salt-menu-group",
@@ -23,7 +34,35 @@ const MenuGroup = React.forwardRef(
23
34
  window: targetWindow
24
35
  });
25
36
  const labelId = useId.useId();
26
- return /* @__PURE__ */ jsxRuntime.jsxs(
37
+ const selected = React.useMemo(
38
+ () => selectionVariant === "single" ? selectedProp.slice(0, 1) : selectedProp,
39
+ [selectedProp, selectionVariant]
40
+ );
41
+ const isSelected = React.useCallback(
42
+ (value) => selected.includes(value),
43
+ [selected]
44
+ );
45
+ const select = React.useCallback(
46
+ (event, value) => {
47
+ if (selectionVariant === "single") {
48
+ if (!selected.includes(value)) {
49
+ onSelectionChange == null ? void 0 : onSelectionChange(event, [value]);
50
+ }
51
+ } else if (selectionVariant === "multiple") {
52
+ onSelectionChange == null ? void 0 : onSelectionChange(
53
+ event,
54
+ selected.includes(value) ? selected.filter((item) => item !== value) : selected.concat(value)
55
+ );
56
+ }
57
+ },
58
+ [onSelectionChange, selected, selectionVariant]
59
+ );
60
+ const contextValue = React.useMemo(
61
+ () => ({ isSelected, select, selectionVariant }),
62
+ [isSelected, select, selectionVariant]
63
+ );
64
+ const alignment = MenuAlignmentContext.useMenuAlignmentScope();
65
+ return /* @__PURE__ */ jsxRuntime.jsx(MenuGroupContext.MenuGroupContext.Provider, { value: contextValue, children: /* @__PURE__ */ jsxRuntime.jsx(MenuAlignmentContext.MenuAlignmentContext.Provider, { value: alignment, children: /* @__PURE__ */ jsxRuntime.jsxs(
27
66
  "div",
28
67
  {
29
68
  "aria-labelledby": label ? labelId : void 0,
@@ -36,7 +75,7 @@ const MenuGroup = React.forwardRef(
36
75
  children
37
76
  ]
38
77
  }
39
- );
78
+ ) }) });
40
79
  }
41
80
  );
42
81
 
@@ -1 +1 @@
1
- {"version":3,"file":"MenuGroup.js","sources":["../src/menu/MenuGroup.tsx"],"sourcesContent":["import { useComponentCssInjection } from \"@salt-ds/styles\";\nimport { useWindow } from \"@salt-ds/window\";\nimport { clsx } from \"clsx\";\nimport {\n type ComponentPropsWithoutRef,\n forwardRef,\n type ReactNode,\n} from \"react\";\nimport { makePrefixer, useId } from \"../utils\";\nimport menuGroupCss from \"./MenuGroup.css\";\n\nexport interface MenuGroupProps extends ComponentPropsWithoutRef<\"div\"> {\n /**\n * The label of the menu group.\n */\n label?: string;\n /**\n * Menus to be rendered inside the menu group.\n */\n children?: ReactNode;\n}\n\nconst withBaseName = makePrefixer(\"saltMenuGroup\");\n\nexport const MenuGroup = forwardRef<HTMLDivElement, MenuGroupProps>(\n function MenuGroup(props, ref) {\n const { className, children, label, ...rest } = props;\n\n const targetWindow = useWindow();\n useComponentCssInjection({\n testId: \"salt-menu-group\",\n css: menuGroupCss,\n window: targetWindow,\n });\n\n const labelId = useId();\n\n return (\n <div\n aria-labelledby={label ? labelId : undefined}\n className={clsx(withBaseName(), className)}\n role=\"group\"\n ref={ref}\n {...rest}\n >\n {label && (\n <div aria-hidden className={withBaseName(\"label\")} id={labelId}>\n {label}\n </div>\n )}\n {children}\n </div>\n );\n },\n);\n"],"names":["makePrefixer","forwardRef","MenuGroup","useWindow","useComponentCssInjection","menuGroupCss","useId","jsxs","clsx","jsx"],"mappings":";;;;;;;;;;;;;;AAsBA,MAAM,YAAA,GAAeA,0BAAa,eAAe,CAAA;AAE1C,MAAM,SAAA,GAAYC,gBAAA;AAAA,EACvB,SAASC,UAAAA,CAAU,KAAA,EAAO,GAAA,EAAK;AAC7B,IAAA,MAAM,EAAE,SAAA,EAAW,QAAA,EAAU,KAAA,EAAO,GAAG,MAAK,GAAI,KAAA;AAEhD,IAAA,MAAM,eAAeC,gBAAA,EAAU;AAC/B,IAAAC,+BAAA,CAAyB;AAAA,MACvB,MAAA,EAAQ,iBAAA;AAAA,MACR,GAAA,EAAKC,WAAA;AAAA,MACL,MAAA,EAAQ;AAAA,KACT,CAAA;AAED,IAAA,MAAM,UAAUC,WAAA,EAAM;AAEtB,IAAA,uBACEC,eAAA;AAAA,MAAC,KAAA;AAAA,MAAA;AAAA,QACC,iBAAA,EAAiB,QAAQ,OAAA,GAAU,MAAA;AAAA,QACnC,SAAA,EAAWC,SAAA,CAAK,YAAA,EAAa,EAAG,SAAS,CAAA;AAAA,QACzC,IAAA,EAAK,OAAA;AAAA,QACL,GAAA;AAAA,QACC,GAAG,IAAA;AAAA,QAEH,QAAA,EAAA;AAAA,UAAA,KAAA,oBACCC,cAAA,CAAC,KAAA,EAAA,EAAI,aAAA,EAAW,IAAA,EAAC,SAAA,EAAW,aAAa,OAAO,CAAA,EAAG,EAAA,EAAI,OAAA,EACpD,QAAA,EAAA,KAAA,EACH,CAAA;AAAA,UAED;AAAA;AAAA;AAAA,KACH;AAAA,EAEJ;AACF;;;;"}
1
+ {"version":3,"file":"MenuGroup.js","sources":["../src/menu/MenuGroup.tsx"],"sourcesContent":["import { useComponentCssInjection } from \"@salt-ds/styles\";\nimport { useWindow } from \"@salt-ds/window\";\nimport { clsx } from \"clsx\";\nimport {\n type ComponentPropsWithoutRef,\n forwardRef,\n type ReactNode,\n type SyntheticEvent,\n useCallback,\n useMemo,\n} from \"react\";\nimport { makePrefixer, useId } from \"../utils\";\nimport {\n MenuAlignmentContext,\n useMenuAlignmentScope,\n} from \"./MenuAlignmentContext\";\nimport menuGroupCss from \"./MenuGroup.css\";\nimport { MenuGroupContext } from \"./MenuGroupContext\";\n\ninterface BaseMenuGroupProps extends ComponentPropsWithoutRef<\"div\"> {\n /**\n * Menus to be rendered inside the menu group.\n */\n children?: ReactNode;\n /**\n * The label of the menu group.\n */\n label?: string;\n /**\n * Selection variant of the menu group. If \"single\", the menu items inside behave like radio buttons. If \"multiple\", they behave like checkboxes. Each selectable menu item needs a `value`. When omitted, the menu items are not selectable.\n */\n selectionVariant?: \"single\" | \"multiple\";\n}\n\ninterface SelectableMenuGroupProps extends BaseMenuGroupProps {\n /**\n * Callback fired when the selection changes.\n * @param event\n * @param newSelected The new selected values.\n */\n onSelectionChange?: (event: SyntheticEvent, newSelected: string[]) => void;\n /**\n * The values of the selected menu items. Required when `selectionVariant` is \"single\" or \"multiple\". The menu's content unmounts when it closes, so keep the selection in state and update it in `onSelectionChange`.\n */\n selected: string[];\n selectionVariant: \"single\" | \"multiple\";\n}\n\ninterface NonSelectableMenuGroupProps extends BaseMenuGroupProps {\n selectionVariant?: undefined;\n}\n\nexport type MenuGroupProps =\n | SelectableMenuGroupProps\n | NonSelectableMenuGroupProps;\n\nconst withBaseName = makePrefixer(\"saltMenuGroup\");\n\nconst noSelection: string[] = [];\n\nexport const MenuGroup = forwardRef<HTMLDivElement, MenuGroupProps>(\n function MenuGroup(props, ref) {\n const {\n className,\n children,\n label,\n onSelectionChange,\n selected: selectedProp = noSelection,\n selectionVariant,\n ...rest\n } = props as BaseMenuGroupProps &\n Partial<Pick<SelectableMenuGroupProps, \"onSelectionChange\" | \"selected\">>;\n\n const targetWindow = useWindow();\n useComponentCssInjection({\n testId: \"salt-menu-group\",\n css: menuGroupCss,\n window: targetWindow,\n });\n\n const labelId = useId();\n\n const selected = useMemo(\n () =>\n selectionVariant === \"single\" ? selectedProp.slice(0, 1) : selectedProp,\n [selectedProp, selectionVariant],\n );\n\n const isSelected = useCallback(\n (value: string) => selected.includes(value),\n [selected],\n );\n\n const select = useCallback(\n (event: SyntheticEvent, value: string) => {\n if (selectionVariant === \"single\") {\n if (!selected.includes(value)) {\n onSelectionChange?.(event, [value]);\n }\n } else if (selectionVariant === \"multiple\") {\n onSelectionChange?.(\n event,\n selected.includes(value)\n ? selected.filter((item) => item !== value)\n : selected.concat(value),\n );\n }\n },\n [onSelectionChange, selected, selectionVariant],\n );\n\n const contextValue = useMemo(\n () => ({ isSelected, select, selectionVariant }),\n [isSelected, select, selectionVariant],\n );\n\n const alignment = useMenuAlignmentScope();\n\n return (\n <MenuGroupContext.Provider value={contextValue}>\n <MenuAlignmentContext.Provider value={alignment}>\n <div\n aria-labelledby={label ? labelId : undefined}\n className={clsx(withBaseName(), className)}\n role=\"group\"\n ref={ref}\n {...rest}\n >\n {label && (\n <div aria-hidden className={withBaseName(\"label\")} id={labelId}>\n {label}\n </div>\n )}\n {children}\n </div>\n </MenuAlignmentContext.Provider>\n </MenuGroupContext.Provider>\n );\n },\n);\n"],"names":["makePrefixer","forwardRef","MenuGroup","useWindow","useComponentCssInjection","menuGroupCss","useId","useMemo","useCallback","useMenuAlignmentScope","jsx","MenuGroupContext","MenuAlignmentContext","jsxs","clsx"],"mappings":"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"}
@@ -0,0 +1,27 @@
1
+ 'use strict';
2
+
3
+ var React = require('react');
4
+ var createContext = require('../utils/createContext.js');
5
+ require('clsx');
6
+ require('react/jsx-runtime');
7
+ require('../utils/useFloatingUI/useFloatingUI.js');
8
+ require('../utils/useId.js');
9
+ require('../salt-provider/SaltProvider.js');
10
+ require('../viewport/ViewportProvider.js');
11
+
12
+ const defaultMenuGroupContextValue = {
13
+ isSelected: () => false,
14
+ select: () => void 0
15
+ };
16
+ const MenuGroupContext = createContext.createContext(
17
+ "MenuGroupContext",
18
+ defaultMenuGroupContextValue
19
+ );
20
+ function useMenuGroup() {
21
+ return React.useContext(MenuGroupContext);
22
+ }
23
+
24
+ exports.MenuGroupContext = MenuGroupContext;
25
+ exports.defaultMenuGroupContextValue = defaultMenuGroupContextValue;
26
+ exports.useMenuGroup = useMenuGroup;
27
+ //# sourceMappingURL=MenuGroupContext.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MenuGroupContext.js","sources":["../src/menu/MenuGroupContext.ts"],"sourcesContent":["import { type SyntheticEvent, useContext } from \"react\";\nimport { createContext } from \"../utils\";\nimport type { MenuGroupProps } from \"./MenuGroup\";\n\nexport interface MenuGroupContextValue {\n isSelected: (value: string) => boolean;\n select: (event: SyntheticEvent, value: string) => void;\n selectionVariant?: MenuGroupProps[\"selectionVariant\"];\n}\n\nexport const defaultMenuGroupContextValue: MenuGroupContextValue = {\n isSelected: () => false,\n select: () => undefined,\n};\n\nexport const MenuGroupContext = createContext<MenuGroupContextValue>(\n \"MenuGroupContext\",\n defaultMenuGroupContextValue,\n);\n\nexport function useMenuGroup() {\n return useContext(MenuGroupContext);\n}\n"],"names":["createContext","useContext"],"mappings":";;;;;;;;;;;AAUO,MAAM,4BAAA,GAAsD;AAAA,EACjE,YAAY,MAAM,KAAA;AAAA,EAClB,QAAQ,MAAM;AAChB;AAEO,MAAM,gBAAA,GAAmBA,2BAAA;AAAA,EAC9B,kBAAA;AAAA,EACA;AACF;AAEO,SAAS,YAAA,GAAe;AAC7B,EAAA,OAAOC,iBAAW,gBAAgB,CAAA;AACpC;;;;;;"}
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var css_248z = ".saltMenuItem {\n color: var(--salt-content-primary-foreground);\n background: var(--salt-selectable-background);\n font-size: var(--salt-text-fontSize);\n font-weight: var(--salt-text-fontWeight);\n font-family: var(--salt-text-fontFamily);\n line-height: var(--salt-text-lineHeight);\n letter-spacing: var(--salt-text-letterSpacing);\n min-height: calc(var(--salt-size-base) + var(--salt-spacing-100));\n padding: calc(var(--salt-spacing-100) + var(--salt-spacing-25)) var(--salt-spacing-100);\n display: flex;\n gap: var(--salt-spacing-100);\n position: relative;\n cursor: var(--salt-cursor-hover);\n box-sizing: border-box;\n flex-shrink: 0;\n}\n\n.saltMenuItem:focus-visible {\n outline: var(--salt-focused-outline);\n outline-offset: calc(var(--salt-size-fixed-100) * -2);\n}\n\n.saltMenuItem:hover {\n outline: none;\n}\n\n.saltMenuItem:hover,\n.saltMenuItem:focus-visible {\n background: var(--salt-selectable-background-hover);\n}\n\n.saltMenuItem:active {\n background: var(--salt-selectable-background-selected);\n box-shadow:\n 0 calc(var(--salt-size-fixed-100) * -1) 0 0 var(--salt-selectable-borderColor-selected),\n 0 var(--salt-size-fixed-100) 0 0 var(--salt-selectable-borderColor-selected);\n}\n\n.saltMenuItem[aria-disabled=\"true\"],\n.saltMenuItem[aria-disabled=\"true\"]:active {\n opacity: 0.4;\n background: var(--salt-selectable-background);\n color: var(--salt-content-primary-foreground);\n cursor: var(--salt-cursor-disabled);\n box-shadow: none;\n}\n\n.saltMenuItem-blurActive {\n z-index: var(--salt-zIndex-default);\n background: var(--salt-selectable-background-selected);\n box-shadow:\n 0 calc(var(--salt-size-fixed-100) * -1) 0 0 var(--salt-selectable-borderColor-selected),\n 0 var(--salt-size-fixed-100) 0 0 var(--salt-selectable-borderColor-selected);\n}\n\n/* TODO: Find a better way of doing this */\n.saltMenuItem .saltIcon:not(.saltCheckboxIcon-icon) {\n min-height: var(--salt-text-lineHeight);\n}\n\n.saltMenuItem-expandIcon.saltIcon {\n margin-left: auto;\n}\n";
3
+ var css_248z = ".saltMenuItem {\n color: var(--salt-content-primary-foreground);\n background: var(--salt-selectable-background);\n font-size: var(--salt-text-fontSize);\n font-weight: var(--salt-text-fontWeight);\n font-family: var(--salt-text-fontFamily);\n line-height: var(--salt-text-lineHeight);\n letter-spacing: var(--salt-text-letterSpacing);\n min-height: calc(var(--salt-size-base) + var(--salt-spacing-100));\n padding: calc(var(--salt-spacing-100) + var(--salt-spacing-25)) var(--salt-spacing-100);\n display: flex;\n gap: var(--salt-spacing-100);\n position: relative;\n cursor: var(--salt-cursor-hover);\n box-sizing: border-box;\n flex-shrink: 0;\n --saltMenuItem-iconColumnWidth: max(var(--salt-size-icon), 12px);\n}\n\n.saltMenuItem:focus-visible {\n outline: var(--salt-focused-outline);\n outline-offset: calc(var(--salt-size-fixed-100) * -2);\n}\n\n.saltMenuItem:hover {\n outline: none;\n}\n\n.saltMenuItem:hover,\n.saltMenuItem:focus-visible {\n background: var(--salt-selectable-background-hover);\n}\n\n.saltMenuItem[role=\"menuitem\"]:active {\n background: var(--salt-selectable-background-selected);\n box-shadow:\n 0 calc(var(--salt-size-fixed-100) * -1) 0 0 var(--salt-selectable-borderColor-selected),\n 0 var(--salt-size-fixed-100) 0 0 var(--salt-selectable-borderColor-selected);\n}\n\n.saltMenuItem[aria-disabled=\"true\"],\n.saltMenuItem[aria-disabled=\"true\"]:active {\n opacity: 0.4;\n background: var(--salt-selectable-background);\n color: var(--salt-content-primary-foreground);\n cursor: var(--salt-cursor-disabled);\n box-shadow: none;\n}\n\n.saltMenuItem-blurActive {\n z-index: var(--salt-zIndex-default);\n background: var(--salt-selectable-background-selected);\n box-shadow:\n 0 calc(var(--salt-size-fixed-100) * -1) 0 0 var(--salt-selectable-borderColor-selected),\n 0 var(--salt-size-fixed-100) 0 0 var(--salt-selectable-borderColor-selected);\n}\n\n/* TODO: Find a better way of doing this */\n.saltMenuItem .saltIcon:not(.saltCheckboxIcon-icon) {\n min-height: var(--salt-text-lineHeight);\n}\n\n.saltMenuItem .saltMenuItem-selectionIcon {\n margin: calc((var(--salt-text-lineHeight) - var(--salt-size-selectable)) / 2) 0;\n}\n\n.saltMenuItem-selectionIconPlaceholder {\n flex-shrink: 0;\n width: var(--salt-size-selectable);\n}\n\n.saltMenuItem-iconPlaceholder {\n flex-shrink: 0;\n width: var(--saltMenuItem-iconColumnWidth);\n}\n\n/* Account for selectable and icon token size differences, so labels after an icon line up with labels after a radio or checkbox */\n.saltMenuItem-selectionAlignedIcon {\n --saltMenuItem-iconColumnWidth: max(var(--salt-size-selectable), var(--salt-size-icon), 12px);\n}\n\n.saltMenuItem-selectionAlignedIcon > .saltIcon:first-child {\n margin-inline: max(0px, calc((var(--saltMenuItem-iconColumnWidth) - var(--icon-size)) / 2));\n}\n\n.saltMenuItem-expandIcon.saltIcon {\n margin-left: auto;\n}\n";
4
4
 
5
5
  module.exports = css_248z;
6
6
  //# sourceMappingURL=MenuItem.css.js.map