@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.
- package/CHANGELOG.md +83 -0
- package/css/salt-core.css +283 -50
- package/dist-cjs/dialog/Dialog.css.js +1 -1
- package/dist-cjs/drawer/Drawer.css.js +1 -1
- package/dist-cjs/drawer/Drawer.js +54 -6
- package/dist-cjs/drawer/Drawer.js.map +1 -1
- package/dist-cjs/drawer/DrawerContext.js +2 -0
- package/dist-cjs/drawer/DrawerContext.js.map +1 -1
- package/dist-cjs/drawer/DrawerFooter.css.js +1 -1
- package/dist-cjs/drawer/DrawerHeader.css.js +1 -1
- package/dist-cjs/drawer/DrawerHeader.js +6 -3
- package/dist-cjs/drawer/DrawerHeader.js.map +1 -1
- package/dist-cjs/drawer/internal/DrawerResizeGuide.css.js +6 -0
- package/dist-cjs/drawer/internal/DrawerResizeGuide.css.js.map +1 -0
- package/dist-cjs/drawer/internal/DrawerResizeGuide.js +44 -0
- package/dist-cjs/drawer/internal/DrawerResizeGuide.js.map +1 -0
- package/dist-cjs/drawer/internal/DrawerResizeHandle.css.js +6 -0
- package/dist-cjs/drawer/internal/DrawerResizeHandle.css.js.map +1 -0
- package/dist-cjs/drawer/internal/DrawerResizeHandle.js +43 -0
- package/dist-cjs/drawer/internal/DrawerResizeHandle.js.map +1 -0
- package/dist-cjs/drawer/internal/useDrawerResize.js +519 -0
- package/dist-cjs/drawer/internal/useDrawerResize.js.map +1 -0
- package/dist-cjs/interactable-card/InteractableCard.js +2 -1
- package/dist-cjs/interactable-card/InteractableCard.js.map +1 -1
- package/dist-cjs/link-button/LinkButton.css.js +1 -1
- package/dist-cjs/mega-menu/useMegaMenuNavigation.js +11 -20
- package/dist-cjs/mega-menu/useMegaMenuNavigation.js.map +1 -1
- package/dist-cjs/menu/MenuAlignmentContext.js +55 -0
- package/dist-cjs/menu/MenuAlignmentContext.js.map +1 -0
- package/dist-cjs/menu/MenuBase.js +9 -3
- package/dist-cjs/menu/MenuBase.js.map +1 -1
- package/dist-cjs/menu/MenuGroup.js +42 -3
- package/dist-cjs/menu/MenuGroup.js.map +1 -1
- package/dist-cjs/menu/MenuGroupContext.js +27 -0
- package/dist-cjs/menu/MenuGroupContext.js.map +1 -0
- package/dist-cjs/menu/MenuItem.css.js +1 -1
- package/dist-cjs/menu/MenuItem.js +176 -50
- package/dist-cjs/menu/MenuItem.js.map +1 -1
- package/dist-cjs/menu/MenuPanel.js +12 -3
- package/dist-cjs/menu/MenuPanel.js.map +1 -1
- package/dist-cjs/menu/MenuPanelContext.js +3 -1
- package/dist-cjs/menu/MenuPanelContext.js.map +1 -1
- package/dist-cjs/pill-input/PillInput.css.js +1 -1
- package/dist-cjs/semantic-icon-provider/SemanticIconProvider.js +2 -2
- package/dist-cjs/semantic-icon-provider/SemanticIconProvider.js.map +1 -1
- package/dist-cjs/stepper/Step.js +12 -1
- package/dist-cjs/stepper/Step.js.map +1 -1
- package/dist-cjs/stepper/internal/StepConnector.css.js +1 -1
- package/dist-cjs/stepper/internal/StepText.css.js +1 -1
- package/dist-cjs/stepper/internal/StepText.js +4 -1
- package/dist-cjs/stepper/internal/StepText.js.map +1 -1
- package/dist-cjs/stepper/internal/hasActiveStep.js +12 -0
- package/dist-cjs/stepper/internal/hasActiveStep.js.map +1 -0
- package/dist-cjs/toggle-button/ToggleButton.css.js +1 -1
- package/dist-cjs/tree/TreeNodeTrigger.css.js +1 -1
- package/dist-cjs/tree/TreeNodeTrigger.js +1 -2
- package/dist-cjs/tree/TreeNodeTrigger.js.map +1 -1
- package/dist-es/dialog/Dialog.css.js +1 -1
- package/dist-es/drawer/Drawer.css.js +1 -1
- package/dist-es/drawer/Drawer.js +54 -6
- package/dist-es/drawer/Drawer.js.map +1 -1
- package/dist-es/drawer/DrawerContext.js +2 -0
- package/dist-es/drawer/DrawerContext.js.map +1 -1
- package/dist-es/drawer/DrawerFooter.css.js +1 -1
- package/dist-es/drawer/DrawerHeader.css.js +1 -1
- package/dist-es/drawer/DrawerHeader.js +6 -3
- package/dist-es/drawer/DrawerHeader.js.map +1 -1
- package/dist-es/drawer/internal/DrawerResizeGuide.css.js +4 -0
- package/dist-es/drawer/internal/DrawerResizeGuide.css.js.map +1 -0
- package/dist-es/drawer/internal/DrawerResizeGuide.js +42 -0
- package/dist-es/drawer/internal/DrawerResizeGuide.js.map +1 -0
- package/dist-es/drawer/internal/DrawerResizeHandle.css.js +4 -0
- package/dist-es/drawer/internal/DrawerResizeHandle.css.js.map +1 -0
- package/dist-es/drawer/internal/DrawerResizeHandle.js +41 -0
- package/dist-es/drawer/internal/DrawerResizeHandle.js.map +1 -0
- package/dist-es/drawer/internal/useDrawerResize.js +517 -0
- package/dist-es/drawer/internal/useDrawerResize.js.map +1 -0
- package/dist-es/interactable-card/InteractableCard.js +2 -1
- package/dist-es/interactable-card/InteractableCard.js.map +1 -1
- package/dist-es/link-button/LinkButton.css.js +1 -1
- package/dist-es/mega-menu/useMegaMenuNavigation.js +11 -20
- package/dist-es/mega-menu/useMegaMenuNavigation.js.map +1 -1
- package/dist-es/menu/MenuAlignmentContext.js +50 -0
- package/dist-es/menu/MenuAlignmentContext.js.map +1 -0
- package/dist-es/menu/MenuBase.js +9 -3
- package/dist-es/menu/MenuBase.js.map +1 -1
- package/dist-es/menu/MenuGroup.js +44 -5
- package/dist-es/menu/MenuGroup.js.map +1 -1
- package/dist-es/menu/MenuGroupContext.js +23 -0
- package/dist-es/menu/MenuGroupContext.js.map +1 -0
- package/dist-es/menu/MenuItem.css.js +1 -1
- package/dist-es/menu/MenuItem.js +177 -51
- package/dist-es/menu/MenuItem.js.map +1 -1
- package/dist-es/menu/MenuPanel.js +12 -3
- package/dist-es/menu/MenuPanel.js.map +1 -1
- package/dist-es/menu/MenuPanelContext.js +3 -1
- package/dist-es/menu/MenuPanelContext.js.map +1 -1
- package/dist-es/pill-input/PillInput.css.js +1 -1
- package/dist-es/semantic-icon-provider/SemanticIconProvider.js +3 -3
- package/dist-es/semantic-icon-provider/SemanticIconProvider.js.map +1 -1
- package/dist-es/stepper/Step.js +12 -1
- package/dist-es/stepper/Step.js.map +1 -1
- package/dist-es/stepper/internal/StepConnector.css.js +1 -1
- package/dist-es/stepper/internal/StepText.css.js +1 -1
- package/dist-es/stepper/internal/StepText.js +4 -1
- package/dist-es/stepper/internal/StepText.js.map +1 -1
- package/dist-es/stepper/internal/hasActiveStep.js +10 -0
- package/dist-es/stepper/internal/hasActiveStep.js.map +1 -0
- package/dist-es/toggle-button/ToggleButton.css.js +1 -1
- package/dist-es/tree/TreeNodeTrigger.css.js +1 -1
- package/dist-es/tree/TreeNodeTrigger.js +1 -2
- package/dist-es/tree/TreeNodeTrigger.js.map +1 -1
- package/dist-types/drawer/Drawer.d.ts +6 -0
- package/dist-types/drawer/DrawerContext.d.ts +3 -0
- package/dist-types/drawer/DrawerHeader.d.ts +1 -1
- package/dist-types/drawer/internal/DrawerResizeGuide.d.ts +7 -0
- package/dist-types/drawer/internal/DrawerResizeHandle.d.ts +8 -0
- package/dist-types/drawer/internal/index.d.ts +3 -0
- package/dist-types/drawer/internal/useDrawerResize.d.ts +34 -0
- package/dist-types/menu/MenuAlignmentContext.d.ts +14 -0
- package/dist-types/menu/MenuGroup.d.ts +26 -4
- package/dist-types/menu/MenuGroupContext.d.ts +10 -0
- package/dist-types/menu/MenuItem.d.ts +4 -0
- package/dist-types/menu/MenuPanelContext.d.ts +2 -0
- package/dist-types/stepper/internal/StepText.d.ts +1 -1
- package/dist-types/stepper/internal/hasActiveStep.d.ts +2 -0
- package/package.json +2 -2
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useDrawerResize.js","sources":["../src/drawer/internal/useDrawerResize.ts"],"sourcesContent":["import { useWindow } from \"@salt-ds/window\";\nimport type {\n AriaAttributes,\n CSSProperties,\n KeyboardEvent as ReactKeyboardEvent,\n MouseEvent as ReactMouseEvent,\n PointerEvent as ReactPointerEvent,\n} from \"react\";\nimport { useCallback, useEffect, useRef, useState } from \"react\";\nimport { useEventCallback, useIsomorphicLayoutEffect } from \"../../utils\";\nimport type { DrawerProps } from \"../Drawer\";\n\ntype DrawerPosition = NonNullable<DrawerProps[\"position\"]>;\n\ninterface Bounds {\n min: number;\n max: number;\n}\n\ninterface DragState extends Bounds {\n pointerId: number;\n startX: number;\n startY: number;\n originSize: number;\n previousSize: number;\n cancelSize: number | undefined;\n moved: boolean;\n}\n\n/** Click-to-place resizing */\ninterface PlacingState extends Bounds {\n /** In viewport coordinates. */\n guideOffset: number;\n /** The placing press started on the guide layer. */\n pressed: boolean;\n}\n\ntype Interaction = \"inactive\" | \"hover\" | \"active\" | \"placing\";\n\nexport interface SeparatorProps\n extends Pick<\n AriaAttributes,\n \"aria-orientation\" | \"aria-valuenow\" | \"aria-valuemin\" | \"aria-valuemax\"\n > {\n role: \"separator\";\n tabIndex: number;\n ref: (element: HTMLElement | null) => void;\n onKeyDown: (event: ReactKeyboardEvent<HTMLElement>) => void;\n onFocus: () => void;\n}\n\nexport interface GuideProps {\n ref: (element: HTMLElement | null) => void;\n onPointerDown: (event: ReactPointerEvent<HTMLElement>) => void;\n onPointerMove: (event: ReactPointerEvent<HTMLElement>) => void;\n onClick: (event: ReactMouseEvent<HTMLElement>) => void;\n onContextMenu: () => void;\n}\n\nexport interface UseDrawerResizeProps {\n enabled: boolean;\n position: DrawerPosition;\n element: HTMLElement | null | undefined;\n}\n\nexport interface UseDrawerResizeResult {\n sizeStyle: CSSProperties | undefined;\n isResizing: boolean;\n isHovered: boolean;\n isPlacing: boolean;\n /** Whether the event is the Escape that cancelled a resize, so it shouldn't close the drawer. */\n isCancelResizeEvent: (event?: Event) => boolean;\n separatorProps: SeparatorProps;\n guideProps: GuideProps;\n}\n\nconst KEYBOARD_STEP = 8;\nconst PROBE_SIZE = 1e6;\n// A press that moves less than this is a click on the handle, not a drag.\nconst CLICK_THRESHOLD = 4;\n\nconst isElement = (target: EventTarget | null): target is Element =>\n target !== null && (target as Node).nodeType === 1;\n\nconst focusWithoutRing = (element: HTMLElement | null) =>\n element?.focus({\n preventScroll: true,\n focusVisible: false,\n } as FocusOptions);\n\n/** Shows the cursor everywhere in the document, over any element's own cursor. */\nconst setDocumentCursor = (ownerDocument: Document, cursor: string) => {\n const view = ownerDocument.defaultView as (Window & typeof globalThis) | null;\n if (!view || !ownerDocument.adoptedStyleSheets) return undefined;\n const sheet = new view.CSSStyleSheet();\n sheet.replaceSync(`*, *:hover { cursor: ${cursor} !important; }`);\n ownerDocument.adoptedStyleSheets = [\n ...ownerDocument.adoptedStyleSheets,\n sheet,\n ];\n return () => {\n ownerDocument.adoptedStyleSheets = ownerDocument.adoptedStyleSheets.filter(\n (adopted) => adopted !== sheet,\n );\n };\n};\n\nconst isHorizontal = (position: DrawerPosition) =>\n position === \"left\" || position === \"right\";\n\nconst growsWithCoordinate = (position: DrawerPosition) =>\n position === \"left\" || position === \"top\";\n\nconst measure = (element: HTMLElement, horizontal: boolean) => {\n const { width, height } = element.getBoundingClientRect();\n return horizontal ? width : height;\n};\n\nconst restoreStyle = (\n style: CSSStyleDeclaration,\n property: string,\n value: string,\n priority: string,\n) => {\n if (value) {\n style.setProperty(property, value, priority);\n } else {\n style.removeProperty(property);\n }\n};\n\n/** Resolves the drawer's CSS min/max size by briefly forcing it to both extremes. */\nconst probeBounds = (element: HTMLElement, horizontal: boolean): Bounds => {\n const property = horizontal ? \"width\" : \"height\";\n const { style } = element;\n const previousValue = style.getPropertyValue(property);\n const previousPriority = style.getPropertyPriority(property);\n const previousTransition = style.getPropertyValue(\"transition-property\");\n const previousTransitionPriority = style.getPropertyPriority(\n \"transition-property\",\n );\n\n // A transition would report the current size at both extremes.\n style.setProperty(\"transition-property\", \"none\", \"important\");\n style.setProperty(property, \"0px\", \"important\");\n const min = measure(element, horizontal);\n style.setProperty(property, `${PROBE_SIZE}px`, \"important\");\n const max = measure(element, horizontal);\n\n restoreStyle(style, property, previousValue, previousPriority);\n // Applies the restored size before transitions return, so it doesn't animate.\n measure(element, horizontal);\n restoreStyle(\n style,\n \"transition-property\",\n previousTransition,\n previousTransitionPriority,\n );\n\n return { min, max: Math.max(min, max) };\n};\n\nconst clamp = (value: number, { min, max }: Bounds) =>\n Math.min(Math.max(value, min), max);\n\n/** Size the drawer needs for its moving edge to sit at the given point. */\nconst sizeFromPoint = (\n rect: DOMRect,\n position: DrawerPosition,\n { clientX: x, clientY: y }: Pick<MouseEvent, \"clientX\" | \"clientY\">,\n) => {\n switch (position) {\n case \"left\":\n return x - rect.left;\n case \"right\":\n return rect.right - x;\n case \"top\":\n return y - rect.top;\n case \"bottom\":\n return rect.bottom - y;\n }\n};\n\n/** Viewport coordinate of the moving edge for a given size. */\nconst edgeFromSize = (\n rect: DOMRect,\n position: DrawerPosition,\n size: number,\n) => {\n switch (position) {\n case \"left\":\n return rect.left + size;\n case \"right\":\n return rect.right - size;\n case \"top\":\n return rect.top + size;\n case \"bottom\":\n return rect.bottom - size;\n }\n};\n\nexport function useDrawerResize({\n enabled,\n position,\n element,\n}: UseDrawerResizeProps): UseDrawerResizeResult {\n const horizontal = isHorizontal(position);\n const targetWindow = useWindow();\n\n // Unset until the user resizes, so the drawer keeps its CSS size.\n const [sizeState, setSizeState] = useState<number | undefined>(undefined);\n // Drop the size when `position` switches axis.\n const [sizeAxisHorizontal, setSizeAxisHorizontal] = useState(horizontal);\n const size =\n enabled && sizeAxisHorizontal === horizontal ? sizeState : undefined;\n\n const [interaction, setInteraction] = useState<Interaction>(\"inactive\");\n const [metrics, setMetrics] = useState<(Bounds & { current: number }) | null>(\n null,\n );\n const dragRef = useRef<DragState | null>(null);\n const placingRef = useRef<PlacingState | null>(null);\n const handleRef = useRef<HTMLElement | null>(null);\n const guideRef = useRef<HTMLElement | null>(null);\n const cancelResizeEventRef = useRef<Event | null>(null);\n const restoreSizeRef = useRef<number | null>(null);\n const initialSizeRef = useRef<number | null>(null);\n const axisRef = useRef(horizontal);\n\n // Probing forces layout, so key presses reuse the last bounds.\n const boundsRef = useRef<Bounds | null>(null);\n\n const readMetrics = useEventCallback((reuseBounds = false) => {\n if (!element) return null;\n const bounds =\n reuseBounds && boundsRef.current\n ? boundsRef.current\n : probeBounds(element, horizontal);\n boundsRef.current = bounds;\n const current = clamp(measure(element, horizontal), bounds);\n const next = { ...bounds, current };\n setMetrics(next);\n return next;\n });\n\n const applySize = (nextSize: number) => {\n setSizeState(nextSize);\n setSizeAxisHorizontal(horizontal);\n };\n\n const isOverHandle = ({\n clientX: x,\n clientY: y,\n }: Pick<MouseEvent, \"clientX\" | \"clientY\">) => {\n const rect = handleRef.current?.getBoundingClientRect();\n return (\n rect !== undefined &&\n x >= rect.left &&\n x <= rect.right &&\n y >= rect.top &&\n y <= rect.bottom\n );\n };\n\n const isHandle = useEventCallback(\n (target: EventTarget | null) =>\n enabled &&\n isElement(target) &&\n handleRef.current?.contains(target) === true,\n );\n\n const startDrag = useEventCallback((event: PointerEvent) => {\n const current = readMetrics();\n if (!current) return;\n\n event.preventDefault();\n dragRef.current = {\n pointerId: event.pointerId,\n startX: event.clientX,\n startY: event.clientY,\n originSize: current.current,\n previousSize: current.current,\n cancelSize: size,\n min: current.min,\n max: current.max,\n moved: false,\n };\n focusWithoutRing(handleRef.current);\n setInteraction(\"active\");\n });\n\n const moveDrag = useEventCallback((event: PointerEvent, drag: DragState) => {\n // Small movement keeps the press a click, so it can start placing the edge by click.\n if (!drag.moved) {\n if (\n Math.hypot(event.clientX - drag.startX, event.clientY - drag.startY) <\n CLICK_THRESHOLD\n ) {\n return;\n }\n drag.moved = true;\n try {\n handleRef.current?.setPointerCapture(event.pointerId);\n } catch {\n // The pointer is no longer active.\n }\n }\n\n const coordinate = horizontal ? event.clientX : event.clientY;\n const origin = horizontal ? drag.startX : drag.startY;\n const direction = growsWithCoordinate(position) ? 1 : -1;\n const nextSize = clamp(\n drag.originSize + (coordinate - origin) * direction,\n drag,\n );\n if (nextSize !== drag.previousSize) {\n drag.previousSize = nextSize;\n applySize(nextSize);\n }\n });\n\n // Set directly, to avoid a re-render on every pointer move.\n const moveGuide = (offset: number) => {\n const placing = placingRef.current;\n if (!placing) return;\n placing.guideOffset = offset;\n guideRef.current?.style.setProperty(\n \"--drawerResizeGuide-offset\",\n `${offset}px`,\n );\n };\n\n const setGuide = useCallback((node: HTMLElement | null) => {\n guideRef.current = node;\n const placing = placingRef.current;\n if (node && placing) {\n node.style.setProperty(\n \"--drawerResizeGuide-offset\",\n `${placing.guideOffset}px`,\n );\n }\n }, []);\n\n const startPlacing = useEventCallback((drag: DragState) => {\n if (!element) return;\n placingRef.current = {\n min: drag.min,\n max: drag.max,\n guideOffset: edgeFromSize(\n element.getBoundingClientRect(),\n position,\n drag.originSize,\n ),\n pressed: false,\n };\n setInteraction(\"placing\");\n });\n\n const stopPlacing = useEventCallback(() => {\n if (!placingRef.current) return;\n placingRef.current = null;\n setInteraction(\"inactive\");\n });\n\n const endDrag = useEventCallback((event: Event) => {\n const drag = dragRef.current;\n if (!drag) return;\n dragRef.current = null;\n // Pointer capture retargets the release to the handle.\n const pointer = event as PointerEvent;\n const stillHovered =\n \"pointerType\" in event &&\n pointer.pointerType !== \"touch\" &&\n isHandle(\n handleRef.current?.ownerDocument.elementFromPoint(\n pointer.clientX,\n pointer.clientY,\n ) ?? null,\n );\n setInteraction(stillHovered ? \"hover\" : \"inactive\");\n });\n\n const cancelDrag = useEventCallback((event: KeyboardEvent) => {\n const drag = dragRef.current;\n if (!drag) return;\n const handle = handleRef.current;\n if (handle?.hasPointerCapture(drag.pointerId)) {\n handle.releasePointerCapture(drag.pointerId);\n }\n setSizeState(drag.cancelSize);\n endDrag(event);\n });\n\n const sizeToPlace = (\n target: HTMLElement,\n rect: DOMRect,\n point: Pick<MouseEvent, \"clientX\" | \"clientY\">,\n bounds: Bounds,\n ) =>\n clamp(\n isOverHandle(point)\n ? measure(target, horizontal)\n : sizeFromPoint(rect, position, point),\n bounds,\n );\n\n const moveGuideToPointer = (\n event: Pick<MouseEvent, \"clientX\" | \"clientY\">,\n ) => {\n const placing = placingRef.current;\n if (!placing || !element) return;\n const rect = element.getBoundingClientRect();\n moveGuide(\n edgeFromSize(rect, position, sizeToPlace(element, rect, event, placing)),\n );\n };\n\n const onGuidePointerDown = useEventCallback(\n (event: ReactPointerEvent<HTMLElement>) => {\n const placing = placingRef.current;\n if (!placing) return;\n if (event.pointerType === \"mouse\" && event.button > 0) {\n stopPlacing();\n return;\n }\n // Keeps focus on the handle.\n event.preventDefault();\n // React bubbles events from the portal up to the drawer.\n event.stopPropagation();\n placing.pressed = true;\n moveGuideToPointer(event);\n },\n );\n\n const onGuidePointerMove = useEventCallback(\n (event: ReactPointerEvent<HTMLElement>) => {\n moveGuideToPointer(event);\n },\n );\n\n const onGuideClick = useEventCallback(\n (event: ReactMouseEvent<HTMLElement>) => {\n const placing = placingRef.current;\n // Ignores the click that started placing.\n if (!placing?.pressed || !element) return;\n event.stopPropagation();\n stopPlacing();\n // The drawer may have moved since placing started, e.g. while sliding in.\n const rect = element.getBoundingClientRect();\n const nextSize = sizeToPlace(element, rect, event, placing);\n const current = clamp(measure(element, horizontal), placing);\n if (nextSize !== current) {\n applySize(nextSize);\n }\n focusWithoutRing(handleRef.current);\n },\n );\n\n useEffect(() => {\n if (!enabled || !element || !targetWindow) return;\n const ownerDocument = targetWindow.document;\n\n const onPointerDown = (event: PointerEvent) => {\n if (event.defaultPrevented || !event.isPrimary) return;\n if (event.pointerType === \"mouse\" && event.button > 0) return;\n if (placingRef.current || dragRef.current || !isHandle(event.target)) {\n return;\n }\n startDrag(event);\n };\n\n const onPointerMove = (event: PointerEvent) => {\n if (event.defaultPrevented) return;\n if (placingRef.current) return;\n const drag = dragRef.current;\n if (!drag) {\n // Touch has no hover, so it would leave the hover state behind.\n if (event.pointerType !== \"touch\") {\n setInteraction(isHandle(event.target) ? \"hover\" : \"inactive\");\n }\n return;\n }\n if (event.pointerId !== drag.pointerId) return;\n // No buttons pressed means the release was missed, e.g. over an iframe.\n if (event.buttons === 0) {\n endDrag(event);\n return;\n }\n moveDrag(event, drag);\n };\n\n const onPointerUp = (event: PointerEvent) => {\n if (event.defaultPrevented) return;\n if (event.pointerType === \"mouse\" && event.button > 0) return;\n const drag = dragRef.current;\n if (drag?.pointerId !== event.pointerId) return;\n event.preventDefault();\n if (!drag.moved) {\n dragRef.current = null;\n startPlacing(drag);\n return;\n }\n endDrag(event);\n };\n\n const onPointerCancel = (event: PointerEvent) => {\n if (dragRef.current?.pointerId === event.pointerId) endDrag(event);\n };\n\n const onContextMenu = (event: MouseEvent) => {\n if (!event.defaultPrevented) endDrag(event);\n };\n\n const onKeyDown = (event: KeyboardEvent) => {\n if (event.key !== \"Escape\" || !dragRef.current) return;\n event.preventDefault();\n cancelResizeEventRef.current = event;\n cancelDrag(event);\n };\n\n const onBlur = (event: FocusEvent) => {\n endDrag(event);\n stopPlacing();\n };\n\n // \"pointerout\" doesn't fire when the pointer moves into an iframe, so hover would stick.\n const onPointerOut = (event: PointerEvent) => {\n if (\n !dragRef.current &&\n isElement(event.relatedTarget) &&\n event.relatedTarget.tagName === \"IFRAME\"\n ) {\n setInteraction(\"inactive\");\n }\n };\n\n ownerDocument.addEventListener(\"pointerdown\", onPointerDown, true);\n ownerDocument.addEventListener(\"pointermove\", onPointerMove);\n ownerDocument.addEventListener(\"pointerup\", onPointerUp, true);\n ownerDocument.addEventListener(\"pointercancel\", onPointerCancel);\n ownerDocument.addEventListener(\"contextmenu\", onContextMenu, true);\n // Capture, to run before the drawer closes on Escape.\n ownerDocument.addEventListener(\"keydown\", onKeyDown, true);\n ownerDocument.addEventListener(\"pointerout\", onPointerOut);\n targetWindow.addEventListener(\"blur\", onBlur);\n return () => {\n ownerDocument.removeEventListener(\"pointerdown\", onPointerDown, true);\n ownerDocument.removeEventListener(\"pointermove\", onPointerMove);\n ownerDocument.removeEventListener(\"pointerup\", onPointerUp, true);\n ownerDocument.removeEventListener(\"pointercancel\", onPointerCancel);\n ownerDocument.removeEventListener(\"contextmenu\", onContextMenu, true);\n ownerDocument.removeEventListener(\"keydown\", onKeyDown, true);\n ownerDocument.removeEventListener(\"pointerout\", onPointerOut);\n targetWindow.removeEventListener(\"blur\", onBlur);\n dragRef.current = null;\n placingRef.current = null;\n setInteraction(\"inactive\");\n };\n }, [\n enabled,\n element,\n targetWindow,\n isHandle,\n startDrag,\n moveDrag,\n endDrag,\n cancelDrag,\n startPlacing,\n stopPlacing,\n ]);\n\n const showResizeCursor = interaction !== \"inactive\";\n useEffect(() => {\n if (!showResizeCursor || !targetWindow) return;\n return setDocumentCursor(\n targetWindow.document,\n horizontal\n ? \"var(--salt-cursor-drag-ew, ew-resize)\"\n : \"var(--salt-cursor-drag-ns, ns-resize)\",\n );\n }, [showResizeCursor, targetWindow, horizontal]);\n\n const onKeyDown = useEventCallback(\n (event: ReactKeyboardEvent<HTMLElement>) => {\n const { key } = event;\n if (placingRef.current) {\n stopPlacing();\n if (key === \"Escape\") {\n event.preventDefault();\n cancelResizeEventRef.current = event.nativeEvent;\n return;\n }\n }\n const resizeKeys = horizontal\n ? [\"ArrowLeft\", \"ArrowRight\"]\n : [\"ArrowUp\", \"ArrowDown\"];\n if (\n !resizeKeys.includes(key) &&\n key !== \"Home\" &&\n key !== \"End\" &&\n key !== \"Enter\"\n ) {\n return;\n }\n\n const current = readMetrics(true);\n if (!current) return;\n\n event.preventDefault();\n\n const collapsed = current.current <= current.min + 1;\n let nextSize: number;\n if (key === \"Home\") {\n if (!collapsed) {\n restoreSizeRef.current = current.current;\n }\n nextSize = current.min;\n } else if (key === \"End\") {\n nextSize = current.max;\n } else if (key === \"Enter\") {\n if (collapsed) {\n nextSize =\n restoreSizeRef.current ?? initialSizeRef.current ?? current.max;\n } else {\n restoreSizeRef.current = current.current;\n nextSize = current.min;\n }\n } else {\n const towardsHigherCoordinate =\n key === \"ArrowRight\" || key === \"ArrowDown\";\n const direction =\n towardsHigherCoordinate === growsWithCoordinate(position) ? 1 : -1;\n nextSize = current.current + KEYBOARD_STEP * direction;\n }\n\n nextSize = clamp(nextSize, current);\n if (nextSize === current.current) return;\n applySize(nextSize);\n },\n );\n\n const isCancelResizeEvent = useCallback(\n (event?: Event) =>\n event !== undefined && event === cancelResizeEventRef.current,\n [],\n );\n\n const onFocus = useCallback(() => {\n if (!dragRef.current) readMetrics();\n }, [readMetrics]);\n\n const setHandle = useCallback((node: HTMLElement | null) => {\n handleRef.current = node;\n }, []);\n\n useEffect(() => {\n if (!enabled) {\n setSizeState(undefined);\n setMetrics(null);\n restoreSizeRef.current = null;\n initialSizeRef.current = null;\n }\n }, [enabled]);\n\n useIsomorphicLayoutEffect(() => {\n if (!enabled || !element) return;\n if (axisRef.current !== horizontal) {\n axisRef.current = horizontal;\n restoreSizeRef.current = null;\n initialSizeRef.current = null;\n }\n const next = readMetrics();\n if (next && initialSizeRef.current === null) {\n initialSizeRef.current = next.current;\n }\n }, [enabled, element, horizontal, readMetrics]);\n\n // biome-ignore lint/correctness/useExhaustiveDependencies: re-syncs the separator's aria values whenever the size changes.\n useIsomorphicLayoutEffect(() => {\n if (!enabled || !element) return;\n readMetrics(true);\n }, [enabled, element, size, readMetrics]);\n\n useEffect(() => {\n if (!enabled || !element || !targetWindow) return;\n const onResize = () => {\n // The size limits stored for placing are stale after the window resizes.\n stopPlacing();\n readMetrics();\n };\n targetWindow.addEventListener(\"resize\", onResize);\n return () => targetWindow.removeEventListener(\"resize\", onResize);\n }, [enabled, element, targetWindow, readMetrics, stopPlacing]);\n\n return {\n sizeStyle:\n size !== undefined\n ? { [horizontal ? \"width\" : \"height\"]: size }\n : undefined,\n isResizing: interaction === \"active\" || interaction === \"placing\",\n isHovered: interaction === \"hover\",\n isPlacing: interaction === \"placing\",\n isCancelResizeEvent,\n separatorProps: {\n role: \"separator\",\n tabIndex: 0,\n ref: setHandle,\n \"aria-orientation\": horizontal ? \"vertical\" : \"horizontal\",\n \"aria-valuenow\": metrics ? Math.round(metrics.current) : undefined,\n \"aria-valuemin\": metrics ? Math.round(metrics.min) : undefined,\n \"aria-valuemax\": metrics ? Math.round(metrics.max) : undefined,\n onKeyDown,\n onFocus,\n },\n guideProps: {\n ref: setGuide,\n onPointerDown: onGuidePointerDown,\n onPointerMove: onGuidePointerMove,\n onClick: onGuideClick,\n onContextMenu: stopPlacing,\n },\n };\n}\n"],"names":["onKeyDown"],"mappings":"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"}
|
|
@@ -34,6 +34,7 @@ const InteractableCard = forwardRef(function InteractableCard2(props, ref) {
|
|
|
34
34
|
onClick,
|
|
35
35
|
onKeyUp,
|
|
36
36
|
onKeyDown,
|
|
37
|
+
tabIndex: tabIndexProp,
|
|
37
38
|
...rest
|
|
38
39
|
} = props;
|
|
39
40
|
const targetWindow = useWindow();
|
|
@@ -128,7 +129,7 @@ const InteractableCard = forwardRef(function InteractableCard2(props, ref) {
|
|
|
128
129
|
...rest,
|
|
129
130
|
onClick: handleClick,
|
|
130
131
|
ref: handleRef,
|
|
131
|
-
tabIndex,
|
|
132
|
+
tabIndex: tabIndexProp ?? tabIndex,
|
|
132
133
|
children
|
|
133
134
|
}
|
|
134
135
|
)
|
|
@@ -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":["InteractableCard","interactableCardCss"],"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":["InteractableCard","interactableCardCss"],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
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";
|
|
1
|
+
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";
|
|
2
2
|
|
|
3
3
|
export { css_248z as default };
|
|
4
4
|
//# sourceMappingURL=LinkButton.css.js.map
|
|
@@ -4,7 +4,7 @@ const COLUMN_SELECTOR = "[data-mega-menu-column]";
|
|
|
4
4
|
const ACTIONS_SELECTOR = "[data-mega-menu-actions]";
|
|
5
5
|
const FOCUSABLE_SELECTOR = 'a[href], button:not([disabled]), [tabindex]:not([tabindex="-1"])';
|
|
6
6
|
const SELF_CONSUMING_SELECTOR = 'input, textarea, select, [contenteditable], [role="combobox"], [role="listbox"], [role="slider"], [role="spinbutton"], [role="textbox"]';
|
|
7
|
-
const HIDDEN_ANCESTOR_SELECTOR = '[aria-hidden="true"], [inert]';
|
|
7
|
+
const HIDDEN_ANCESTOR_SELECTOR = '[aria-hidden="true"], [inert], [data-floating-ui-focus-guard]';
|
|
8
8
|
function queryFocusables(root) {
|
|
9
9
|
return Array.from(
|
|
10
10
|
root.querySelectorAll(FOCUSABLE_SELECTOR)
|
|
@@ -192,27 +192,18 @@ function handleArrow(key, cell, panel, context) {
|
|
|
192
192
|
}
|
|
193
193
|
return false;
|
|
194
194
|
}
|
|
195
|
-
function
|
|
195
|
+
function findNextAfterPanel(context, panel) {
|
|
196
196
|
var _a;
|
|
197
197
|
const reference = context.elements.reference;
|
|
198
198
|
const refFocusable = firstFocusable(reference) ?? reference;
|
|
199
199
|
const nextLi = (_a = refFocusable == null ? void 0 : refFocusable.closest("li")) == null ? void 0 : _a.nextElementSibling;
|
|
200
200
|
const nextSibling = nextLi instanceof HTMLElement ? firstFocusable(nextLi) : null;
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
})();
|
|
208
|
-
if (nextOutside) {
|
|
209
|
-
const view = panel.ownerDocument.defaultView;
|
|
210
|
-
view == null ? void 0 : view.requestAnimationFrame(() => {
|
|
211
|
-
view == null ? void 0 : view.requestAnimationFrame(() => {
|
|
212
|
-
nextOutside.focus();
|
|
213
|
-
});
|
|
214
|
-
});
|
|
215
|
-
}
|
|
201
|
+
if (nextSibling) return nextSibling;
|
|
202
|
+
const allFocusable = queryFocusables(
|
|
203
|
+
panel.ownerDocument.documentElement
|
|
204
|
+
).filter((el) => !panel.contains(el));
|
|
205
|
+
const idx = refFocusable ? allFocusable.indexOf(refFocusable) : -1;
|
|
206
|
+
return idx >= 0 ? allFocusable[idx + 1] : void 0;
|
|
216
207
|
}
|
|
217
208
|
function useMegaMenuNavigation(context, props = {}) {
|
|
218
209
|
const { enabled = true } = props;
|
|
@@ -224,7 +215,7 @@ function useMegaMenuNavigation(context, props = {}) {
|
|
|
224
215
|
return {
|
|
225
216
|
floating: {
|
|
226
217
|
onKeyDown(event) {
|
|
227
|
-
var _a, _b;
|
|
218
|
+
var _a, _b, _c;
|
|
228
219
|
if (!open) return;
|
|
229
220
|
const panel = event.currentTarget;
|
|
230
221
|
const target = event.target;
|
|
@@ -246,10 +237,10 @@ function useMegaMenuNavigation(context, props = {}) {
|
|
|
246
237
|
(_a = allCells[linearIndex - 1]) == null ? void 0 : _a.focus();
|
|
247
238
|
}
|
|
248
239
|
} else if (linearIndex === allCells.length - 1) {
|
|
240
|
+
(_b = findNextAfterPanel(context, panel)) == null ? void 0 : _b.focus();
|
|
249
241
|
onOpenChange(false);
|
|
250
|
-
focusNextAfterPanel(context, panel);
|
|
251
242
|
} else {
|
|
252
|
-
(
|
|
243
|
+
(_c = allCells[linearIndex + 1]) == null ? void 0 : _c.focus();
|
|
253
244
|
}
|
|
254
245
|
return;
|
|
255
246
|
}
|
|
@@ -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":[],"mappings":";;AAGA,MAAM,eAAA,GAAkB,yBAAA;AACxB,MAAM,gBAAA,GAAmB,0BAAA;AAElB,MAAM,kBAAA,GACX;AAIF,MAAM,uBAAA,GACJ,yIAAA;AAIF,MAAM,wBAAA,GAA2B,+BAAA;AAEjC,SAAS,gBAAgB,IAAA,EAAkC;AACzD,EAAA,OAAO,KAAA,CAAM,IAAA;AAAA,IACX,IAAA,CAAK,iBAA8B,kBAAkB;AAAA,GACvD,CAAE,OAAO,CAAC,EAAA,KAAO,CAAC,EAAA,CAAG,OAAA,CAAQ,wBAAwB,CAAC,CAAA;AACxD;AAEA,SAAS,eAAe,IAAA,EAA8C;AACpE,EAAA,OAAO,OAAQ,eAAA,CAAgB,IAAI,CAAA,CAAE,CAAC,KAAK,IAAA,GAAQ,IAAA;AACrD;AAUA,SAAS,WAAW,KAAA,EAA8B;AAChD,EAAA,MAAM,UAAU,KAAA,CAAM,IAAA;AAAA,IACpB,KAAA,CAAM,iBAA8B,eAAe;AAAA,GACrD,CAAE,OAAO,CAAC,EAAA,KAAO,gBAAgB,EAAE,CAAA,CAAE,SAAS,CAAC,CAAA;AAE/C,EAAA,MAAM,UAAU,KAAA,CAAM,IAAA;AAAA,IACpB,KAAA,CAAM,iBAA8B,gBAAgB;AAAA,GACtD,CAAE,OAAO,CAAC,EAAA,KAAO,gBAAgB,EAAE,CAAA,CAAE,SAAS,CAAC,CAAA;AAE/C,EAAA,OAAO,EAAE,SAAS,OAAA,EAAQ;AAC5B;AAEA,SAAS,aAAa,OAAA,EAA8B;AAhDpD,EAAA,IAAA,EAAA;AAiDE,EAAA,MAAM,SAAA,GAAY,QAAQ,QAAA,CAAS,SAAA;AACnC,EAAA,CAAC,EAAA,GAAA,cAAA,CAAe,SAAS,CAAA,IAAK,SAAA,KAA7B,IAAA,GAAA,MAAA,GAAA,EAAA,CAAyC,KAAA,EAAA;AAC5C;AAGA,SAAS,yBAAyB,OAAA,EAAuC;AACvE,EAAA,MAAM,SAAA,GAAY,QAAQ,QAAA,CAAS,SAAA;AACnC,EAAA,MAAM,OAAA,GAAU,cAAA,CAAe,SAAS,CAAA,IAAK,SAAA;AAC7C,EAAA,MAAM,EAAA,GAAK,mCAAS,OAAA,CAAQ,IAAA,CAAA;AAC5B,EAAA,MAAM,QACJ,EAAA,IAAA,IAAA,GAAA,MAAA,GAAA,EAAA,CAAI,kBAAA,aAA8B,cAC9B,cAAA,CAAe,EAAA,CAAG,kBAAkB,CAAA,GACpC,IAAA;AACN,EAAA,IAAI,IAAA,EAAM;AACR,IAAA,OAAA,CAAQ,aAAa,KAAK,CAAA;AAC1B,IAAA,IAAA,CAAK,KAAA,EAAM;AACX,IAAA,OAAO,IAAA;AAAA,EACT;AACA,EAAA,OAAO,KAAA;AACT;AAGA,SAAS,eAAe,OAAA,EAAiC;AACvD,EAAA,IAAI,OAAA,CAAQ,MAAA,GAAS,CAAA,EAAG,OAAO,KAAA;AAC/B,EAAA,MAAM,KAAA,GAAQ,OAAA,CAAQ,CAAC,CAAA,CAAE,qBAAA,EAAsB;AAC/C,EAAA,MAAM,MAAA,GAAS,OAAA,CAAQ,CAAC,CAAA,CAAE,qBAAA,EAAsB;AAChD,EAAA,OAAO,MAAA,CAAO,GAAA,IAAO,KAAA,CAAM,MAAA,GAAS,CAAA;AACtC;AAGA,SAAS,YAAA,CACP,GAAA,EACA,IAAA,EACA,KAAA,EACA,OAAA,EACS;AApFX,EAAA,IAAA,EAAA,EAAA,EAAA;AAqFE,EAAA,MAAM,KAAA,GAAQ,gBAAgB,KAAK,CAAA;AACnC,EAAA,MAAM,KAAA,GAAQ,KAAA,CAAM,OAAA,CAAQ,IAAI,CAAA;AAChC,EAAA,IAAI,KAAA,KAAU,IAAI,OAAO,KAAA;AAEzB,EAAA,QAAQ,GAAA;AAAK,IACX,KAAK,WAAA;AAAA,IACL,KAAK,YAAA,EAAc;AACjB,MAAA,IAAI,KAAA,GAAQ,KAAA,CAAM,MAAA,GAAS,CAAA,EAAG;AAC5B,QAAA,KAAA,CAAM,KAAA,GAAQ,CAAC,CAAA,CAAE,KAAA,EAAM;AAAA,MACzB;AACA,MAAA,OAAO,IAAA;AAAA,IACT;AAAA,IACA,KAAK,SAAA;AAAA,IACL,KAAK,WAAA,EAAa;AAChB,MAAA,IAAI,QAAQ,CAAA,EAAG;AACb,QAAA,KAAA,CAAM,KAAA,GAAQ,CAAC,CAAA,CAAE,KAAA,EAAM;AAAA,MACzB,CAAA,MAAO;AACL,QAAA,YAAA,CAAa,OAAO,CAAA;AAAA,MACtB;AACA,MAAA,OAAO,IAAA;AAAA,IACT;AAAA,IACA,KAAK,MAAA,EAAQ;AACX,MAAA,CAAA,EAAA,GAAA,KAAA,CAAM,CAAC,MAAP,IAAA,GAAA,MAAA,GAAA,EAAA,CAAU,KAAA,EAAA;AACV,MAAA,OAAO,IAAA;AAAA,IACT;AAAA,IACA,KAAK,KAAA,EAAO;AACV,MAAA,CAAA,EAAA,GAAA,KAAA,CAAM,KAAA,CAAM,MAAA,GAAS,CAAC,CAAA,KAAtB,IAAA,GAAA,MAAA,GAAA,EAAA,CAAyB,KAAA,EAAA;AACzB,MAAA,OAAO,IAAA;AAAA,IACT;AAAA,IACA;AACE,MAAA,OAAO,KAAA;AAAA;AAEb;AAGA,SAAS,WAAA,CACP,GAAA,EACA,IAAA,EACA,KAAA,EACA,OAAA,EACS;AA7HX,EAAA,IAAA,EAAA,EAAA,EAAA,EAAA,EAAA,EAAA,EAAA,EAAA,EAAA,EAAA,EAAA,EAAA,EAAA,EAAA,EAAA,EAAA,EAAA;AA8HE,EAAA,MAAM,EAAE,OAAA,EAAS,OAAA,EAAQ,GAAI,WAAW,KAAK,CAAA;AAE7C,EAAA,IAAI,cAAA,CAAe,OAAO,CAAA,EAAG;AAC3B,IAAA,OAAO,YAAA,CAAa,GAAA,EAAK,IAAA,EAAM,KAAA,EAAO,OAAO,CAAA;AAAA,EAC/C;AAEA,EAAA,MAAM,MAAA,GAAS,IAAA,CAAK,OAAA,CAAqB,eAAe,CAAA;AACxD,EAAA,MAAM,SAAA,GAAY,IAAA,CAAK,OAAA,CAAqB,gBAAgB,CAAA;AAE5D,EAAA,IAAI,MAAA,EAAQ;AACV,IAAA,MAAM,QAAA,GAAW,OAAA,CAAQ,OAAA,CAAQ,MAAM,CAAA;AACvC,IAAA,MAAM,KAAA,GAAQ,gBAAgB,MAAM,CAAA;AACpC,IAAA,MAAM,QAAA,GAAW,KAAA,CAAM,OAAA,CAAQ,IAAI,CAAA;AAEnC,IAAA,QAAQ,GAAA;AAAK,MACX,KAAK,WAAA,EAAa;AAChB,QAAA,IAAI,QAAA,GAAW,KAAA,CAAM,MAAA,GAAS,CAAA,EAAG;AAC/B,UAAA,KAAA,CAAM,QAAA,GAAW,CAAC,CAAA,CAAE,KAAA,EAAM;AAAA,QAC5B,CAAA,MAAA,IAAW,QAAA,GAAW,OAAA,CAAQ,MAAA,GAAS,CAAA,EAAG;AACxC,UAAA,CAAA,EAAA,GAAA,cAAA,CAAe,OAAA,CAAQ,QAAA,GAAW,CAAC,CAAC,MAApC,IAAA,GAAA,MAAA,GAAA,EAAA,CAAuC,KAAA,EAAA;AAAA,QACzC,CAAA,MAAA,IAAW,OAAA,CAAQ,MAAA,GAAS,CAAA,EAAG;AAC7B,UAAA,CAAA,EAAA,GAAA,cAAA,CAAe,OAAA,CAAQ,CAAC,CAAC,CAAA,KAAzB,IAAA,GAAA,MAAA,GAAA,EAAA,CAA4B,KAAA,EAAA;AAAA,QAC9B,CAAA,MAAO;AACL,UAAA,wBAAA,CAAyB,OAAO,CAAA;AAAA,QAClC;AACA,QAAA,OAAO,IAAA;AAAA,MACT;AAAA,MACA,KAAK,SAAA,EAAW;AACd,QAAA,IAAI,WAAW,CAAA,EAAG;AAChB,UAAA,KAAA,CAAM,QAAA,GAAW,CAAC,CAAA,CAAE,KAAA,EAAM;AAAA,QAC5B,CAAA,MAAO;AACL,UAAA,YAAA,CAAa,OAAO,CAAA;AAAA,QACtB;AACA,QAAA,OAAO,IAAA;AAAA,MACT;AAAA,MACA,KAAK,YAAA,EAAc;AACjB,QAAA,IAAI,QAAA,GAAW,OAAA,CAAQ,MAAA,GAAS,CAAA,EAAG;AACjC,UAAA,CAAA,EAAA,GAAA,cAAA,CAAe,OAAA,CAAQ,QAAA,GAAW,CAAC,CAAC,MAApC,IAAA,GAAA,MAAA,GAAA,EAAA,CAAuC,KAAA,EAAA;AACvC,UAAA,OAAO,IAAA;AAAA,QACT;AAEA,QAAA,IACE,aAAa,KAAA,CAAM,MAAA,GAAS,CAAA,IAC5B,wBAAA,CAAyB,OAAO,CAAA,EAChC;AACA,UAAA,OAAO,IAAA;AAAA,QACT;AAGA,QAAA,YAAA,CAAa,OAAO,CAAA;AACpB,QAAA,OAAO,IAAA;AAAA,MACT;AAAA,MACA,KAAK,WAAA,EAAa;AAChB,QAAA,IAAI,WAAW,CAAA,EAAG;AAChB,UAAA,CAAA,EAAA,GAAA,cAAA,CAAe,OAAA,CAAQ,QAAA,GAAW,CAAC,CAAC,MAApC,IAAA,GAAA,MAAA,GAAA,EAAA,CAAuC,KAAA,EAAA;AAAA,QACzC,CAAA,MAAO;AACL,UAAA,YAAA,CAAa,OAAO,CAAA;AAAA,QACtB;AACA,QAAA,OAAO,IAAA;AAAA,MACT;AAAA,MACA,KAAK,MAAA,EAAQ;AACX,QAAA,CAAA,EAAA,GAAA,KAAA,CAAM,CAAC,MAAP,IAAA,GAAA,MAAA,GAAA,EAAA,CAAU,KAAA,EAAA;AACV,QAAA,OAAO,IAAA;AAAA,MACT;AAAA,MACA,KAAK,KAAA,EAAO;AACV,QAAA,CAAA,EAAA,GAAA,KAAA,CAAM,KAAA,CAAM,MAAA,GAAS,CAAC,CAAA,KAAtB,IAAA,GAAA,MAAA,GAAA,EAAA,CAAyB,KAAA,EAAA;AACzB,QAAA,OAAO,IAAA;AAAA,MACT;AAAA,MACA;AACE,QAAA,OAAO,KAAA;AAAA;AACX,EACF;AAEA,EAAA,IAAI,SAAA,EAAW;AACb,IAAA,MAAM,KAAA,GAAQ,gBAAgB,SAAS,CAAA;AACvC,IAAA,MAAM,KAAA,GAAQ,KAAA,CAAM,OAAA,CAAQ,IAAI,CAAA;AAEhC,IAAA,QAAQ,GAAA;AAAK,MACX,KAAK,YAAA,EAAc;AACjB,QAAA,IAAI,KAAA,GAAQ,KAAA,CAAM,MAAA,GAAS,CAAA,EAAG;AAC5B,UAAA,KAAA,CAAM,KAAA,GAAQ,CAAC,CAAA,CAAE,KAAA,EAAM;AAAA,QACzB,CAAA,MAAA,IAAW,CAAC,wBAAA,CAAyB,OAAO,CAAA,EAAG;AAE7C,UAAA,YAAA,CAAa,OAAO,CAAA;AAAA,QACtB;AACA,QAAA,OAAO,IAAA;AAAA,MACT;AAAA,MACA,KAAK,WAAA,EAAa;AAChB,QAAA,IAAI,QAAQ,CAAA,EAAG;AACb,UAAA,KAAA,CAAM,KAAA,GAAQ,CAAC,CAAA,CAAE,KAAA,EAAM;AAAA,QACzB,CAAA,MAAA,IAAW,IAAA,KAAS,cAAA,CAAe,KAAK,CAAA,EAAG;AACzC,UAAA,YAAA,CAAa,OAAO,CAAA;AAAA,QACtB;AACA,QAAA,OAAO,IAAA;AAAA,MACT;AAAA,MACA,KAAK,SAAA,EAAW;AACd,QAAA,IAAI,OAAA,CAAQ,SAAS,CAAA,EAAG;AACtB,UAAA,MAAM,kBAAkB,eAAA,CAAgB,OAAA,CAAQ,OAAA,CAAQ,MAAA,GAAS,CAAC,CAAC,CAAA;AACnE,UAAA,CAAA,EAAA,GAAA,eAAA,CAAgB,eAAA,CAAgB,MAAA,GAAS,CAAC,CAAA,KAA1C,IAAA,GAAA,MAAA,GAAA,EAAA,CAA6C,KAAA,EAAA;AAAA,QAC/C,CAAA,MAAO;AACL,UAAA,YAAA,CAAa,OAAO,CAAA;AAAA,QACtB;AACA,QAAA,OAAO,IAAA;AAAA,MACT;AAAA,MACA,KAAK,WAAA,EAAa;AAChB,QAAA,IAAI,KAAA,KAAU,KAAA,CAAM,MAAA,GAAS,CAAA,EAAG;AAC9B,UAAA,wBAAA,CAAyB,OAAO,CAAA;AAAA,QAClC;AACA,QAAA,OAAO,IAAA;AAAA,MACT;AAAA,MACA,KAAK,MAAA,EAAQ;AACX,QAAA,CAAA,EAAA,GAAA,KAAA,CAAM,CAAC,MAAP,IAAA,GAAA,MAAA,GAAA,EAAA,CAAU,KAAA,EAAA;AACV,QAAA,OAAO,IAAA;AAAA,MACT;AAAA,MACA,KAAK,KAAA,EAAO;AACV,QAAA,CAAA,EAAA,GAAA,KAAA,CAAM,KAAA,CAAM,MAAA,GAAS,CAAC,CAAA,KAAtB,IAAA,GAAA,MAAA,GAAA,EAAA,CAAyB,KAAA,EAAA;AACzB,QAAA,OAAO,IAAA;AAAA,MACT;AAAA,MACA;AACE,QAAA,OAAO,KAAA;AAAA;AACX,EACF;AAEA,EAAA,OAAO,KAAA;AACT;AAGA,SAAS,mBAAA,CAAoB,SAA8B,KAAA,EAAoB;AA7P/E,EAAA,IAAA,EAAA;AA8PE,EAAA,MAAM,SAAA,GAAY,QAAQ,QAAA,CAAS,SAAA;AACnC,EAAA,MAAM,YAAA,GAAe,cAAA,CAAe,SAAS,CAAA,IAAK,SAAA;AAElD,EAAA,MAAM,MAAA,GAAA,CAAS,EAAA,GAAA,YAAA,IAAA,IAAA,GAAA,MAAA,GAAA,YAAA,CAAc,OAAA,CAAQ,IAAA,CAAA,KAAtB,IAAA,GAAA,MAAA,GAAA,EAAA,CAA6B,kBAAA;AAC5C,EAAA,MAAM,WAAA,GACJ,MAAA,YAAkB,WAAA,GAAc,cAAA,CAAe,MAAM,CAAA,GAAI,IAAA;AAE3D,EAAA,MAAM,WAAA,GACJ,gBACC,MAAM;AACL,IAAA,MAAM,YAAA,GAAe,eAAA;AAAA,MACnB,MAAM,aAAA,CAAc;AAAA,KACtB,CAAE,OAAO,CAAC,EAAA,KAAO,CAAC,KAAA,CAAM,QAAA,CAAS,EAAE,CAAC,CAAA;AACpC,IAAA,MAAM,GAAA,GAAM,YAAA,GAAe,YAAA,CAAa,OAAA,CAAQ,YAAY,CAAA,GAAI,EAAA;AAChE,IAAA,OAAO,GAAA,IAAO,CAAA,GAAI,YAAA,CAAa,GAAA,GAAM,CAAC,CAAA,GAAI,MAAA;AAAA,EAC5C,CAAA,GAAG;AAEL,EAAA,IAAI,WAAA,EAAa;AACf,IAAA,MAAM,IAAA,GAAO,MAAM,aAAA,CAAc,WAAA;AACjC,IAAA,IAAA,IAAA,IAAA,GAAA,MAAA,GAAA,IAAA,CAAM,sBAAsB,MAAM;AAChC,MAAA,IAAA,IAAA,IAAA,GAAA,MAAA,GAAA,IAAA,CAAM,sBAAsB,MAAM;AAChC,QAAA,WAAA,CAAY,KAAA,EAAM;AAAA,MACpB,CAAA,CAAA;AAAA,IACF,CAAA,CAAA;AAAA,EACF;AACF;AAcO,SAAS,qBAAA,CACd,OAAA,EACA,KAAA,GAAoC,EAAC,EACvB;AACd,EAAA,MAAM,EAAE,OAAA,GAAU,IAAA,EAAK,GAAI,KAAA;AAC3B,EAAA,MAAM,EAAE,IAAA,EAAM,YAAA,EAAa,GAAI,OAAA;AAE/B,EAAA,OAAO,QAAQ,MAAM;AACnB,IAAA,IAAI,CAAC,OAAA,EAAS;AACZ,MAAA,OAAO,EAAC;AAAA,IACV;AAEA,IAAA,OAAO;AAAA,MACL,QAAA,EAAU;AAAA,QACR,UAAU,KAAA,EAA4B;AAnT9C,UAAA,IAAA,EAAA,EAAA,EAAA;AAoTU,UAAA,IAAI,CAAC,IAAA,EAAM;AAEX,UAAA,MAAM,QAAQ,KAAA,CAAM,aAAA;AACpB,UAAA,MAAM,SAAS,KAAA,CAAM,MAAA;AACrB,UAAA,MAAM,EAAE,KAAI,GAAI,KAAA;AAEhB,UAAA,MAAM,aAAA,GACJ,GAAA,KAAQ,SAAA,IACR,GAAA,KAAQ,WAAA,IACR,GAAA,KAAQ,WAAA,IACR,GAAA,KAAQ,YAAA,IACR,GAAA,KAAQ,MAAA,IACR,GAAA,KAAQ,KAAA;AAGV,UAAA,IAAI,aAAA,IAAiB,MAAA,CAAO,OAAA,CAAQ,uBAAuB,CAAA,EAAG;AAC5D,YAAA;AAAA,UACF;AAEA,UAAA,MAAM,IAAA,GAAO,MAAA,CAAO,OAAA,CAAqB,kBAAkB,CAAA;AAI3D,UAAA,IAAI,QAAQ,KAAA,EAAO;AACjB,YAAA,MAAM,QAAA,GAAW,gBAAgB,KAAK,CAAA;AACtC,YAAA,MAAM,WAAA,GAAc,IAAA,GAAO,QAAA,CAAS,OAAA,CAAQ,IAAI,CAAA,GAAI,EAAA;AACpD,YAAA,IAAI,gBAAgB,EAAA,EAAI;AACxB,YAAA,KAAA,CAAM,cAAA,EAAe;AACrB,YAAA,IAAI,MAAM,QAAA,EAAU;AAClB,cAAA,IAAI,gBAAgB,CAAA,EAAG;AACrB,gBAAA,YAAA,CAAa,OAAO,CAAA;AAAA,cACtB,CAAA,MAAO;AACL,gBAAA,CAAA,EAAA,GAAA,QAAA,CAAS,WAAA,GAAc,CAAC,CAAA,KAAxB,IAAA,GAAA,MAAA,GAAA,EAAA,CAA2B,KAAA,EAAA;AAAA,cAC7B;AAAA,YACF,CAAA,MAAA,IAAW,WAAA,KAAgB,QAAA,CAAS,MAAA,GAAS,CAAA,EAAG;AAC9C,cAAA,YAAA,CAAa,KAAK,CAAA;AAClB,cAAA,mBAAA,CAAoB,SAAS,KAAK,CAAA;AAAA,YACpC,CAAA,MAAO;AACL,cAAA,CAAA,EAAA,GAAA,QAAA,CAAS,WAAA,GAAc,CAAC,CAAA,KAAxB,IAAA,GAAA,MAAA,GAAA,EAAA,CAA2B,KAAA,EAAA;AAAA,YAC7B;AACA,YAAA;AAAA,UACF;AAEA,UAAA,IAAI,CAAC,IAAA,IAAQ,CAAC,aAAA,EAAe;AAE7B,UAAA,IAAI,WAAA,CAAY,GAAA,EAAK,IAAA,EAAM,KAAA,EAAO,OAAO,CAAA,EAAG;AAC1C,YAAA,KAAA,CAAM,cAAA,EAAe;AAAA,UACvB;AAAA,QACF;AAAA;AACF,KACF;AAAA,EACF,GAAG,CAAC,OAAA,EAAS,IAAA,EAAM,OAAA,EAAS,YAAY,CAAC,CAAA;AAC3C;AAGO,SAAS,cAAA,CAAe,KAAA,EAAoB,OAAA,GAAU,CAAA,EAAS;AACpE,EAAA,MAAM,SAAA,GAAY,eAAe,KAAK,CAAA;AAEtC,EAAA,IAAI,SAAA,EAAW;AACb,IAAA,SAAA,CAAU,KAAA,EAAM;AAChB,IAAA;AAAA,EACF;AAEA,EAAA,MAAM,IAAA,GAAO,MAAM,aAAA,CAAc,WAAA;AACjC,EAAA,IAAI,OAAA,GAAU,KAAK,IAAA,EAAM;AACvB,IAAA,IAAA,CAAK,sBAAsB,MAAM,cAAA,CAAe,KAAA,EAAO,OAAA,GAAU,CAAC,CAAC,CAAA;AAAA,EACrE;AACF;;;;"}
|
|
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":[],"mappings":"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"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { useMemo, useState, useCallback, useContext } from 'react';
|
|
2
|
+
import { createContext } from '../utils/createContext.js';
|
|
3
|
+
import 'clsx';
|
|
4
|
+
import 'react/jsx-runtime';
|
|
5
|
+
import '../utils/useFloatingUI/useFloatingUI.js';
|
|
6
|
+
import '../utils/useId.js';
|
|
7
|
+
import '../salt-provider/SaltProvider.js';
|
|
8
|
+
import '../viewport/ViewportProvider.js';
|
|
9
|
+
|
|
10
|
+
const MenuAlignmentContext = createContext(
|
|
11
|
+
"MenuAlignmentContext",
|
|
12
|
+
{
|
|
13
|
+
reserveIconSpace: false,
|
|
14
|
+
reserveSelectionIconSpace: false,
|
|
15
|
+
registerIcon: () => () => void 0,
|
|
16
|
+
registerSelectionIcon: () => () => void 0
|
|
17
|
+
}
|
|
18
|
+
);
|
|
19
|
+
function useSlotRegistry() {
|
|
20
|
+
const [count, setCount] = useState(0);
|
|
21
|
+
const register = useCallback(() => {
|
|
22
|
+
setCount((current) => current + 1);
|
|
23
|
+
return () => setCount((current) => current - 1);
|
|
24
|
+
}, []);
|
|
25
|
+
return [count > 0, register];
|
|
26
|
+
}
|
|
27
|
+
function useMenuAlignmentScope() {
|
|
28
|
+
const [reserveIconSpace, registerIcon] = useSlotRegistry();
|
|
29
|
+
const [reserveSelectionIconSpace, registerSelectionIcon] = useSlotRegistry();
|
|
30
|
+
return useMemo(
|
|
31
|
+
() => ({
|
|
32
|
+
reserveIconSpace,
|
|
33
|
+
reserveSelectionIconSpace,
|
|
34
|
+
registerIcon,
|
|
35
|
+
registerSelectionIcon
|
|
36
|
+
}),
|
|
37
|
+
[
|
|
38
|
+
reserveIconSpace,
|
|
39
|
+
reserveSelectionIconSpace,
|
|
40
|
+
registerIcon,
|
|
41
|
+
registerSelectionIcon
|
|
42
|
+
]
|
|
43
|
+
);
|
|
44
|
+
}
|
|
45
|
+
function useMenuAlignment() {
|
|
46
|
+
return useContext(MenuAlignmentContext);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export { MenuAlignmentContext, useMenuAlignment, useMenuAlignmentScope, useSlotRegistry };
|
|
50
|
+
//# 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":[],"mappings":";;;;;;;;;AAcO,MAAM,oBAAA,GAAuB,aAAA;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,GAAI,SAAS,CAAC,CAAA;AACpC,EAAA,MAAM,QAAA,GAAW,YAAY,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,OAAO,OAAA;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,OAAO,WAAW,oBAAoB,CAAA;AACxC;;;;"}
|
package/dist-es/menu/MenuBase.js
CHANGED
|
@@ -9,6 +9,7 @@ import '../utils/useId.js';
|
|
|
9
9
|
import '../salt-provider/SaltProvider.js';
|
|
10
10
|
import '../viewport/ViewportProvider.js';
|
|
11
11
|
import { MenuContext } from './MenuContext.js';
|
|
12
|
+
import { MenuGroupContext, defaultMenuGroupContextValue } from './MenuGroupContext.js';
|
|
12
13
|
|
|
13
14
|
function MenuBase(props) {
|
|
14
15
|
const {
|
|
@@ -40,10 +41,14 @@ function MenuBase(props) {
|
|
|
40
41
|
const [focusInside, setFocusInside] = useState(false);
|
|
41
42
|
const [triggerDisabled, setTriggerDisabled] = useState(false);
|
|
42
43
|
const isNested = parentId != null;
|
|
44
|
+
const handleOpenChange = (newOpen) => {
|
|
45
|
+
if (newOpen && triggerDisabled) return;
|
|
46
|
+
setOpen(newOpen);
|
|
47
|
+
};
|
|
43
48
|
const { x, y, strategy, elements, refs, context } = useFloatingUI({
|
|
44
49
|
nodeId,
|
|
45
50
|
open: openState,
|
|
46
|
-
onOpenChange:
|
|
51
|
+
onOpenChange: handleOpenChange,
|
|
47
52
|
strategy: !getVirtualElement ? "absolute" : "fixed",
|
|
48
53
|
placement: placement ?? (isNested || getVirtualElement ? "right-start" : "bottom-start"),
|
|
49
54
|
middleware: [
|
|
@@ -84,7 +89,8 @@ function MenuBase(props) {
|
|
|
84
89
|
listRef: elementsRef,
|
|
85
90
|
activeIndex,
|
|
86
91
|
nested: isNested,
|
|
87
|
-
onNavigate: setActiveIndex
|
|
92
|
+
onNavigate: setActiveIndex,
|
|
93
|
+
disabledIndices: (index) => elementsRef.current[index] == null
|
|
88
94
|
})
|
|
89
95
|
]
|
|
90
96
|
);
|
|
@@ -127,7 +133,7 @@ function MenuBase(props) {
|
|
|
127
133
|
triggerDisabled,
|
|
128
134
|
setTriggerDisabled
|
|
129
135
|
},
|
|
130
|
-
children
|
|
136
|
+
children: /* @__PURE__ */ jsx(MenuGroupContext.Provider, { value: defaultMenuGroupContextValue, children })
|
|
131
137
|
}
|
|
132
138
|
) });
|
|
133
139
|
}
|
|
@@ -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:
|
|
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":["elements"],"mappings":"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"}
|
|
@@ -1,19 +1,30 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
2
2
|
import { useComponentCssInjection } from '@salt-ds/styles';
|
|
3
3
|
import { useWindow } from '@salt-ds/window';
|
|
4
4
|
import { clsx } from 'clsx';
|
|
5
|
-
import { forwardRef } from 'react';
|
|
5
|
+
import { forwardRef, useMemo, useCallback } from 'react';
|
|
6
6
|
import { makePrefixer } from '../utils/makePrefixer.js';
|
|
7
7
|
import '../utils/useFloatingUI/useFloatingUI.js';
|
|
8
8
|
import { useId } from '../utils/useId.js';
|
|
9
9
|
import '../salt-provider/SaltProvider.js';
|
|
10
10
|
import '../viewport/ViewportProvider.js';
|
|
11
|
+
import { useMenuAlignmentScope, MenuAlignmentContext } from './MenuAlignmentContext.js';
|
|
11
12
|
import css_248z from './MenuGroup.css.js';
|
|
13
|
+
import { MenuGroupContext } from './MenuGroupContext.js';
|
|
12
14
|
|
|
13
15
|
const withBaseName = makePrefixer("saltMenuGroup");
|
|
16
|
+
const noSelection = [];
|
|
14
17
|
const MenuGroup = forwardRef(
|
|
15
18
|
function MenuGroup2(props, ref) {
|
|
16
|
-
const {
|
|
19
|
+
const {
|
|
20
|
+
className,
|
|
21
|
+
children,
|
|
22
|
+
label,
|
|
23
|
+
onSelectionChange,
|
|
24
|
+
selected: selectedProp = noSelection,
|
|
25
|
+
selectionVariant,
|
|
26
|
+
...rest
|
|
27
|
+
} = props;
|
|
17
28
|
const targetWindow = useWindow();
|
|
18
29
|
useComponentCssInjection({
|
|
19
30
|
testId: "salt-menu-group",
|
|
@@ -21,7 +32,35 @@ const MenuGroup = forwardRef(
|
|
|
21
32
|
window: targetWindow
|
|
22
33
|
});
|
|
23
34
|
const labelId = useId();
|
|
24
|
-
|
|
35
|
+
const selected = useMemo(
|
|
36
|
+
() => selectionVariant === "single" ? selectedProp.slice(0, 1) : selectedProp,
|
|
37
|
+
[selectedProp, selectionVariant]
|
|
38
|
+
);
|
|
39
|
+
const isSelected = useCallback(
|
|
40
|
+
(value) => selected.includes(value),
|
|
41
|
+
[selected]
|
|
42
|
+
);
|
|
43
|
+
const select = useCallback(
|
|
44
|
+
(event, value) => {
|
|
45
|
+
if (selectionVariant === "single") {
|
|
46
|
+
if (!selected.includes(value)) {
|
|
47
|
+
onSelectionChange == null ? void 0 : onSelectionChange(event, [value]);
|
|
48
|
+
}
|
|
49
|
+
} else if (selectionVariant === "multiple") {
|
|
50
|
+
onSelectionChange == null ? void 0 : onSelectionChange(
|
|
51
|
+
event,
|
|
52
|
+
selected.includes(value) ? selected.filter((item) => item !== value) : selected.concat(value)
|
|
53
|
+
);
|
|
54
|
+
}
|
|
55
|
+
},
|
|
56
|
+
[onSelectionChange, selected, selectionVariant]
|
|
57
|
+
);
|
|
58
|
+
const contextValue = useMemo(
|
|
59
|
+
() => ({ isSelected, select, selectionVariant }),
|
|
60
|
+
[isSelected, select, selectionVariant]
|
|
61
|
+
);
|
|
62
|
+
const alignment = useMenuAlignmentScope();
|
|
63
|
+
return /* @__PURE__ */ jsx(MenuGroupContext.Provider, { value: contextValue, children: /* @__PURE__ */ jsx(MenuAlignmentContext.Provider, { value: alignment, children: /* @__PURE__ */ jsxs(
|
|
25
64
|
"div",
|
|
26
65
|
{
|
|
27
66
|
"aria-labelledby": label ? labelId : void 0,
|
|
@@ -34,7 +73,7 @@ const MenuGroup = forwardRef(
|
|
|
34
73
|
children
|
|
35
74
|
]
|
|
36
75
|
}
|
|
37
|
-
);
|
|
76
|
+
) }) });
|
|
38
77
|
}
|
|
39
78
|
);
|
|
40
79
|
|