@mortenbrudvik/waveui 0.10.0 → 0.12.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/README.md +454 -74
- package/dist/components/button/Link.cjs +1 -1
- package/dist/components/button/Link.cjs.map +1 -1
- package/dist/components/button/Link.mjs +4 -4
- package/dist/components/button/Toolbar.cjs +1 -1
- package/dist/components/button/Toolbar.cjs.map +1 -1
- package/dist/components/button/Toolbar.mjs +25 -30
- package/dist/components/button/Toolbar.mjs.map +1 -1
- package/dist/components/button/Toolbar.navigation.cjs +2 -0
- package/dist/components/button/Toolbar.navigation.cjs.map +1 -0
- package/dist/components/button/Toolbar.navigation.mjs +17 -0
- package/dist/components/button/Toolbar.navigation.mjs.map +1 -0
- package/dist/components/data-display/Avatar.cjs +1 -1
- package/dist/components/data-display/Avatar.cjs.map +1 -1
- package/dist/components/data-display/Avatar.context.cjs +2 -0
- package/dist/components/data-display/Avatar.context.cjs.map +1 -0
- package/dist/components/data-display/Avatar.context.mjs +9 -0
- package/dist/components/data-display/Avatar.context.mjs.map +1 -0
- package/dist/components/data-display/Avatar.mjs +66 -61
- package/dist/components/data-display/Avatar.mjs.map +1 -1
- package/dist/components/data-display/AvatarGroup.cjs +1 -1
- package/dist/components/data-display/AvatarGroup.cjs.map +1 -1
- package/dist/components/data-display/AvatarGroup.mjs +10 -10
- package/dist/components/data-display/InfoButton.cjs +1 -1
- package/dist/components/data-display/InfoButton.cjs.map +1 -1
- package/dist/components/data-display/InfoButton.mjs +12 -12
- package/dist/components/data-display/InteractionTag.cjs +2 -0
- package/dist/components/data-display/InteractionTag.cjs.map +1 -0
- package/dist/components/data-display/InteractionTag.mjs +234 -0
- package/dist/components/data-display/InteractionTag.mjs.map +1 -0
- package/dist/components/data-display/Tag.cjs +1 -1
- package/dist/components/data-display/Tag.cjs.map +1 -1
- package/dist/components/data-display/Tag.mjs +222 -90
- package/dist/components/data-display/Tag.mjs.map +1 -1
- package/dist/components/data-display/TagGroup.cjs +2 -0
- package/dist/components/data-display/TagGroup.cjs.map +1 -0
- package/dist/components/data-display/TagGroup.context.cjs +2 -0
- package/dist/components/data-display/TagGroup.context.cjs.map +1 -0
- package/dist/components/data-display/TagGroup.context.mjs +113 -0
- package/dist/components/data-display/TagGroup.context.mjs.map +1 -0
- package/dist/components/data-display/TagGroup.mjs +149 -0
- package/dist/components/data-display/TagGroup.mjs.map +1 -0
- package/dist/components/data-display/tagStyles.cjs +2 -0
- package/dist/components/data-display/tagStyles.cjs.map +1 -0
- package/dist/components/data-display/tagStyles.mjs +108 -0
- package/dist/components/data-display/tagStyles.mjs.map +1 -0
- package/dist/components/feedback/Toaster.cjs +1 -1
- package/dist/components/feedback/Toaster.cjs.map +1 -1
- package/dist/components/feedback/Toaster.mjs +287 -255
- package/dist/components/feedback/Toaster.mjs.map +1 -1
- package/dist/components/input/Combobox.cjs +1 -1
- package/dist/components/input/Combobox.cjs.map +1 -1
- package/dist/components/input/Combobox.expand.cjs +1 -1
- package/dist/components/input/Combobox.expand.cjs.map +1 -1
- package/dist/components/input/Combobox.expand.mjs +7 -7
- package/dist/components/input/Combobox.expand.mjs.map +1 -1
- package/dist/components/input/Combobox.mjs +176 -175
- package/dist/components/input/Combobox.mjs.map +1 -1
- package/dist/components/input/DatePicker.cjs +1 -1
- package/dist/components/input/DatePicker.cjs.map +1 -1
- package/dist/components/input/DatePicker.mjs +188 -187
- package/dist/components/input/DatePicker.mjs.map +1 -1
- package/dist/components/input/Dropdown.cjs +1 -1
- package/dist/components/input/Dropdown.cjs.map +1 -1
- package/dist/components/input/Dropdown.mjs +41 -40
- package/dist/components/input/Dropdown.mjs.map +1 -1
- package/dist/components/input/Option.cjs +1 -1
- package/dist/components/input/Option.cjs.map +1 -1
- package/dist/components/input/Option.mjs +101 -94
- package/dist/components/input/Option.mjs.map +1 -1
- package/dist/components/input/SwatchPicker.cjs.map +1 -1
- package/dist/components/input/SwatchPicker.context.cjs.map +1 -1
- package/dist/components/input/SwatchPicker.context.mjs.map +1 -1
- package/dist/components/input/SwatchPicker.mjs.map +1 -1
- package/dist/components/input/TagPicker.cjs +1 -1
- package/dist/components/input/TagPicker.cjs.map +1 -1
- package/dist/components/input/TagPicker.context.cjs +2 -0
- package/dist/components/input/TagPicker.context.cjs.map +1 -0
- package/dist/components/input/TagPicker.context.mjs +20 -0
- package/dist/components/input/TagPicker.context.mjs.map +1 -0
- package/dist/components/input/TagPicker.create.cjs +2 -0
- package/dist/components/input/TagPicker.create.cjs.map +1 -0
- package/dist/components/input/TagPicker.create.mjs +24 -0
- package/dist/components/input/TagPicker.create.mjs.map +1 -0
- package/dist/components/input/TagPicker.mjs +13 -279
- package/dist/components/input/TagPicker.mjs.map +1 -1
- package/dist/components/input/TagPicker.option.cjs +2 -0
- package/dist/components/input/TagPicker.option.cjs.map +1 -0
- package/dist/components/input/TagPicker.option.mjs +45 -0
- package/dist/components/input/TagPicker.option.mjs.map +1 -0
- package/dist/components/input/TagPicker.overflow.cjs +2 -0
- package/dist/components/input/TagPicker.overflow.cjs.map +1 -0
- package/dist/components/input/TagPicker.overflow.mjs +153 -0
- package/dist/components/input/TagPicker.overflow.mjs.map +1 -0
- package/dist/components/input/TagPicker.parts.cjs +2 -0
- package/dist/components/input/TagPicker.parts.cjs.map +1 -0
- package/dist/components/input/TagPicker.parts.mjs +425 -0
- package/dist/components/input/TagPicker.parts.mjs.map +1 -0
- package/dist/components/input/TagPicker.root.cjs +2 -0
- package/dist/components/input/TagPicker.root.cjs.map +1 -0
- package/dist/components/input/TagPicker.root.mjs +417 -0
- package/dist/components/input/TagPicker.root.mjs.map +1 -0
- package/dist/components/input/TimePicker.cjs +1 -1
- package/dist/components/input/TimePicker.cjs.map +1 -1
- package/dist/components/input/TimePicker.mjs +156 -154
- package/dist/components/input/TimePicker.mjs.map +1 -1
- package/dist/components/layout/Accordion.cjs.map +1 -1
- package/dist/components/layout/Accordion.mjs.map +1 -1
- package/dist/components/navigation/Hamburger.cjs +2 -0
- package/dist/components/navigation/Hamburger.cjs.map +1 -0
- package/dist/components/navigation/Hamburger.mjs +54 -0
- package/dist/components/navigation/Hamburger.mjs.map +1 -0
- package/dist/components/navigation/Menu.popover.cjs +1 -1
- package/dist/components/navigation/Menu.popover.cjs.map +1 -1
- package/dist/components/navigation/Menu.popover.mjs +137 -127
- package/dist/components/navigation/Menu.popover.mjs.map +1 -1
- package/dist/components/navigation/Menu.root.cjs +1 -1
- package/dist/components/navigation/Menu.root.cjs.map +1 -1
- package/dist/components/navigation/Menu.root.mjs +4 -4
- package/dist/components/navigation/Nav.cjs +1 -1
- package/dist/components/navigation/Nav.cjs.map +1 -1
- package/dist/components/navigation/Nav.context.cjs +2 -0
- package/dist/components/navigation/Nav.context.cjs.map +1 -0
- package/dist/components/navigation/Nav.context.mjs +137 -0
- package/dist/components/navigation/Nav.context.mjs.map +1 -0
- package/dist/components/navigation/Nav.mjs +151 -258
- package/dist/components/navigation/Nav.mjs.map +1 -1
- package/dist/components/navigation/Nav.parts.cjs +2 -0
- package/dist/components/navigation/Nav.parts.cjs.map +1 -0
- package/dist/components/navigation/Nav.parts.mjs +77 -0
- package/dist/components/navigation/Nav.parts.mjs.map +1 -0
- package/dist/components/navigation/Nav.root.cjs +2 -0
- package/dist/components/navigation/Nav.root.cjs.map +1 -0
- package/dist/components/navigation/Nav.root.mjs +78 -0
- package/dist/components/navigation/Nav.root.mjs.map +1 -0
- package/dist/components/navigation/NavDrawer.cjs +2 -0
- package/dist/components/navigation/NavDrawer.cjs.map +1 -0
- package/dist/components/navigation/NavDrawer.context.cjs +2 -0
- package/dist/components/navigation/NavDrawer.context.cjs.map +1 -0
- package/dist/components/navigation/NavDrawer.context.mjs +11 -0
- package/dist/components/navigation/NavDrawer.context.mjs.map +1 -0
- package/dist/components/navigation/NavDrawer.mjs +179 -0
- package/dist/components/navigation/NavDrawer.mjs.map +1 -0
- package/dist/components/overlays/Dialog.cjs +1 -1
- package/dist/components/overlays/Dialog.cjs.map +1 -1
- package/dist/components/overlays/Dialog.mjs +188 -123
- package/dist/components/overlays/Dialog.mjs.map +1 -1
- package/dist/components/overlays/Dialog.shared.cjs +1 -1
- package/dist/components/overlays/Dialog.shared.cjs.map +1 -1
- package/dist/components/overlays/Dialog.shared.mjs +157 -81
- package/dist/components/overlays/Dialog.shared.mjs.map +1 -1
- package/dist/components/overlays/Dialog.slots.cjs +2 -0
- package/dist/components/overlays/Dialog.slots.cjs.map +1 -0
- package/dist/components/overlays/Dialog.slots.mjs +129 -0
- package/dist/components/overlays/Dialog.slots.mjs.map +1 -0
- package/dist/components/overlays/Drawer.cjs +1 -1
- package/dist/components/overlays/Drawer.cjs.map +1 -1
- package/dist/components/overlays/Drawer.context.cjs +2 -0
- package/dist/components/overlays/Drawer.context.cjs.map +1 -0
- package/dist/components/overlays/Drawer.context.mjs +29 -0
- package/dist/components/overlays/Drawer.context.mjs.map +1 -0
- package/dist/components/overlays/Drawer.mjs +12 -187
- package/dist/components/overlays/Drawer.mjs.map +1 -1
- package/dist/components/overlays/Drawer.panel.cjs +2 -0
- package/dist/components/overlays/Drawer.panel.cjs.map +1 -0
- package/dist/components/overlays/Drawer.panel.mjs +159 -0
- package/dist/components/overlays/Drawer.panel.mjs.map +1 -0
- package/dist/components/overlays/Drawer.parts.cjs +2 -0
- package/dist/components/overlays/Drawer.parts.cjs.map +1 -0
- package/dist/components/overlays/Drawer.parts.mjs +152 -0
- package/dist/components/overlays/Drawer.parts.mjs.map +1 -0
- package/dist/components/overlays/Drawer.root.cjs +2 -0
- package/dist/components/overlays/Drawer.root.cjs.map +1 -0
- package/dist/components/overlays/Drawer.root.mjs +207 -0
- package/dist/components/overlays/Drawer.root.mjs.map +1 -0
- package/dist/components/overlays/Drawer.scroll.cjs +2 -0
- package/dist/components/overlays/Drawer.scroll.cjs.map +1 -0
- package/dist/components/overlays/Drawer.scroll.mjs +42 -0
- package/dist/components/overlays/Drawer.scroll.mjs.map +1 -0
- package/dist/components/overlays/Popover.cjs +1 -1
- package/dist/components/overlays/Popover.cjs.map +1 -1
- package/dist/components/overlays/Popover.mjs +173 -162
- package/dist/components/overlays/Popover.mjs.map +1 -1
- package/dist/components/overlays/TeachingPopover.cjs +1 -1
- package/dist/components/overlays/TeachingPopover.cjs.map +1 -1
- package/dist/components/overlays/TeachingPopover.mjs +96 -91
- package/dist/components/overlays/TeachingPopover.mjs.map +1 -1
- package/dist/components/overlays/Tooltip.cjs +1 -1
- package/dist/components/overlays/Tooltip.cjs.map +1 -1
- package/dist/components/overlays/Tooltip.mjs +47 -47
- package/dist/components/overlays/Tooltip.mjs.map +1 -1
- package/dist/components/portal/Portal.cjs +1 -1
- package/dist/components/portal/Portal.cjs.map +1 -1
- package/dist/components/portal/Portal.mjs +5 -5
- package/dist/components/table/DataGrid.cjs +1 -1
- package/dist/components/table/DataGrid.cjs.map +1 -1
- package/dist/components/table/DataGrid.mjs +1 -1
- package/dist/hooks/useDismiss.cjs.map +1 -1
- package/dist/hooks/useDismiss.mjs.map +1 -1
- package/dist/hooks/useFocusTrap.cjs +1 -1
- package/dist/hooks/useFocusTrap.cjs.map +1 -1
- package/dist/hooks/useFocusTrap.mjs +115 -98
- package/dist/hooks/useFocusTrap.mjs.map +1 -1
- package/dist/hooks/useFocusVisible.cjs +2 -0
- package/dist/hooks/useFocusVisible.cjs.map +1 -0
- package/dist/hooks/useFocusVisible.mjs +49 -0
- package/dist/hooks/useFocusVisible.mjs.map +1 -0
- package/dist/hooks/useFocusableGroup.cjs +2 -0
- package/dist/hooks/useFocusableGroup.cjs.map +1 -0
- package/dist/hooks/useFocusableGroup.mjs +70 -0
- package/dist/hooks/useFocusableGroup.mjs.map +1 -0
- package/dist/hooks/useModalLayer.cjs +1 -1
- package/dist/hooks/useModalLayer.cjs.map +1 -1
- package/dist/hooks/useModalLayer.mjs +34 -21
- package/dist/hooks/useModalLayer.mjs.map +1 -1
- package/dist/hooks/useModalOpen.cjs +2 -0
- package/dist/hooks/useModalOpen.cjs.map +1 -0
- package/dist/hooks/useModalOpen.mjs +14 -0
- package/dist/hooks/useModalOpen.mjs.map +1 -0
- package/dist/hooks/usePopupPosition.cjs +1 -1
- package/dist/hooks/usePopupPosition.cjs.map +1 -1
- package/dist/hooks/usePopupPosition.mjs +82 -53
- package/dist/hooks/usePopupPosition.mjs.map +1 -1
- package/dist/hooks/useResolvedTarget.cjs +2 -0
- package/dist/hooks/useResolvedTarget.cjs.map +1 -0
- package/dist/hooks/useResolvedTarget.mjs +37 -0
- package/dist/hooks/useResolvedTarget.mjs.map +1 -0
- package/dist/hooks/useRestoreFocus.cjs +1 -1
- package/dist/hooks/useRestoreFocus.cjs.map +1 -1
- package/dist/hooks/useRestoreFocus.mjs +91 -78
- package/dist/hooks/useRestoreFocus.mjs.map +1 -1
- package/dist/hooks/useRovingGrid.cjs +1 -1
- package/dist/hooks/useRovingGrid.cjs.map +1 -1
- package/dist/hooks/useRovingGrid.mjs +8 -57
- package/dist/hooks/useRovingGrid.mjs.map +1 -1
- package/dist/hooks/useRovingTabIndex.cjs +1 -1
- package/dist/hooks/useRovingTabIndex.cjs.map +1 -1
- package/dist/hooks/useRovingTabIndex.mjs +180 -121
- package/dist/hooks/useRovingTabIndex.mjs.map +1 -1
- package/dist/index.cjs +1 -1
- package/dist/index.d.cts +3070 -269
- package/dist/index.d.ts +3070 -269
- package/dist/index.mjs +127 -107
- package/dist/lib/classNames.cjs +1 -1
- package/dist/lib/classNames.cjs.map +1 -1
- package/dist/lib/classNames.mjs +137 -77
- package/dist/lib/classNames.mjs.map +1 -1
- package/dist/lib/icons.cjs +1 -1
- package/dist/lib/icons.cjs.map +1 -1
- package/dist/lib/icons.mjs +13 -6
- package/dist/lib/icons.mjs.map +1 -1
- package/dist/lib/layers.cjs +1 -1
- package/dist/lib/layers.cjs.map +1 -1
- package/dist/lib/layers.mjs +120 -111
- package/dist/lib/layers.mjs.map +1 -1
- package/dist/styles.css +1 -1
- package/package.json +1 -1
- package/src/styles/tokens.css +25 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"usePopupPosition.cjs","names":["autoUpdate","useDirection","offsetMiddleware","flipMiddleware","shiftMiddleware","sizeMiddleware","arrowMiddleware","useMemo","platform","useFloating","useRef","useEventCallback","useCallback","require_useEventCallback","require_useDirection","react","_floating_ui_react_dom","STATIC_SIDE","ARROW_OFFSET","resolveSide","side","dir","EMPTY_RECT","isElementAnchor","anchor","createVirtualProxy","latest","whileElementsMounted","reference","floating","update","sizeApply","style","elements","availableWidth","availableHeight","rects","usePopupPosition","options","physicalSide","requestedPlacement","align","padding","shift","shiftCrossAxis","middleware","offset","flip","matchReferenceWidth","fitViewport","arrowRef","directionalPlatform","open","virtualRef","proxyRef","updatePosition","setFloatingReference","floatingReference","refs","setReference","proxy","finalSide","finalAlign","placement","next","floatingStyles","arrowX","middlewareData","arrowY","arrowStyles","styles","floatingProps"],"sources":["../../src/hooks/usePopupPosition.ts"],"sourcesContent":["import { useCallback, useMemo, useRef } from 'react';\nimport type * as React from 'react';\nimport {\n arrow as arrowMiddleware,\n autoUpdate,\n flip as flipMiddleware,\n offset as offsetMiddleware,\n platform,\n shift as shiftMiddleware,\n size as sizeMiddleware,\n useFloating,\n type Middleware,\n type Placement,\n type Platform,\n type ReferenceType,\n type SizeOptions,\n} from '@floating-ui/react-dom';\nimport type { PopupAlign, PopupRect, PopupSide, VirtualElement } from '../lib/types';\nimport type { Direction } from '../lib/direction';\nimport { useDirection } from './useDirection';\nimport { useEventCallback } from './useEventCallback';\n\n/** Options of {@link usePopupPosition}. */\nexport interface UsePopupPositionOptions {\n /** Whether the popup is open; positions are kept up to date only while `true`. */\n open: boolean;\n /** Side of the anchor. `start`/`end` follow the writing direction. @default 'bottom' */\n side?: PopupSide;\n /** Alignment along that side. @default 'start' */\n align?: PopupAlign;\n /** Distance from the anchor in px. @default 4 (tooltips use 8) */\n offset?: number;\n /** Flip to the opposite side when there is not enough room. @default true */\n flip?: boolean;\n /**\n * Shift along the side to stay inside the viewport. Its padding is also the viewport padding of\n * `flip` and of `size` (`fitViewport`, `matchReferenceWidth`): `true` means 8px, and `false`\n * lets the popup flip only once it touches the viewport edge and grow right up to it. With\n * `crossAxis: true` it also shifts across the side, over the anchor, when neither side has room\n * after `flip` (submenus), and `fitViewport` then offers the whole viewport in that direction.\n * @default { padding: 8 }\n */\n shift?: boolean | { padding: number; crossAxis?: boolean };\n /** Make the surface as wide as the anchor (listboxes). @default false */\n matchReferenceWidth?: boolean;\n /** Limit the surface to the available space (`max-width`/`max-height`). @default false */\n fitViewport?: boolean;\n /** An arrow (beak) element inside the surface, positioned through `arrowStyles`. */\n arrowRef?: React.RefObject<HTMLElement | null>;\n /** CSS positioning strategy. @default 'fixed' */\n strategy?: 'absolute' | 'fixed';\n}\n\n/** Returned by {@link usePopupPosition}. */\nexport interface UsePopupPositionResult {\n /**\n * Sets the anchor: a ref callback for the anchor (trigger) element, or a call from a layout\n * effect or an event. The anchor is an element or a `VirtualElement` (a rectangle such as the\n * pointer position; a new object on every render is fine); give it a `contextElement` so\n * scrolling its containers updates the position.\n */\n setReference(el: HTMLElement | VirtualElement | null): void;\n /** Ref callback for the popup surface. */\n setFloating(el: HTMLElement | null): void;\n /** Position styles for the surface (also in `floatingProps.style`). */\n floatingStyles: React.CSSProperties;\n /** Position styles for the arrow element. */\n arrowStyles: React.CSSProperties;\n /** Final placement after flipping, e.g. `'top-start'`. */\n placement: string;\n /** Final physical side after flipping. */\n side: 'top' | 'bottom' | 'left' | 'right';\n /** Whether a position has been computed since the popup opened. */\n isPositioned: boolean;\n /** Spread onto the surface: `data-side`, `data-align` and the position style. */\n floatingProps: { 'data-side': string; 'data-align': string; style: React.CSSProperties };\n}\n\ntype PhysicalSide = 'top' | 'bottom' | 'left' | 'right';\n\nconst STATIC_SIDE: Record<PhysicalSide, PhysicalSide> = {\n top: 'bottom',\n bottom: 'top',\n left: 'right',\n right: 'left',\n};\n\n/** Half the arrow size, so the arrow sticks out of the surface towards the anchor. */\nconst ARROW_OFFSET = 'calc(var(--wave-popup-arrow-size, 8px) / -2)';\n\nfunction resolveSide(side: PopupSide, dir: Direction): PhysicalSide {\n if (side === 'start') return dir === 'rtl' ? 'right' : 'left';\n if (side === 'end') return dir === 'rtl' ? 'left' : 'right';\n return side;\n}\n\n/** The rectangle of a virtual anchor that is not set (never reached while one is the reference). */\nconst EMPTY_RECT: PopupRect = {\n x: 0,\n y: 0,\n width: 0,\n height: 0,\n top: 0,\n right: 0,\n bottom: 0,\n left: 0,\n};\n\n/** Whether an anchor is a DOM element (duck typed, so an element of another realm counts). */\nfunction isElementAnchor(anchor: HTMLElement | VirtualElement): anchor is HTMLElement {\n return typeof (anchor as Partial<Node>).nodeType === 'number';\n}\n\n/**\n * The stable stand-in floating-ui gets for virtual anchors: it reads the latest `VirtualElement`\n * from `latest`, so a new virtual object sets no floating-ui state. One proxy per\n * `contextElement`, so `autoUpdate` observes the scroll containers of the current one.\n */\ninterface VirtualProxy extends VirtualElement {\n contextElement: Element | undefined;\n}\n\nfunction createVirtualProxy(\n latest: React.RefObject<VirtualElement | null>,\n contextElement: Element | undefined,\n): VirtualProxy {\n return {\n getBoundingClientRect: () => latest.current?.getBoundingClientRect() ?? EMPTY_RECT,\n contextElement,\n };\n}\n\n/** Keeps the position updated while mounted; observers are used only where they exist. */\nfunction whileElementsMounted(\n reference: ReferenceType,\n floating: HTMLElement,\n update: () => void,\n): () => void {\n return autoUpdate(reference, floating, update, {\n elementResize: typeof ResizeObserver !== 'undefined',\n layoutShift: typeof IntersectionObserver !== 'undefined',\n });\n}\n\n/**\n * Writes the available space and the anchor width as CSS variables on the surface:\n * `--wave-popup-available-width`, `--wave-popup-available-height`, `--wave-popup-reference-width`.\n * It captures no options (floating-ui compares middleware functions by source text).\n */\nconst sizeApply: NonNullable<SizeOptions['apply']> = ({\n availableWidth,\n availableHeight,\n rects,\n elements,\n}) => {\n const style = elements.floating.style;\n style.setProperty('--wave-popup-available-width', `${Math.max(0, Math.floor(availableWidth))}px`);\n style.setProperty(\n '--wave-popup-available-height',\n `${Math.max(0, Math.floor(availableHeight))}px`,\n );\n style.setProperty('--wave-popup-reference-width', `${Math.round(rects.reference.width)}px`);\n};\n\n/**\n * Positions a popup surface next to its anchor with `@floating-ui/react-dom` (Tooltip, Popover,\n * Menu, listboxes, the DatePicker calendar, TeachingPopover): `offset`, `flip`, `shift`, optional\n * `size` (reference width / available space as CSS variables) and `arrow`. `flip`, `shift` and\n * `size` keep the same viewport padding, taken from the `shift` option (8px by default). Logical\n * `start`/`end` sides follow `useDirection()` (the WaveProvider `dir`, else the document\n * direction), and so does start/end alignment.\n *\n * Positions update only while `open` (`autoUpdate` on scroll/resize; element resizes and layout\n * shifts only where `ResizeObserver`/`IntersectionObserver` exist). Spread `floatingProps` onto the\n * surface: `data-side`/`data-align` expose the final placement for styling (C-CLASS).\n *\n * The anchor is an element or a `VirtualElement` (a rectangle such as the pointer position; a new\n * object on every render is fine); give it a `contextElement` so scrolling its containers updates\n * the position. A virtual anchor reaches floating-ui through one stable proxy that reads the latest\n * object: a new object only recomputes the position (which renders only when the position\n * changes), and a new proxy is made only when the `contextElement` changes.\n *\n * Destructure the result: `eslint-plugin-react-hooks` (`react-hooks/refs`) treats an object\n * whose member is passed to a `ref` prop as a ref, and then rejects reading its other members\n * during render.\n *\n * @example\n * const { setReference, setFloating, floatingProps } = usePopupPosition({ open, side: 'bottom' });\n * <button ref={setReference} />\n * {open && <Portal><div ref={setFloating} {...floatingProps} /></Portal>}\n */\nexport function usePopupPosition(options: UsePopupPositionOptions): UsePopupPositionResult {\n const {\n open,\n side = 'bottom',\n align = 'start',\n offset = 4,\n flip = true,\n shift = { padding: 8 },\n matchReferenceWidth = false,\n fitViewport = false,\n arrowRef,\n strategy = 'fixed',\n } = options;\n const dir = useDirection();\n const physicalSide = resolveSide(side, dir);\n const requestedPlacement = (\n align === 'center' ? physicalSide : `${physicalSide}-${align}`\n ) as Placement;\n const padding = shift === false ? 0 : shift === true ? 8 : shift.padding;\n const shiftCrossAxis = typeof shift === 'object' && shift.crossAxis === true;\n\n const middleware: Middleware[] = [offsetMiddleware(offset)];\n if (flip) middleware.push(flipMiddleware({ padding }));\n if (shift !== false) {\n middleware.push(shiftMiddleware({ padding, crossAxis: shiftCrossAxis }));\n }\n if (matchReferenceWidth || fitViewport) {\n middleware.push(sizeMiddleware({ padding, apply: sizeApply }));\n }\n if (arrowRef) middleware.push(arrowMiddleware({ element: arrowRef }));\n\n // Alignment follows the hook's direction (not only the surface's computed CSS direction).\n const directionalPlatform = useMemo<Platform>(\n () => ({ ...platform, isRTL: () => dir === 'rtl' }),\n [dir],\n );\n\n const { refs, floatingStyles, placement, middlewareData, isPositioned, update } = useFloating({\n open,\n placement: requestedPlacement,\n strategy,\n middleware,\n platform: directionalPlatform,\n whileElementsMounted: open ? whileElementsMounted : undefined,\n });\n\n // Virtual anchors: the latest object (written in setReference, never during render) and the\n // proxy floating-ui holds for it.\n const virtualRef = useRef<VirtualElement | null>(null);\n const proxyRef = useRef<VirtualProxy | null>(null);\n const updatePosition = useEventCallback(update);\n const { setReference: setFloatingReference, reference: floatingReference } = refs;\n const setReference = useCallback(\n (anchor: HTMLElement | VirtualElement | null) => {\n if (anchor === null || isElementAnchor(anchor)) {\n virtualRef.current = null;\n setFloatingReference(anchor);\n return;\n }\n virtualRef.current = anchor;\n let proxy = proxyRef.current;\n if (!proxy || proxy.contextElement !== anchor.contextElement) {\n proxy = createVirtualProxy(virtualRef, anchor.contextElement);\n proxyRef.current = proxy;\n }\n if (floatingReference.current === proxy) updatePosition();\n else setFloatingReference(proxy);\n },\n [setFloatingReference, floatingReference, updatePosition],\n );\n\n const [finalSide, finalAlign = 'center'] = placement.split('-') as [PhysicalSide, string?];\n\n const style = useMemo<React.CSSProperties>(() => {\n const next: React.CSSProperties = { ...floatingStyles };\n if (matchReferenceWidth) next.width = 'var(--wave-popup-reference-width)';\n if (fitViewport) {\n next.maxWidth = 'var(--wave-popup-available-width)';\n next.maxHeight = 'var(--wave-popup-available-height)';\n }\n return next;\n }, [floatingStyles, matchReferenceWidth, fitViewport]);\n\n const arrowX = middlewareData.arrow?.x;\n const arrowY = middlewareData.arrow?.y;\n const arrowStyles = useMemo<React.CSSProperties>(() => {\n const styles: Record<string, string> = {\n position: 'absolute',\n left: arrowX != null ? `${arrowX}px` : '',\n top: arrowY != null ? `${arrowY}px` : '',\n };\n styles[STATIC_SIDE[finalSide]] = ARROW_OFFSET;\n return styles as React.CSSProperties;\n }, [arrowX, arrowY, finalSide]);\n\n const floatingProps = useMemo(\n () => ({ 'data-side': finalSide, 'data-align': finalAlign, style }),\n [finalSide, finalAlign, style],\n );\n\n return {\n setReference,\n setFloating: refs.setFloating,\n floatingStyles: style,\n arrowStyles,\n placement,\n side: finalSide,\n isPositioned,\n floatingProps,\n };\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"usePopupPosition.cjs","names":["autoUpdate","useDirection","offsetMiddleware","flipMiddleware","shiftMiddleware","sizeMiddleware","hideMiddleware","arrowMiddleware","useMemo","platform","useFloating","useRef","useEventCallback","useCallback","require_useEventCallback","require_useDirection","react","_floating_ui_react_dom","resolvePositioning","positioning","defaults","STATIC_SIDE","ARROW_OFFSET","resolveSide","side","dir","EMPTY_RECT","isElementAnchor","anchor","createVirtualProxy","latest","whileElementsMounted","reference","floating","update","sizeApply","style","elements","availableWidth","availableHeight","rects","usePopupPosition","options","physicalSide","toPlacement","placementAlign","placementSide","requestedPlacement","align","padding","shift","shiftCrossAxis","middleware","offset","flip","fallbackPlacements","placement","matchReferenceWidth","fitViewport","hideWhenDetached","arrowRef","directionalPlatform","open","virtualRef","proxyRef","updatePosition","updateWhileOpen","setFloatingReference","floatingReference","refs","setReference","proxy","finalSide","finalAlign","reportPositioned","onPositioned","info","isPositioned","referenceHidden","middlewareData","next","floatingStyles","arrowX","arrowY","arrowStyles","styles","floatingProps"],"sources":["../../src/hooks/usePopupPosition.ts"],"sourcesContent":["import { useCallback, useEffect, useMemo, useRef } from 'react';\nimport type * as React from 'react';\nimport {\n arrow as arrowMiddleware,\n autoUpdate,\n flip as flipMiddleware,\n hide as hideMiddleware,\n offset as offsetMiddleware,\n platform,\n shift as shiftMiddleware,\n size as sizeMiddleware,\n useFloating,\n type Middleware,\n type Placement,\n type Platform,\n type ReferenceType,\n type SizeOptions,\n} from '@floating-ui/react-dom';\nimport type {\n PopupAlign,\n PopupPlacement,\n PopupPositioning,\n PopupRect,\n PopupSide,\n VirtualElement,\n} from '../lib/types';\nimport type { Direction } from '../lib/direction';\nimport { useDirection } from './useDirection';\nimport { useEventCallback } from './useEventCallback';\n\n/** Options of {@link usePopupPosition}. */\nexport interface UsePopupPositionOptions {\n /** Whether the popup is open; positions are kept up to date only while `true`. */\n open: boolean;\n /** Side of the anchor. `start`/`end` follow the writing direction. @default 'bottom' */\n side?: PopupSide;\n /** Alignment along that side. @default 'start' */\n align?: PopupAlign;\n /** Distance from the anchor in px. @default 4 (tooltips use 8) */\n offset?: number;\n /** Flip to the opposite side when there is not enough room. @default true */\n flip?: boolean;\n /**\n * Shift along the side to stay inside the viewport. Its padding is also the viewport padding of\n * `flip` and of `size` (`fitViewport`, `matchReferenceWidth`): `true` means 8px, and `false`\n * lets the popup flip only once it touches the viewport edge and grow right up to it. With\n * `crossAxis: true` it also shifts across the side, over the anchor, when neither side has room\n * after `flip` (submenus), and `fitViewport` then offers the whole viewport in that direction.\n * @default { padding: 8 }\n */\n shift?: boolean | { padding: number; crossAxis?: boolean };\n /** Make the surface as wide as the anchor (listboxes). @default false */\n matchReferenceWidth?: boolean;\n /** Limit the surface to the available space (`max-width`/`max-height`). @default false */\n fitViewport?: boolean;\n /** An arrow (beak) element inside the surface, positioned through `arrowStyles`. */\n arrowRef?: React.RefObject<HTMLElement | null>;\n /** CSS positioning strategy. @default 'fixed' */\n strategy?: 'absolute' | 'fixed';\n /**\n * Placements to try, in order, when the requested side has no room, instead of only the opposite\n * side. Ignored with `flip: false`. An omitted `align` is the hook's own `align`.\n */\n fallbackPlacements?: readonly PopupPlacement[];\n /**\n * Hide the surface (`visibility: hidden`: its layout is unaffected, but its content cannot take\n * focus, so a surface that holds focus loses it) while the anchor is scrolled out of view or\n * clipped away. @default false\n */\n hideWhenDetached?: boolean;\n /**\n * Called after the surface is positioned, and again whenever the final placement changes (a flip,\n * a fallback): not on every scroll or resize recompute. It runs from an effect, never during\n * render, and not while closed.\n */\n onPositioned?: (info: PositionedInfo) => void;\n}\n\n/** What {@link UsePopupPositionOptions.onPositioned} receives. */\nexport interface PositionedInfo {\n /** Final placement after flipping, e.g. `'top-start'`. */\n placement: string;\n /** Final physical side after flipping. */\n side: 'top' | 'bottom' | 'left' | 'right';\n /** Always `true`: the callback runs once a position exists. */\n isPositioned: boolean;\n}\n\n/** Returned by {@link usePopupPosition}. */\nexport interface UsePopupPositionResult {\n /**\n * Sets the anchor: a ref callback for the anchor (trigger) element, or a call from a layout\n * effect or an event. The anchor is an element or a `VirtualElement` (a rectangle such as the\n * pointer position; a new object on every render is fine); give it a `contextElement` so\n * scrolling its containers updates the position.\n */\n setReference(el: HTMLElement | VirtualElement | null): void;\n /** Ref callback for the popup surface. */\n setFloating(el: HTMLElement | null): void;\n /** Position styles for the surface (also in `floatingProps.style`). */\n floatingStyles: React.CSSProperties;\n /** Position styles for the arrow element. */\n arrowStyles: React.CSSProperties;\n /** Final placement after flipping, e.g. `'top-start'`. */\n placement: string;\n /** Final physical side after flipping. */\n side: 'top' | 'bottom' | 'left' | 'right';\n /** Whether a position has been computed since the popup opened. */\n isPositioned: boolean;\n /** Recomputes the position now, for a change floating-ui cannot observe. A no-op while closed. */\n update(): void;\n /** Spread onto the surface: `data-side`, `data-align` and the position style. */\n floatingProps: { 'data-side': string; 'data-align': string; style: React.CSSProperties };\n}\n\ntype PhysicalSide = 'top' | 'bottom' | 'left' | 'right';\n\n/**\n * Internal. The options a component's `positioning` prop sets on top of the component's own\n * defaults: a value the consumer gave (also `0` or `false`) wins, `undefined` keeps the default.\n */\nexport function resolvePositioning(\n positioning: PopupPositioning | undefined,\n defaults: { offset?: number; matchReferenceWidth?: boolean; fitViewport?: boolean },\n): Pick<\n UsePopupPositionOptions,\n 'offset' | 'matchReferenceWidth' | 'fitViewport' | 'fallbackPlacements'\n> {\n return {\n offset: positioning?.offset ?? defaults.offset,\n matchReferenceWidth: positioning?.matchReferenceWidth ?? defaults.matchReferenceWidth,\n fitViewport: positioning?.fitViewport ?? defaults.fitViewport,\n fallbackPlacements: positioning?.fallbackPlacements,\n };\n}\n\nconst STATIC_SIDE: Record<PhysicalSide, PhysicalSide> = {\n top: 'bottom',\n bottom: 'top',\n left: 'right',\n right: 'left',\n};\n\n/** Half the arrow size, so the arrow sticks out of the surface towards the anchor. */\nconst ARROW_OFFSET = 'calc(var(--wave-popup-arrow-size, 8px) / -2)';\n\nfunction resolveSide(side: PopupSide, dir: Direction): PhysicalSide {\n if (side === 'start') return dir === 'rtl' ? 'right' : 'left';\n if (side === 'end') return dir === 'rtl' ? 'left' : 'right';\n return side;\n}\n\n/** The rectangle of a virtual anchor that is not set (never reached while one is the reference). */\nconst EMPTY_RECT: PopupRect = {\n x: 0,\n y: 0,\n width: 0,\n height: 0,\n top: 0,\n right: 0,\n bottom: 0,\n left: 0,\n};\n\n/** Whether an anchor is a DOM element (duck typed, so an element of another realm counts). */\nfunction isElementAnchor(anchor: HTMLElement | VirtualElement): anchor is HTMLElement {\n return typeof (anchor as Partial<Node>).nodeType === 'number';\n}\n\n/**\n * The stable stand-in floating-ui gets for virtual anchors: it reads the latest `VirtualElement`\n * from `latest`, so a new virtual object sets no floating-ui state. One proxy per\n * `contextElement`, so `autoUpdate` observes the scroll containers of the current one.\n */\ninterface VirtualProxy extends VirtualElement {\n contextElement: Element | undefined;\n}\n\nfunction createVirtualProxy(\n latest: React.RefObject<VirtualElement | null>,\n contextElement: Element | undefined,\n): VirtualProxy {\n return {\n getBoundingClientRect: () => latest.current?.getBoundingClientRect() ?? EMPTY_RECT,\n contextElement,\n };\n}\n\n/** Keeps the position updated while mounted; observers are used only where they exist. */\nfunction whileElementsMounted(\n reference: ReferenceType,\n floating: HTMLElement,\n update: () => void,\n): () => void {\n return autoUpdate(reference, floating, update, {\n elementResize: typeof ResizeObserver !== 'undefined',\n layoutShift: typeof IntersectionObserver !== 'undefined',\n });\n}\n\n/**\n * Writes the available space and the anchor width as CSS variables on the surface:\n * `--wave-popup-available-width`, `--wave-popup-available-height`, `--wave-popup-reference-width`.\n * It captures no options (floating-ui compares middleware functions by source text).\n */\nconst sizeApply: NonNullable<SizeOptions['apply']> = ({\n availableWidth,\n availableHeight,\n rects,\n elements,\n}) => {\n const style = elements.floating.style;\n style.setProperty('--wave-popup-available-width', `${Math.max(0, Math.floor(availableWidth))}px`);\n style.setProperty(\n '--wave-popup-available-height',\n `${Math.max(0, Math.floor(availableHeight))}px`,\n );\n style.setProperty('--wave-popup-reference-width', `${Math.round(rects.reference.width)}px`);\n};\n\n/**\n * Positions a popup surface next to its anchor with `@floating-ui/react-dom` (Tooltip, Popover,\n * Menu, listboxes, the DatePicker calendar, TeachingPopover): `offset`, `flip`, `shift`, optional\n * `size` (reference width / available space as CSS variables) and `arrow`. `flip`, `shift` and\n * `size` keep the same viewport padding, taken from the `shift` option (8px by default). Logical\n * `start`/`end` sides follow `useDirection()` (the WaveProvider `dir`, else the document\n * direction), and so does start/end alignment.\n *\n * Positions update only while `open` (`autoUpdate` on scroll/resize; element resizes and layout\n * shifts only where `ResizeObserver`/`IntersectionObserver` exist). Spread `floatingProps` onto the\n * surface: `data-side`/`data-align` expose the final placement for styling (C-CLASS).\n *\n * The anchor is an element or a `VirtualElement` (a rectangle such as the pointer position; a new\n * object on every render is fine); give it a `contextElement` so scrolling its containers updates\n * the position. A virtual anchor reaches floating-ui through one stable proxy that reads the latest\n * object: a new object only recomputes the position (which renders only when the position\n * changes), and a new proxy is made only when the `contextElement` changes.\n *\n * Destructure the result: `eslint-plugin-react-hooks` (`react-hooks/refs`) treats an object\n * whose member is passed to a `ref` prop as a ref, and then rejects reading its other members\n * during render.\n *\n * @example\n * const { setReference, setFloating, floatingProps } = usePopupPosition({ open, side: 'bottom' });\n * <button ref={setReference} />\n * {open && <Portal><div ref={setFloating} {...floatingProps} /></Portal>}\n */\nexport function usePopupPosition(options: UsePopupPositionOptions): UsePopupPositionResult {\n const {\n open,\n side = 'bottom',\n align = 'start',\n offset = 4,\n flip = true,\n shift = { padding: 8 },\n matchReferenceWidth = false,\n fitViewport = false,\n arrowRef,\n strategy = 'fixed',\n fallbackPlacements,\n hideWhenDetached = false,\n onPositioned,\n } = options;\n const dir = useDirection();\n const physicalSide = resolveSide(side, dir);\n const toPlacement = (placementSide: PhysicalSide, placementAlign: PopupAlign) =>\n (placementAlign === 'center'\n ? placementSide\n : `${placementSide}-${placementAlign}`) as Placement;\n const requestedPlacement = toPlacement(physicalSide, align);\n const padding = shift === false ? 0 : shift === true ? 8 : shift.padding;\n const shiftCrossAxis = typeof shift === 'object' && shift.crossAxis === true;\n\n const middleware: Middleware[] = [offsetMiddleware(offset)];\n if (flip) {\n middleware.push(\n flipMiddleware({\n padding,\n ...(fallbackPlacements && {\n fallbackPlacements: fallbackPlacements.map((placement) =>\n toPlacement(resolveSide(placement.side, dir), placement.align ?? align),\n ),\n }),\n }),\n );\n }\n if (shift !== false) {\n middleware.push(shiftMiddleware({ padding, crossAxis: shiftCrossAxis }));\n }\n if (matchReferenceWidth || fitViewport) {\n middleware.push(sizeMiddleware({ padding, apply: sizeApply }));\n }\n if (hideWhenDetached) middleware.push(hideMiddleware({ strategy: 'referenceHidden' }));\n if (arrowRef) middleware.push(arrowMiddleware({ element: arrowRef }));\n\n // Alignment follows the hook's direction (not only the surface's computed CSS direction).\n const directionalPlatform = useMemo<Platform>(\n () => ({ ...platform, isRTL: () => dir === 'rtl' }),\n [dir],\n );\n\n const { refs, floatingStyles, placement, middlewareData, isPositioned, update } = useFloating({\n open,\n placement: requestedPlacement,\n strategy,\n middleware,\n platform: directionalPlatform,\n whileElementsMounted: open ? whileElementsMounted : undefined,\n });\n\n // Virtual anchors: the latest object (written in setReference, never during render) and the\n // proxy floating-ui holds for it.\n const virtualRef = useRef<VirtualElement | null>(null);\n const proxyRef = useRef<VirtualProxy | null>(null);\n const updatePosition = useEventCallback(update);\n const updateWhileOpen = useEventCallback(() => {\n if (open) update();\n });\n const { setReference: setFloatingReference, reference: floatingReference } = refs;\n const setReference = useCallback(\n (anchor: HTMLElement | VirtualElement | null) => {\n if (anchor === null || isElementAnchor(anchor)) {\n virtualRef.current = null;\n setFloatingReference(anchor);\n return;\n }\n virtualRef.current = anchor;\n let proxy = proxyRef.current;\n if (!proxy || proxy.contextElement !== anchor.contextElement) {\n proxy = createVirtualProxy(virtualRef, anchor.contextElement);\n proxyRef.current = proxy;\n }\n if (floatingReference.current === proxy) updatePosition();\n else setFloatingReference(proxy);\n },\n [setFloatingReference, floatingReference, updatePosition],\n );\n\n const [finalSide, finalAlign = 'center'] = placement.split('-') as [PhysicalSide, string?];\n\n const reportPositioned = useEventCallback((info: PositionedInfo) => onPositioned?.(info));\n useEffect(() => {\n if (open && isPositioned) {\n reportPositioned({ placement, side: finalSide, isPositioned: true });\n }\n }, [open, isPositioned, placement, finalSide, reportPositioned]);\n\n const referenceHidden = middlewareData.hide?.referenceHidden === true;\n const style = useMemo<React.CSSProperties>(() => {\n const next: React.CSSProperties = { ...floatingStyles };\n if (matchReferenceWidth) next.width = 'var(--wave-popup-reference-width)';\n if (fitViewport) {\n next.maxWidth = 'var(--wave-popup-available-width)';\n next.maxHeight = 'var(--wave-popup-available-height)';\n }\n if (referenceHidden) next.visibility = 'hidden';\n return next;\n }, [floatingStyles, matchReferenceWidth, fitViewport, referenceHidden]);\n\n const arrowX = middlewareData.arrow?.x;\n const arrowY = middlewareData.arrow?.y;\n const arrowStyles = useMemo<React.CSSProperties>(() => {\n const styles: Record<string, string> = {\n position: 'absolute',\n left: arrowX != null ? `${arrowX}px` : '',\n top: arrowY != null ? `${arrowY}px` : '',\n };\n styles[STATIC_SIDE[finalSide]] = ARROW_OFFSET;\n return styles as React.CSSProperties;\n }, [arrowX, arrowY, finalSide]);\n\n const floatingProps = useMemo(\n () => ({ 'data-side': finalSide, 'data-align': finalAlign, style }),\n [finalSide, finalAlign, style],\n );\n\n return {\n setReference,\n setFloating: refs.setFloating,\n floatingStyles: style,\n arrowStyles,\n placement,\n side: finalSide,\n isPositioned,\n update: updateWhileOpen,\n floatingProps,\n };\n}\n"],"mappings":"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"}
|
|
@@ -1,9 +1,17 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { useEventCallback as e } from "./useEventCallback.mjs";
|
|
3
3
|
import { useDirection as t } from "./useDirection.mjs";
|
|
4
|
-
import { useCallback as n,
|
|
5
|
-
import { arrow as
|
|
4
|
+
import { useCallback as n, useEffect as r, useMemo as i, useRef as a } from "react";
|
|
5
|
+
import { arrow as o, autoUpdate as s, flip as ee, hide as te, offset as ne, platform as c, shift as l, size as u, useFloating as d } from "@floating-ui/react-dom";
|
|
6
6
|
//#region src/hooks/usePopupPosition.ts
|
|
7
|
+
function f(e, t) {
|
|
8
|
+
return {
|
|
9
|
+
offset: e?.offset ?? t.offset,
|
|
10
|
+
matchReferenceWidth: e?.matchReferenceWidth ?? t.matchReferenceWidth,
|
|
11
|
+
fitViewport: e?.fitViewport ?? t.fitViewport,
|
|
12
|
+
fallbackPlacements: e?.fallbackPlacements
|
|
13
|
+
};
|
|
14
|
+
}
|
|
7
15
|
var p = {
|
|
8
16
|
top: "bottom",
|
|
9
17
|
bottom: "top",
|
|
@@ -26,92 +34,113 @@ var g = {
|
|
|
26
34
|
function _(e) {
|
|
27
35
|
return typeof e.nodeType == "number";
|
|
28
36
|
}
|
|
29
|
-
function
|
|
37
|
+
function re(e, t) {
|
|
30
38
|
return {
|
|
31
39
|
getBoundingClientRect: () => e.current?.getBoundingClientRect() ?? g,
|
|
32
40
|
contextElement: t
|
|
33
41
|
};
|
|
34
42
|
}
|
|
35
|
-
function
|
|
36
|
-
return
|
|
43
|
+
function ie(e, t, n) {
|
|
44
|
+
return s(e, t, n, {
|
|
37
45
|
elementResize: typeof ResizeObserver < "u",
|
|
38
46
|
layoutShift: typeof IntersectionObserver < "u"
|
|
39
47
|
});
|
|
40
48
|
}
|
|
41
|
-
var
|
|
49
|
+
var ae = ({ availableWidth: e, availableHeight: t, rects: n, elements: r }) => {
|
|
42
50
|
let i = r.floating.style;
|
|
43
51
|
i.setProperty("--wave-popup-available-width", `${Math.max(0, Math.floor(e))}px`), i.setProperty("--wave-popup-available-height", `${Math.max(0, Math.floor(t))}px`), i.setProperty("--wave-popup-reference-width", `${Math.round(n.reference.width)}px`);
|
|
44
52
|
};
|
|
45
|
-
function
|
|
46
|
-
let { open:
|
|
47
|
-
|
|
48
|
-
padding:
|
|
49
|
-
|
|
50
|
-
})),
|
|
51
|
-
padding:
|
|
52
|
-
|
|
53
|
-
})),
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
53
|
+
function v(s) {
|
|
54
|
+
let { open: f, side: g = "bottom", align: v = "start", offset: y = 4, flip: b = !0, shift: x = { padding: 8 }, matchReferenceWidth: S = !1, fitViewport: C = !1, arrowRef: w, strategy: T = "fixed", fallbackPlacements: E, hideWhenDetached: D = !1, onPositioned: O } = s, k = t(), oe = h(g, k), A = (e, t) => t === "center" ? e : `${e}-${t}`, se = A(oe, v), j = x === !1 ? 0 : x === !0 ? 8 : x.padding, M = typeof x == "object" && x.crossAxis === !0, N = [ne(y)];
|
|
55
|
+
b && N.push(ee({
|
|
56
|
+
padding: j,
|
|
57
|
+
...E && { fallbackPlacements: E.map((e) => A(h(e.side, k), e.align ?? v)) }
|
|
58
|
+
})), x !== !1 && N.push(l({
|
|
59
|
+
padding: j,
|
|
60
|
+
crossAxis: M
|
|
61
|
+
})), (S || C) && N.push(u({
|
|
62
|
+
padding: j,
|
|
63
|
+
apply: ae
|
|
64
|
+
})), D && N.push(te({ strategy: "referenceHidden" })), w && N.push(o({ element: w }));
|
|
65
|
+
let P = i(() => ({
|
|
66
|
+
...c,
|
|
67
|
+
isRTL: () => k === "rtl"
|
|
68
|
+
}), [k]), { refs: F, floatingStyles: I, placement: L, middlewareData: R, isPositioned: z, update: B } = d({
|
|
69
|
+
open: f,
|
|
70
|
+
placement: se,
|
|
71
|
+
strategy: T,
|
|
72
|
+
middleware: N,
|
|
73
|
+
platform: P,
|
|
74
|
+
whileElementsMounted: f ? ie : void 0
|
|
75
|
+
}), V = a(null), H = a(null), U = e(B), W = e(() => {
|
|
76
|
+
f && B();
|
|
77
|
+
}), { setReference: G, reference: K } = F, ce = n((e) => {
|
|
65
78
|
if (e === null || _(e)) {
|
|
66
|
-
|
|
79
|
+
V.current = null, G(e);
|
|
67
80
|
return;
|
|
68
81
|
}
|
|
69
|
-
|
|
70
|
-
let t =
|
|
71
|
-
(!t || t.contextElement !== e.contextElement) && (t =
|
|
82
|
+
V.current = e;
|
|
83
|
+
let t = H.current;
|
|
84
|
+
(!t || t.contextElement !== e.contextElement) && (t = re(V, e.contextElement), H.current = t), K.current === t ? U() : G(t);
|
|
72
85
|
}, [
|
|
86
|
+
G,
|
|
73
87
|
K,
|
|
88
|
+
U
|
|
89
|
+
]), [q, J = "center"] = L.split("-"), Y = e((e) => O?.(e));
|
|
90
|
+
r(() => {
|
|
91
|
+
f && z && Y({
|
|
92
|
+
placement: L,
|
|
93
|
+
side: q,
|
|
94
|
+
isPositioned: !0
|
|
95
|
+
});
|
|
96
|
+
}, [
|
|
97
|
+
f,
|
|
98
|
+
z,
|
|
99
|
+
L,
|
|
74
100
|
q,
|
|
75
|
-
|
|
76
|
-
])
|
|
77
|
-
|
|
78
|
-
|
|
101
|
+
Y
|
|
102
|
+
]);
|
|
103
|
+
let X = R.hide?.referenceHidden === !0, Z = i(() => {
|
|
104
|
+
let e = { ...I };
|
|
105
|
+
return S && (e.width = "var(--wave-popup-reference-width)"), C && (e.maxWidth = "var(--wave-popup-available-width)", e.maxHeight = "var(--wave-popup-available-height)"), X && (e.visibility = "hidden"), e;
|
|
79
106
|
}, [
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
107
|
+
I,
|
|
108
|
+
S,
|
|
109
|
+
C,
|
|
110
|
+
X
|
|
111
|
+
]), Q = R.arrow?.x, $ = R.arrow?.y, le = i(() => {
|
|
84
112
|
let e = {
|
|
85
113
|
position: "absolute",
|
|
86
114
|
left: Q == null ? "" : `${Q}px`,
|
|
87
115
|
top: $ == null ? "" : `${$}px`
|
|
88
116
|
};
|
|
89
|
-
return e[p[
|
|
117
|
+
return e[p[q]] = m, e;
|
|
90
118
|
}, [
|
|
91
119
|
Q,
|
|
92
120
|
$,
|
|
93
|
-
|
|
94
|
-
]),
|
|
95
|
-
"data-side":
|
|
96
|
-
"data-align":
|
|
121
|
+
q
|
|
122
|
+
]), ue = i(() => ({
|
|
123
|
+
"data-side": q,
|
|
124
|
+
"data-align": J,
|
|
97
125
|
style: Z
|
|
98
126
|
}), [
|
|
99
|
-
|
|
100
|
-
|
|
127
|
+
q,
|
|
128
|
+
J,
|
|
101
129
|
Z
|
|
102
130
|
]);
|
|
103
131
|
return {
|
|
104
|
-
setReference:
|
|
105
|
-
setFloating:
|
|
132
|
+
setReference: ce,
|
|
133
|
+
setFloating: F.setFloating,
|
|
106
134
|
floatingStyles: Z,
|
|
107
|
-
arrowStyles:
|
|
108
|
-
placement:
|
|
109
|
-
side:
|
|
110
|
-
isPositioned:
|
|
111
|
-
|
|
135
|
+
arrowStyles: le,
|
|
136
|
+
placement: L,
|
|
137
|
+
side: q,
|
|
138
|
+
isPositioned: z,
|
|
139
|
+
update: W,
|
|
140
|
+
floatingProps: ue
|
|
112
141
|
};
|
|
113
142
|
}
|
|
114
143
|
//#endregion
|
|
115
|
-
export {
|
|
144
|
+
export { f as resolvePositioning, v as usePopupPosition };
|
|
116
145
|
|
|
117
146
|
//# sourceMappingURL=usePopupPosition.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"usePopupPosition.mjs","names":["shift","offsetMiddleware","offset","flip","flipMiddleware","shiftMiddleware","sizeMiddleware","arrowMiddleware","STATIC_SIDE","ARROW_OFFSET","resolveSide","side","dir","EMPTY_RECT","isElementAnchor","anchor","createVirtualProxy","latest","whileElementsMounted","autoUpdate","reference","floating","update","sizeApply","style","elements","availableWidth","availableHeight","rects","usePopupPosition","offset$1","flip$1","shift$1","options","useDirection","physicalSide","requestedPlacement","align","padding","shiftCrossAxis","middleware","offset","flip","shift","matchReferenceWidth","fitViewport","size","arrowRef","arrow","directionalPlatform","useMemo","platform","useFloating","open","virtualRef","useRef","proxyRef","updatePosition","useEventCallback","setFloatingReference","floatingReference","refs","setReference","useCallback","proxy","finalSide","finalAlign","placement","next","floatingStyles","arrowX","middlewareData","arrowY","arrowStyles","styles","floatingProps"],"sources":["../../src/hooks/usePopupPosition.ts"],"sourcesContent":["import { useCallback, useMemo, useRef } from 'react';\nimport type * as React from 'react';\nimport {\n arrow as arrowMiddleware,\n autoUpdate,\n flip as flipMiddleware,\n offset as offsetMiddleware,\n platform,\n shift as shiftMiddleware,\n size as sizeMiddleware,\n useFloating,\n type Middleware,\n type Placement,\n type Platform,\n type ReferenceType,\n type SizeOptions,\n} from '@floating-ui/react-dom';\nimport type { PopupAlign, PopupRect, PopupSide, VirtualElement } from '../lib/types';\nimport type { Direction } from '../lib/direction';\nimport { useDirection } from './useDirection';\nimport { useEventCallback } from './useEventCallback';\n\n/** Options of {@link usePopupPosition}. */\nexport interface UsePopupPositionOptions {\n /** Whether the popup is open; positions are kept up to date only while `true`. */\n open: boolean;\n /** Side of the anchor. `start`/`end` follow the writing direction. @default 'bottom' */\n side?: PopupSide;\n /** Alignment along that side. @default 'start' */\n align?: PopupAlign;\n /** Distance from the anchor in px. @default 4 (tooltips use 8) */\n offset?: number;\n /** Flip to the opposite side when there is not enough room. @default true */\n flip?: boolean;\n /**\n * Shift along the side to stay inside the viewport. Its padding is also the viewport padding of\n * `flip` and of `size` (`fitViewport`, `matchReferenceWidth`): `true` means 8px, and `false`\n * lets the popup flip only once it touches the viewport edge and grow right up to it. With\n * `crossAxis: true` it also shifts across the side, over the anchor, when neither side has room\n * after `flip` (submenus), and `fitViewport` then offers the whole viewport in that direction.\n * @default { padding: 8 }\n */\n shift?: boolean | { padding: number; crossAxis?: boolean };\n /** Make the surface as wide as the anchor (listboxes). @default false */\n matchReferenceWidth?: boolean;\n /** Limit the surface to the available space (`max-width`/`max-height`). @default false */\n fitViewport?: boolean;\n /** An arrow (beak) element inside the surface, positioned through `arrowStyles`. */\n arrowRef?: React.RefObject<HTMLElement | null>;\n /** CSS positioning strategy. @default 'fixed' */\n strategy?: 'absolute' | 'fixed';\n}\n\n/** Returned by {@link usePopupPosition}. */\nexport interface UsePopupPositionResult {\n /**\n * Sets the anchor: a ref callback for the anchor (trigger) element, or a call from a layout\n * effect or an event. The anchor is an element or a `VirtualElement` (a rectangle such as the\n * pointer position; a new object on every render is fine); give it a `contextElement` so\n * scrolling its containers updates the position.\n */\n setReference(el: HTMLElement | VirtualElement | null): void;\n /** Ref callback for the popup surface. */\n setFloating(el: HTMLElement | null): void;\n /** Position styles for the surface (also in `floatingProps.style`). */\n floatingStyles: React.CSSProperties;\n /** Position styles for the arrow element. */\n arrowStyles: React.CSSProperties;\n /** Final placement after flipping, e.g. `'top-start'`. */\n placement: string;\n /** Final physical side after flipping. */\n side: 'top' | 'bottom' | 'left' | 'right';\n /** Whether a position has been computed since the popup opened. */\n isPositioned: boolean;\n /** Spread onto the surface: `data-side`, `data-align` and the position style. */\n floatingProps: { 'data-side': string; 'data-align': string; style: React.CSSProperties };\n}\n\ntype PhysicalSide = 'top' | 'bottom' | 'left' | 'right';\n\nconst STATIC_SIDE: Record<PhysicalSide, PhysicalSide> = {\n top: 'bottom',\n bottom: 'top',\n left: 'right',\n right: 'left',\n};\n\n/** Half the arrow size, so the arrow sticks out of the surface towards the anchor. */\nconst ARROW_OFFSET = 'calc(var(--wave-popup-arrow-size, 8px) / -2)';\n\nfunction resolveSide(side: PopupSide, dir: Direction): PhysicalSide {\n if (side === 'start') return dir === 'rtl' ? 'right' : 'left';\n if (side === 'end') return dir === 'rtl' ? 'left' : 'right';\n return side;\n}\n\n/** The rectangle of a virtual anchor that is not set (never reached while one is the reference). */\nconst EMPTY_RECT: PopupRect = {\n x: 0,\n y: 0,\n width: 0,\n height: 0,\n top: 0,\n right: 0,\n bottom: 0,\n left: 0,\n};\n\n/** Whether an anchor is a DOM element (duck typed, so an element of another realm counts). */\nfunction isElementAnchor(anchor: HTMLElement | VirtualElement): anchor is HTMLElement {\n return typeof (anchor as Partial<Node>).nodeType === 'number';\n}\n\n/**\n * The stable stand-in floating-ui gets for virtual anchors: it reads the latest `VirtualElement`\n * from `latest`, so a new virtual object sets no floating-ui state. One proxy per\n * `contextElement`, so `autoUpdate` observes the scroll containers of the current one.\n */\ninterface VirtualProxy extends VirtualElement {\n contextElement: Element | undefined;\n}\n\nfunction createVirtualProxy(\n latest: React.RefObject<VirtualElement | null>,\n contextElement: Element | undefined,\n): VirtualProxy {\n return {\n getBoundingClientRect: () => latest.current?.getBoundingClientRect() ?? EMPTY_RECT,\n contextElement,\n };\n}\n\n/** Keeps the position updated while mounted; observers are used only where they exist. */\nfunction whileElementsMounted(\n reference: ReferenceType,\n floating: HTMLElement,\n update: () => void,\n): () => void {\n return autoUpdate(reference, floating, update, {\n elementResize: typeof ResizeObserver !== 'undefined',\n layoutShift: typeof IntersectionObserver !== 'undefined',\n });\n}\n\n/**\n * Writes the available space and the anchor width as CSS variables on the surface:\n * `--wave-popup-available-width`, `--wave-popup-available-height`, `--wave-popup-reference-width`.\n * It captures no options (floating-ui compares middleware functions by source text).\n */\nconst sizeApply: NonNullable<SizeOptions['apply']> = ({\n availableWidth,\n availableHeight,\n rects,\n elements,\n}) => {\n const style = elements.floating.style;\n style.setProperty('--wave-popup-available-width', `${Math.max(0, Math.floor(availableWidth))}px`);\n style.setProperty(\n '--wave-popup-available-height',\n `${Math.max(0, Math.floor(availableHeight))}px`,\n );\n style.setProperty('--wave-popup-reference-width', `${Math.round(rects.reference.width)}px`);\n};\n\n/**\n * Positions a popup surface next to its anchor with `@floating-ui/react-dom` (Tooltip, Popover,\n * Menu, listboxes, the DatePicker calendar, TeachingPopover): `offset`, `flip`, `shift`, optional\n * `size` (reference width / available space as CSS variables) and `arrow`. `flip`, `shift` and\n * `size` keep the same viewport padding, taken from the `shift` option (8px by default). Logical\n * `start`/`end` sides follow `useDirection()` (the WaveProvider `dir`, else the document\n * direction), and so does start/end alignment.\n *\n * Positions update only while `open` (`autoUpdate` on scroll/resize; element resizes and layout\n * shifts only where `ResizeObserver`/`IntersectionObserver` exist). Spread `floatingProps` onto the\n * surface: `data-side`/`data-align` expose the final placement for styling (C-CLASS).\n *\n * The anchor is an element or a `VirtualElement` (a rectangle such as the pointer position; a new\n * object on every render is fine); give it a `contextElement` so scrolling its containers updates\n * the position. A virtual anchor reaches floating-ui through one stable proxy that reads the latest\n * object: a new object only recomputes the position (which renders only when the position\n * changes), and a new proxy is made only when the `contextElement` changes.\n *\n * Destructure the result: `eslint-plugin-react-hooks` (`react-hooks/refs`) treats an object\n * whose member is passed to a `ref` prop as a ref, and then rejects reading its other members\n * during render.\n *\n * @example\n * const { setReference, setFloating, floatingProps } = usePopupPosition({ open, side: 'bottom' });\n * <button ref={setReference} />\n * {open && <Portal><div ref={setFloating} {...floatingProps} /></Portal>}\n */\nexport function usePopupPosition(options: UsePopupPositionOptions): UsePopupPositionResult {\n const {\n open,\n side = 'bottom',\n align = 'start',\n offset = 4,\n flip = true,\n shift = { padding: 8 },\n matchReferenceWidth = false,\n fitViewport = false,\n arrowRef,\n strategy = 'fixed',\n } = options;\n const dir = useDirection();\n const physicalSide = resolveSide(side, dir);\n const requestedPlacement = (\n align === 'center' ? physicalSide : `${physicalSide}-${align}`\n ) as Placement;\n const padding = shift === false ? 0 : shift === true ? 8 : shift.padding;\n const shiftCrossAxis = typeof shift === 'object' && shift.crossAxis === true;\n\n const middleware: Middleware[] = [offsetMiddleware(offset)];\n if (flip) middleware.push(flipMiddleware({ padding }));\n if (shift !== false) {\n middleware.push(shiftMiddleware({ padding, crossAxis: shiftCrossAxis }));\n }\n if (matchReferenceWidth || fitViewport) {\n middleware.push(sizeMiddleware({ padding, apply: sizeApply }));\n }\n if (arrowRef) middleware.push(arrowMiddleware({ element: arrowRef }));\n\n // Alignment follows the hook's direction (not only the surface's computed CSS direction).\n const directionalPlatform = useMemo<Platform>(\n () => ({ ...platform, isRTL: () => dir === 'rtl' }),\n [dir],\n );\n\n const { refs, floatingStyles, placement, middlewareData, isPositioned, update } = useFloating({\n open,\n placement: requestedPlacement,\n strategy,\n middleware,\n platform: directionalPlatform,\n whileElementsMounted: open ? whileElementsMounted : undefined,\n });\n\n // Virtual anchors: the latest object (written in setReference, never during render) and the\n // proxy floating-ui holds for it.\n const virtualRef = useRef<VirtualElement | null>(null);\n const proxyRef = useRef<VirtualProxy | null>(null);\n const updatePosition = useEventCallback(update);\n const { setReference: setFloatingReference, reference: floatingReference } = refs;\n const setReference = useCallback(\n (anchor: HTMLElement | VirtualElement | null) => {\n if (anchor === null || isElementAnchor(anchor)) {\n virtualRef.current = null;\n setFloatingReference(anchor);\n return;\n }\n virtualRef.current = anchor;\n let proxy = proxyRef.current;\n if (!proxy || proxy.contextElement !== anchor.contextElement) {\n proxy = createVirtualProxy(virtualRef, anchor.contextElement);\n proxyRef.current = proxy;\n }\n if (floatingReference.current === proxy) updatePosition();\n else setFloatingReference(proxy);\n },\n [setFloatingReference, floatingReference, updatePosition],\n );\n\n const [finalSide, finalAlign = 'center'] = placement.split('-') as [PhysicalSide, string?];\n\n const style = useMemo<React.CSSProperties>(() => {\n const next: React.CSSProperties = { ...floatingStyles };\n if (matchReferenceWidth) next.width = 'var(--wave-popup-reference-width)';\n if (fitViewport) {\n next.maxWidth = 'var(--wave-popup-available-width)';\n next.maxHeight = 'var(--wave-popup-available-height)';\n }\n return next;\n }, [floatingStyles, matchReferenceWidth, fitViewport]);\n\n const arrowX = middlewareData.arrow?.x;\n const arrowY = middlewareData.arrow?.y;\n const arrowStyles = useMemo<React.CSSProperties>(() => {\n const styles: Record<string, string> = {\n position: 'absolute',\n left: arrowX != null ? `${arrowX}px` : '',\n top: arrowY != null ? `${arrowY}px` : '',\n };\n styles[STATIC_SIDE[finalSide]] = ARROW_OFFSET;\n return styles as React.CSSProperties;\n }, [arrowX, arrowY, finalSide]);\n\n const floatingProps = useMemo(\n () => ({ 'data-side': finalSide, 'data-align': finalAlign, style }),\n [finalSide, finalAlign, style],\n );\n\n return {\n setReference,\n setFloating: refs.setFloating,\n floatingStyles: style,\n arrowStyles,\n placement,\n side: finalSide,\n isPositioned,\n floatingProps,\n };\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"usePopupPosition.mjs","names":["shift","offsetMiddleware","offset","flip","flipMiddleware","shiftMiddleware","sizeMiddleware","hideMiddleware","arrowMiddleware","resolvePositioning","positioning","defaults","STATIC_SIDE","ARROW_OFFSET","resolveSide","side","dir","EMPTY_RECT","isElementAnchor","anchor","createVirtualProxy","latest","whileElementsMounted","autoUpdate","reference","floating","update","sizeApply","style","elements","availableWidth","availableHeight","rects","usePopupPosition","offset$1","flip$1","shift$1","options","useDirection","physicalSide","toPlacement","placementAlign","placementSide","requestedPlacement","align","padding","shiftCrossAxis","middleware","offset","flip","fallbackPlacements","placement","shift","matchReferenceWidth","fitViewport","size","hideWhenDetached","hide","arrowRef","arrow","directionalPlatform","useMemo","platform","useFloating","open","virtualRef","useRef","proxyRef","updatePosition","useEventCallback","updateWhileOpen","setFloatingReference","floatingReference","refs","setReference","useCallback","proxy","finalSide","finalAlign","reportPositioned","onPositioned","info","isPositioned","referenceHidden","middlewareData","next","floatingStyles","arrowX","arrowY","arrowStyles","styles","floatingProps"],"sources":["../../src/hooks/usePopupPosition.ts"],"sourcesContent":["import { useCallback, useEffect, useMemo, useRef } from 'react';\nimport type * as React from 'react';\nimport {\n arrow as arrowMiddleware,\n autoUpdate,\n flip as flipMiddleware,\n hide as hideMiddleware,\n offset as offsetMiddleware,\n platform,\n shift as shiftMiddleware,\n size as sizeMiddleware,\n useFloating,\n type Middleware,\n type Placement,\n type Platform,\n type ReferenceType,\n type SizeOptions,\n} from '@floating-ui/react-dom';\nimport type {\n PopupAlign,\n PopupPlacement,\n PopupPositioning,\n PopupRect,\n PopupSide,\n VirtualElement,\n} from '../lib/types';\nimport type { Direction } from '../lib/direction';\nimport { useDirection } from './useDirection';\nimport { useEventCallback } from './useEventCallback';\n\n/** Options of {@link usePopupPosition}. */\nexport interface UsePopupPositionOptions {\n /** Whether the popup is open; positions are kept up to date only while `true`. */\n open: boolean;\n /** Side of the anchor. `start`/`end` follow the writing direction. @default 'bottom' */\n side?: PopupSide;\n /** Alignment along that side. @default 'start' */\n align?: PopupAlign;\n /** Distance from the anchor in px. @default 4 (tooltips use 8) */\n offset?: number;\n /** Flip to the opposite side when there is not enough room. @default true */\n flip?: boolean;\n /**\n * Shift along the side to stay inside the viewport. Its padding is also the viewport padding of\n * `flip` and of `size` (`fitViewport`, `matchReferenceWidth`): `true` means 8px, and `false`\n * lets the popup flip only once it touches the viewport edge and grow right up to it. With\n * `crossAxis: true` it also shifts across the side, over the anchor, when neither side has room\n * after `flip` (submenus), and `fitViewport` then offers the whole viewport in that direction.\n * @default { padding: 8 }\n */\n shift?: boolean | { padding: number; crossAxis?: boolean };\n /** Make the surface as wide as the anchor (listboxes). @default false */\n matchReferenceWidth?: boolean;\n /** Limit the surface to the available space (`max-width`/`max-height`). @default false */\n fitViewport?: boolean;\n /** An arrow (beak) element inside the surface, positioned through `arrowStyles`. */\n arrowRef?: React.RefObject<HTMLElement | null>;\n /** CSS positioning strategy. @default 'fixed' */\n strategy?: 'absolute' | 'fixed';\n /**\n * Placements to try, in order, when the requested side has no room, instead of only the opposite\n * side. Ignored with `flip: false`. An omitted `align` is the hook's own `align`.\n */\n fallbackPlacements?: readonly PopupPlacement[];\n /**\n * Hide the surface (`visibility: hidden`: its layout is unaffected, but its content cannot take\n * focus, so a surface that holds focus loses it) while the anchor is scrolled out of view or\n * clipped away. @default false\n */\n hideWhenDetached?: boolean;\n /**\n * Called after the surface is positioned, and again whenever the final placement changes (a flip,\n * a fallback): not on every scroll or resize recompute. It runs from an effect, never during\n * render, and not while closed.\n */\n onPositioned?: (info: PositionedInfo) => void;\n}\n\n/** What {@link UsePopupPositionOptions.onPositioned} receives. */\nexport interface PositionedInfo {\n /** Final placement after flipping, e.g. `'top-start'`. */\n placement: string;\n /** Final physical side after flipping. */\n side: 'top' | 'bottom' | 'left' | 'right';\n /** Always `true`: the callback runs once a position exists. */\n isPositioned: boolean;\n}\n\n/** Returned by {@link usePopupPosition}. */\nexport interface UsePopupPositionResult {\n /**\n * Sets the anchor: a ref callback for the anchor (trigger) element, or a call from a layout\n * effect or an event. The anchor is an element or a `VirtualElement` (a rectangle such as the\n * pointer position; a new object on every render is fine); give it a `contextElement` so\n * scrolling its containers updates the position.\n */\n setReference(el: HTMLElement | VirtualElement | null): void;\n /** Ref callback for the popup surface. */\n setFloating(el: HTMLElement | null): void;\n /** Position styles for the surface (also in `floatingProps.style`). */\n floatingStyles: React.CSSProperties;\n /** Position styles for the arrow element. */\n arrowStyles: React.CSSProperties;\n /** Final placement after flipping, e.g. `'top-start'`. */\n placement: string;\n /** Final physical side after flipping. */\n side: 'top' | 'bottom' | 'left' | 'right';\n /** Whether a position has been computed since the popup opened. */\n isPositioned: boolean;\n /** Recomputes the position now, for a change floating-ui cannot observe. A no-op while closed. */\n update(): void;\n /** Spread onto the surface: `data-side`, `data-align` and the position style. */\n floatingProps: { 'data-side': string; 'data-align': string; style: React.CSSProperties };\n}\n\ntype PhysicalSide = 'top' | 'bottom' | 'left' | 'right';\n\n/**\n * Internal. The options a component's `positioning` prop sets on top of the component's own\n * defaults: a value the consumer gave (also `0` or `false`) wins, `undefined` keeps the default.\n */\nexport function resolvePositioning(\n positioning: PopupPositioning | undefined,\n defaults: { offset?: number; matchReferenceWidth?: boolean; fitViewport?: boolean },\n): Pick<\n UsePopupPositionOptions,\n 'offset' | 'matchReferenceWidth' | 'fitViewport' | 'fallbackPlacements'\n> {\n return {\n offset: positioning?.offset ?? defaults.offset,\n matchReferenceWidth: positioning?.matchReferenceWidth ?? defaults.matchReferenceWidth,\n fitViewport: positioning?.fitViewport ?? defaults.fitViewport,\n fallbackPlacements: positioning?.fallbackPlacements,\n };\n}\n\nconst STATIC_SIDE: Record<PhysicalSide, PhysicalSide> = {\n top: 'bottom',\n bottom: 'top',\n left: 'right',\n right: 'left',\n};\n\n/** Half the arrow size, so the arrow sticks out of the surface towards the anchor. */\nconst ARROW_OFFSET = 'calc(var(--wave-popup-arrow-size, 8px) / -2)';\n\nfunction resolveSide(side: PopupSide, dir: Direction): PhysicalSide {\n if (side === 'start') return dir === 'rtl' ? 'right' : 'left';\n if (side === 'end') return dir === 'rtl' ? 'left' : 'right';\n return side;\n}\n\n/** The rectangle of a virtual anchor that is not set (never reached while one is the reference). */\nconst EMPTY_RECT: PopupRect = {\n x: 0,\n y: 0,\n width: 0,\n height: 0,\n top: 0,\n right: 0,\n bottom: 0,\n left: 0,\n};\n\n/** Whether an anchor is a DOM element (duck typed, so an element of another realm counts). */\nfunction isElementAnchor(anchor: HTMLElement | VirtualElement): anchor is HTMLElement {\n return typeof (anchor as Partial<Node>).nodeType === 'number';\n}\n\n/**\n * The stable stand-in floating-ui gets for virtual anchors: it reads the latest `VirtualElement`\n * from `latest`, so a new virtual object sets no floating-ui state. One proxy per\n * `contextElement`, so `autoUpdate` observes the scroll containers of the current one.\n */\ninterface VirtualProxy extends VirtualElement {\n contextElement: Element | undefined;\n}\n\nfunction createVirtualProxy(\n latest: React.RefObject<VirtualElement | null>,\n contextElement: Element | undefined,\n): VirtualProxy {\n return {\n getBoundingClientRect: () => latest.current?.getBoundingClientRect() ?? EMPTY_RECT,\n contextElement,\n };\n}\n\n/** Keeps the position updated while mounted; observers are used only where they exist. */\nfunction whileElementsMounted(\n reference: ReferenceType,\n floating: HTMLElement,\n update: () => void,\n): () => void {\n return autoUpdate(reference, floating, update, {\n elementResize: typeof ResizeObserver !== 'undefined',\n layoutShift: typeof IntersectionObserver !== 'undefined',\n });\n}\n\n/**\n * Writes the available space and the anchor width as CSS variables on the surface:\n * `--wave-popup-available-width`, `--wave-popup-available-height`, `--wave-popup-reference-width`.\n * It captures no options (floating-ui compares middleware functions by source text).\n */\nconst sizeApply: NonNullable<SizeOptions['apply']> = ({\n availableWidth,\n availableHeight,\n rects,\n elements,\n}) => {\n const style = elements.floating.style;\n style.setProperty('--wave-popup-available-width', `${Math.max(0, Math.floor(availableWidth))}px`);\n style.setProperty(\n '--wave-popup-available-height',\n `${Math.max(0, Math.floor(availableHeight))}px`,\n );\n style.setProperty('--wave-popup-reference-width', `${Math.round(rects.reference.width)}px`);\n};\n\n/**\n * Positions a popup surface next to its anchor with `@floating-ui/react-dom` (Tooltip, Popover,\n * Menu, listboxes, the DatePicker calendar, TeachingPopover): `offset`, `flip`, `shift`, optional\n * `size` (reference width / available space as CSS variables) and `arrow`. `flip`, `shift` and\n * `size` keep the same viewport padding, taken from the `shift` option (8px by default). Logical\n * `start`/`end` sides follow `useDirection()` (the WaveProvider `dir`, else the document\n * direction), and so does start/end alignment.\n *\n * Positions update only while `open` (`autoUpdate` on scroll/resize; element resizes and layout\n * shifts only where `ResizeObserver`/`IntersectionObserver` exist). Spread `floatingProps` onto the\n * surface: `data-side`/`data-align` expose the final placement for styling (C-CLASS).\n *\n * The anchor is an element or a `VirtualElement` (a rectangle such as the pointer position; a new\n * object on every render is fine); give it a `contextElement` so scrolling its containers updates\n * the position. A virtual anchor reaches floating-ui through one stable proxy that reads the latest\n * object: a new object only recomputes the position (which renders only when the position\n * changes), and a new proxy is made only when the `contextElement` changes.\n *\n * Destructure the result: `eslint-plugin-react-hooks` (`react-hooks/refs`) treats an object\n * whose member is passed to a `ref` prop as a ref, and then rejects reading its other members\n * during render.\n *\n * @example\n * const { setReference, setFloating, floatingProps } = usePopupPosition({ open, side: 'bottom' });\n * <button ref={setReference} />\n * {open && <Portal><div ref={setFloating} {...floatingProps} /></Portal>}\n */\nexport function usePopupPosition(options: UsePopupPositionOptions): UsePopupPositionResult {\n const {\n open,\n side = 'bottom',\n align = 'start',\n offset = 4,\n flip = true,\n shift = { padding: 8 },\n matchReferenceWidth = false,\n fitViewport = false,\n arrowRef,\n strategy = 'fixed',\n fallbackPlacements,\n hideWhenDetached = false,\n onPositioned,\n } = options;\n const dir = useDirection();\n const physicalSide = resolveSide(side, dir);\n const toPlacement = (placementSide: PhysicalSide, placementAlign: PopupAlign) =>\n (placementAlign === 'center'\n ? placementSide\n : `${placementSide}-${placementAlign}`) as Placement;\n const requestedPlacement = toPlacement(physicalSide, align);\n const padding = shift === false ? 0 : shift === true ? 8 : shift.padding;\n const shiftCrossAxis = typeof shift === 'object' && shift.crossAxis === true;\n\n const middleware: Middleware[] = [offsetMiddleware(offset)];\n if (flip) {\n middleware.push(\n flipMiddleware({\n padding,\n ...(fallbackPlacements && {\n fallbackPlacements: fallbackPlacements.map((placement) =>\n toPlacement(resolveSide(placement.side, dir), placement.align ?? align),\n ),\n }),\n }),\n );\n }\n if (shift !== false) {\n middleware.push(shiftMiddleware({ padding, crossAxis: shiftCrossAxis }));\n }\n if (matchReferenceWidth || fitViewport) {\n middleware.push(sizeMiddleware({ padding, apply: sizeApply }));\n }\n if (hideWhenDetached) middleware.push(hideMiddleware({ strategy: 'referenceHidden' }));\n if (arrowRef) middleware.push(arrowMiddleware({ element: arrowRef }));\n\n // Alignment follows the hook's direction (not only the surface's computed CSS direction).\n const directionalPlatform = useMemo<Platform>(\n () => ({ ...platform, isRTL: () => dir === 'rtl' }),\n [dir],\n );\n\n const { refs, floatingStyles, placement, middlewareData, isPositioned, update } = useFloating({\n open,\n placement: requestedPlacement,\n strategy,\n middleware,\n platform: directionalPlatform,\n whileElementsMounted: open ? whileElementsMounted : undefined,\n });\n\n // Virtual anchors: the latest object (written in setReference, never during render) and the\n // proxy floating-ui holds for it.\n const virtualRef = useRef<VirtualElement | null>(null);\n const proxyRef = useRef<VirtualProxy | null>(null);\n const updatePosition = useEventCallback(update);\n const updateWhileOpen = useEventCallback(() => {\n if (open) update();\n });\n const { setReference: setFloatingReference, reference: floatingReference } = refs;\n const setReference = useCallback(\n (anchor: HTMLElement | VirtualElement | null) => {\n if (anchor === null || isElementAnchor(anchor)) {\n virtualRef.current = null;\n setFloatingReference(anchor);\n return;\n }\n virtualRef.current = anchor;\n let proxy = proxyRef.current;\n if (!proxy || proxy.contextElement !== anchor.contextElement) {\n proxy = createVirtualProxy(virtualRef, anchor.contextElement);\n proxyRef.current = proxy;\n }\n if (floatingReference.current === proxy) updatePosition();\n else setFloatingReference(proxy);\n },\n [setFloatingReference, floatingReference, updatePosition],\n );\n\n const [finalSide, finalAlign = 'center'] = placement.split('-') as [PhysicalSide, string?];\n\n const reportPositioned = useEventCallback((info: PositionedInfo) => onPositioned?.(info));\n useEffect(() => {\n if (open && isPositioned) {\n reportPositioned({ placement, side: finalSide, isPositioned: true });\n }\n }, [open, isPositioned, placement, finalSide, reportPositioned]);\n\n const referenceHidden = middlewareData.hide?.referenceHidden === true;\n const style = useMemo<React.CSSProperties>(() => {\n const next: React.CSSProperties = { ...floatingStyles };\n if (matchReferenceWidth) next.width = 'var(--wave-popup-reference-width)';\n if (fitViewport) {\n next.maxWidth = 'var(--wave-popup-available-width)';\n next.maxHeight = 'var(--wave-popup-available-height)';\n }\n if (referenceHidden) next.visibility = 'hidden';\n return next;\n }, [floatingStyles, matchReferenceWidth, fitViewport, referenceHidden]);\n\n const arrowX = middlewareData.arrow?.x;\n const arrowY = middlewareData.arrow?.y;\n const arrowStyles = useMemo<React.CSSProperties>(() => {\n const styles: Record<string, string> = {\n position: 'absolute',\n left: arrowX != null ? `${arrowX}px` : '',\n top: arrowY != null ? `${arrowY}px` : '',\n };\n styles[STATIC_SIDE[finalSide]] = ARROW_OFFSET;\n return styles as React.CSSProperties;\n }, [arrowX, arrowY, finalSide]);\n\n const floatingProps = useMemo(\n () => ({ 'data-side': finalSide, 'data-align': finalAlign, style }),\n [finalSide, finalAlign, style],\n );\n\n return {\n setReference,\n setFloating: refs.setFloating,\n floatingStyles: style,\n arrowStyles,\n placement,\n side: finalSide,\n isPositioned,\n update: updateWhileOpen,\n floatingProps,\n };\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
"use client";const e=require("../_virtual/_rolldown/runtime.cjs"),t=require("../lib/dev.cjs");let n=require("react");n=e.__toESM(n,1);function r(e){return typeof e==`object`&&!!e&&`current`in e}function i(e){let[t,i]=n.useState(null),a=r(e)?e:null;return n.useLayoutEffect(()=>{if(!a)return;let e=!1;return queueMicrotask(()=>{e||i(a.current)}),()=>{e=!0}}),r(e)?t:e}function a(e,r,i){let a=r!=null&&i!=null;n.useEffect(()=>{a&&t.warnOnce(`${e}:positioning-target`,`${e}: both target and positioning.target are set; target is used.`)},[e,a])}function o(e,t,n){a(e,t,n?.target);let o=t===void 0?n?.target:t,s=i(o);return{target:s,pending:r(o)&&s===null}}exports.isTargetRef=r,exports.usePopupTarget=o,exports.useResolvedTarget=i,exports.useTargetConflictWarning=a;
|
|
2
|
+
//# sourceMappingURL=useResolvedTarget.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useResolvedTarget.cjs","names":["React","require_runtime","require_dev","react","isTargetRef","target","useResolvedTarget","refElement","setRefElement","ref","cancelled","useTargetConflictWarning","conflict","positioningTarget","component","usePopupTarget","positioning","input","resolved"],"sources":["../../src/hooks/useResolvedTarget.ts"],"sourcesContent":["import * as React from 'react';\nimport type { PopupPositioning, PopupTarget, PopupTargetInput } from '../lib/types';\nimport { warnOnce } from '../lib/dev';\n\n/** Whether a `target` is a ref object rather than an element or a `VirtualElement`. */\nexport function isTargetRef(\n target: PopupTargetInput | undefined,\n): target is { readonly current: HTMLElement | null } {\n return target != null && typeof target === 'object' && 'current' in target;\n}\n\n/**\n * Internal. Turns a popup's `target` prop into a {@link PopupTarget}: an element or a\n * `VirtualElement` is returned as it is, a ref object becomes the element it holds. A ref cannot be\n * observed, so it is read once more after each commit of the popup (deferred, C-HOOKS): until then\n * the previous element is kept, and an element that attaches or detaches without the popup\n * rendering is noticed the next time the popup renders.\n */\nexport function useResolvedTarget(target: PopupTargetInput | undefined): PopupTarget | undefined {\n const [refElement, setRefElement] = React.useState<HTMLElement | null>(null);\n const ref = isTargetRef(target) ? target : null;\n React.useLayoutEffect(() => {\n if (!ref) return;\n let cancelled = false;\n queueMicrotask(() => {\n if (!cancelled) setRefElement(ref.current);\n });\n return () => {\n cancelled = true;\n };\n });\n if (isTargetRef(target)) return refElement;\n return target;\n}\n\n/**\n * Internal. Warns once (from an effect) when both `target` and `positioning.target` are set; the\n * component uses `target`.\n */\nexport function useTargetConflictWarning(\n component: string,\n target: PopupTargetInput | undefined,\n positioningTarget: PopupTargetInput | undefined,\n): void {\n const conflict = target != null && positioningTarget != null;\n React.useEffect(() => {\n if (conflict) {\n warnOnce(\n `${component}:positioning-target`,\n `${component}: both target and positioning.target are set; target is used.`,\n );\n }\n }, [component, conflict]);\n}\n\n/**\n * Internal. The `target` of a popup that also takes `positioning`: the `target` prop, else\n * `positioning.target`, resolved by {@link useResolvedTarget}. `pending` is `true` while the target\n * is a ref object that holds no element: the popup is rendered hidden, as TeachingPopover's is.\n */\nexport function usePopupTarget(\n component: string,\n target: PopupTargetInput | undefined,\n positioning: PopupPositioning | undefined,\n): { target: PopupTarget | undefined; pending: boolean } {\n useTargetConflictWarning(component, target, positioning?.target);\n const input = target !== undefined ? target : positioning?.target;\n const resolved = useResolvedTarget(input);\n // A ref object whose element is not there (yet): the popup stays hidden until it is.\n const pending = isTargetRef(input) && resolved === null;\n return { target: resolved, pending };\n}\n"],"mappings":"sIAKA,SAAgBI,EACd,EACoD,CACpD,OAAyB,OAAOC,GAAW,YAApCA,GAAgD,YAAaA,CACtE,CASA,SAAgBC,EAAkB,EAA+D,CAC/F,GAAM,CAACC,EAAYC,GAAiBR,EAAM,SAA6B,IAAI,EACrES,EAAML,EAAYC,CAAM,EAAIA,EAAS,KAY3C,OAXAF,EAAM,oBAAsB,CAC1B,GAAI,CAACM,EAAK,OACV,IAAIC,EAAY,GAIhB,OAHA,mBAAqB,CACdA,GAAWF,EAAcC,EAAI,OAAO,CAC3C,CAAC,MACY,CACX,EAAY,EACd,CACF,CAAC,EACGL,EAAYC,CAAM,EAAUE,EACzBF,CACT,CAMA,SAAgBM,EACd,EACA,EACA,EACM,CACN,IAAMC,EAAWP,GAAU,MAAQQ,GAAqB,KACxDV,EAAM,cAAgB,CAChBS,GACFV,EAAA,SACE,GAAGY,EAAU,qBACb,GAAGA,EAAU,8DACf,CAEJ,EAAG,CAACA,EAAWF,CAAQ,CAAC,CAC1B,CAOA,SAAgBG,EACd,EACA,EACA,EACuD,CACvDJ,EAAyBG,EAAWT,EAAQW,GAAa,MAAM,EAC/D,IAAMC,EAAQZ,IAAW,IAAA,GAAqBW,GAAa,OAAtBX,EAC/Ba,EAAWZ,EAAkBW,CAAK,EAGxC,MAAO,CAAE,OAAQC,EAAU,QADXd,EAAYa,CAAK,GAAKC,IAAa,IAChB,CACrC"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { warnOnce as e } from "../lib/dev.mjs";
|
|
3
|
+
import * as t from "react";
|
|
4
|
+
//#region src/hooks/useResolvedTarget.ts
|
|
5
|
+
function n(e) {
|
|
6
|
+
return typeof e == "object" && !!e && "current" in e;
|
|
7
|
+
}
|
|
8
|
+
function r(e) {
|
|
9
|
+
let [r, i] = t.useState(null), a = n(e) ? e : null;
|
|
10
|
+
return t.useLayoutEffect(() => {
|
|
11
|
+
if (!a) return;
|
|
12
|
+
let e = !1;
|
|
13
|
+
return queueMicrotask(() => {
|
|
14
|
+
e || i(a.current);
|
|
15
|
+
}), () => {
|
|
16
|
+
e = !0;
|
|
17
|
+
};
|
|
18
|
+
}), n(e) ? r : e;
|
|
19
|
+
}
|
|
20
|
+
function i(n, r, i) {
|
|
21
|
+
let a = r != null && i != null;
|
|
22
|
+
t.useEffect(() => {
|
|
23
|
+
a && e(`${n}:positioning-target`, `${n}: both target and positioning.target are set; target is used.`);
|
|
24
|
+
}, [n, a]);
|
|
25
|
+
}
|
|
26
|
+
function a(e, t, a) {
|
|
27
|
+
i(e, t, a?.target);
|
|
28
|
+
let o = t === void 0 ? a?.target : t, s = r(o);
|
|
29
|
+
return {
|
|
30
|
+
target: s,
|
|
31
|
+
pending: n(o) && s === null
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
//#endregion
|
|
35
|
+
export { n as isTargetRef, a as usePopupTarget, r as useResolvedTarget, i as useTargetConflictWarning };
|
|
36
|
+
|
|
37
|
+
//# sourceMappingURL=useResolvedTarget.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useResolvedTarget.mjs","names":["React","isTargetRef","target","useResolvedTarget","refElement","setRefElement","ref","cancelled","useTargetConflictWarning","conflict","positioningTarget","warnOnce","component","usePopupTarget","positioning","input","resolved"],"sources":["../../src/hooks/useResolvedTarget.ts"],"sourcesContent":["import * as React from 'react';\nimport type { PopupPositioning, PopupTarget, PopupTargetInput } from '../lib/types';\nimport { warnOnce } from '../lib/dev';\n\n/** Whether a `target` is a ref object rather than an element or a `VirtualElement`. */\nexport function isTargetRef(\n target: PopupTargetInput | undefined,\n): target is { readonly current: HTMLElement | null } {\n return target != null && typeof target === 'object' && 'current' in target;\n}\n\n/**\n * Internal. Turns a popup's `target` prop into a {@link PopupTarget}: an element or a\n * `VirtualElement` is returned as it is, a ref object becomes the element it holds. A ref cannot be\n * observed, so it is read once more after each commit of the popup (deferred, C-HOOKS): until then\n * the previous element is kept, and an element that attaches or detaches without the popup\n * rendering is noticed the next time the popup renders.\n */\nexport function useResolvedTarget(target: PopupTargetInput | undefined): PopupTarget | undefined {\n const [refElement, setRefElement] = React.useState<HTMLElement | null>(null);\n const ref = isTargetRef(target) ? target : null;\n React.useLayoutEffect(() => {\n if (!ref) return;\n let cancelled = false;\n queueMicrotask(() => {\n if (!cancelled) setRefElement(ref.current);\n });\n return () => {\n cancelled = true;\n };\n });\n if (isTargetRef(target)) return refElement;\n return target;\n}\n\n/**\n * Internal. Warns once (from an effect) when both `target` and `positioning.target` are set; the\n * component uses `target`.\n */\nexport function useTargetConflictWarning(\n component: string,\n target: PopupTargetInput | undefined,\n positioningTarget: PopupTargetInput | undefined,\n): void {\n const conflict = target != null && positioningTarget != null;\n React.useEffect(() => {\n if (conflict) {\n warnOnce(\n `${component}:positioning-target`,\n `${component}: both target and positioning.target are set; target is used.`,\n );\n }\n }, [component, conflict]);\n}\n\n/**\n * Internal. The `target` of a popup that also takes `positioning`: the `target` prop, else\n * `positioning.target`, resolved by {@link useResolvedTarget}. `pending` is `true` while the target\n * is a ref object that holds no element: the popup is rendered hidden, as TeachingPopover's is.\n */\nexport function usePopupTarget(\n component: string,\n target: PopupTargetInput | undefined,\n positioning: PopupPositioning | undefined,\n): { target: PopupTarget | undefined; pending: boolean } {\n useTargetConflictWarning(component, target, positioning?.target);\n const input = target !== undefined ? target : positioning?.target;\n const resolved = useResolvedTarget(input);\n // A ref object whose element is not there (yet): the popup stays hidden until it is.\n const pending = isTargetRef(input) && resolved === null;\n return { target: resolved, pending };\n}\n"],"mappings":";;;;AAKA,SAAgBC,EACd,GACoD;CACpD,OAAyB,OAAOC,KAAW,cAApCA,KAAgD,aAAaA;AACtE;AASA,SAAgBC,EAAkB,GAA+D;CAC/F,IAAM,CAACC,GAAYC,KAAiBL,EAAM,SAA6B,IAAI,GACrEM,IAAML,EAAYC,CAAM,IAAIA,IAAS;CAY3C,OAXAF,EAAM,sBAAsB;EAC1B,IAAI,CAACM,GAAK;EACV,IAAIC,IAAY;EAIhB,OAHA,qBAAqB;GACnB,AAAKA,KAAWF,EAAcC,EAAI,OAAO;EAC3C,CAAC,SACY;GACX,IAAY;EACd;CACF,CAAC,GACGL,EAAYC,CAAM,IAAUE,IACzBF;AACT;AAMA,SAAgBM,EACd,GACA,GACA,GACM;CACN,IAAMC,IAAWP,KAAU,QAAQQ,KAAqB;CACxD,EAAM,gBAAgB;EACpB,AAAID,KACFE,EACE,GAAGC,EAAU,sBACb,GAAGA,EAAU,8DACf;CAEJ,GAAG,CAACA,GAAWH,CAAQ,CAAC;AAC1B;AAOA,SAAgBI,EACd,GACA,GACA,GACuD;CACvD,EAAyBD,GAAWV,GAAQY,GAAa,MAAM;CAC/D,IAAMC,IAAQb,MAAW,KAAA,IAAqBY,GAAa,SAAtBZ,GAC/Bc,IAAWb,EAAkBY,CAAK;CAGxC,OAAO;EAAE,QAAQC;EAAU,SADXf,EAAYc,CAAK,KAAKC,MAAa;CAChB;AACrC"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use client";const e=require("../_virtual/_rolldown/runtime.cjs"),t=require("../lib/globalRegistry.cjs"),n=require("../lib/focus.cjs"),r=require("../lib/layers.cjs"),i=require("./useDismiss.cjs");let a=require("react");a=e.__toESM(a,1);var o=4,s=`[data-wave-portal]`;function c(e){return!e||!e.isConnected||!n.isFocusable(e)||e.closest(`[aria-hidden="true"]`)?!1:!r.isInsideOtherOpenModal(e)}function l(e){let t={path:[],next:[],previous:[]},n=e.ownerDocument.body;for(let r=e;r&&(t.path.push(r),t.next.push(r.nextElementSibling),t.previous.push(r.previousElementSibling),r!==n);r=r.parentElement);return t}function u(e,t){if(e.closest(`[data-wave-focus-trap-allow]`))return[];let n=r.getOpenLayers().filter(t=>r.isInsideLayerTree(t.id,e)).sort((e,t)=>r.compareLayers(t,e)),i=[];for(let r of n){let n=r.getAnchor();!n||n===e||t&&t.contains(n)||i.some(e=>e.element===n)||i.push({element:n,position:l(n)})}return i}function d(){let e=m();return e.surfaces??=new Set,e.surfaces}function f(e,t=new Set){if(t.has(e))return!1;if(t.add(e),e.isHoverClose())return!0;let n=e.getOpener();if(!n)return!1;for(let r of d()){let i=r===e?null:r.getContainer();if(i&&i.contains(n)&&f(r,t))return!0}return!1}function p(e,t){return e?f(e):t.isHoverClose?.()===!0}function m(){return t.getGlobalRegistry(`restoreFocusTracker`,()=>({users:0,last:null,uninstall:null}))}var h=1;function g(e){return!!e&&e.nodeType===h}function _(e,t){let n=t.ownerDocument;if(t===n.body||t===n.documentElement){e.last=null;return}e.last={element:t,position:l(t),anchors:u(t,null)}}function v(e){let t=e.last;if(!t||!t.element.isConnected)return;let n=u(t.element,null);for(let e of t.anchors)n.some(t=>t.element===e.element)||n.push(e);e.last={element:t.element,position:l(t.element),anchors:n}}function y(){if(typeof document>`u`)return()=>{};let e=m();if(e.users+=1,!e.uninstall){let t=document,i=t=>{g(t.target)&&_(e,t.target)},a=t=>{let r=t.target;!t.relatedTarget&&g(r)&&queueMicrotask(()=>{e.last?.element===r&&r.isConnected&&n.isFocusable(r)&&r.ownerDocument.activeElement!==r&&(e.last=null)})};t.addEventListener(`focusin`,i,!0),t.addEventListener(`focusout`,a,!0);let o=r.subscribeLayers(()=>v(e));g(t.activeElement)&&_(e,t.activeElement),e.uninstall=()=>{t.removeEventListener(`focusin`,i,!0),t.removeEventListener(`focusout`,a,!0),o(),e.last=null}}let t=!0;return()=>{t&&(t=!1,e.users=Math.max(0,e.users-1),!(e.users>0)&&(e.uninstall?.(),e.uninstall=null))}}function b(){let e=m().last;if(!e)return null;let{element:t}=e;return t.ownerDocument.activeElement===t||t.isConnected&&n.isFocusable(t)?null:e}function x(e){if(typeof document>`u`)return null;let{container:t,triggerRef:n}=e,r=e=>!!e&&e!==e.ownerDocument.body&&e!==e.ownerDocument.documentElement&&!(t&&t.contains(e)),i=n?.current,a=document.activeElement,o=null;if(r(i)?o=i:r(a)&&(o=a),o)return{element:o,position:l(o),anchors:u(o,t)};let s=b();return!s||!r(s.element)?null:{element:s.element,position:s.position,anchors:s.anchors.filter(e=>!(t&&t.contains(e.element)))}}function S(e){if(!e)return[];let t=[];for(let r of e.getElements()){if(!r)continue;t.push(r);let e=n.getFirstTabbable(r);e&&t.push(e)}return t}function C(e,t){let{ref:n,placement:r}=t;if(e===n)return r===`before`;let i=(n.compareDocumentPosition(e)&o)!==0;return r===`before`?i:i&&!n.contains(e)}function w(e){let{path:t}=e,n=t.findIndex(e=>e.isConnected);if(n===-1)return null;if(n===0){let e=t[0].parentElement;return e?{root:e,point:{ref:t[0],placement:`after`}}:null}if(t.slice(0,n).some(e=>e.matches(s)))return null;let r=t[n],i=e.next[n-1];if(i&&i.parentElement===r)return{root:r,point:{ref:i,placement:`before`}};let a=e.previous[n-1];return a&&a.parentElement===r?{root:r,point:{ref:a,placement:`after`}}:{root:r,point:{ref:r,placement:`before`}}}function T(e,t){let i=w(e);if(!i)return[];let{root:a,point:l}=i,u=a.ownerDocument.body,d=[];for(let e=a;e&&!(r.isInsideOtherOpenModal(e)||(d.push(e),e===u||e.matches(s)));e=e.parentElement);if(d.length===0)return[];let f=n.getTabbableElements(d[d.length-1]).filter(e=>!(t&&t.contains(e))&&c(e)).sort((e,t)=>(e.compareDocumentPosition(t)&o)===0?1:-1),p=[];for(let e of d){let t=f.filter(t=>e.contains(t)&&!p.includes(t)),n=t.find(e=>C(e,l)),r=t.filter(e=>!C(e,l)).pop();n&&p.push(n),r&&p.push(r)}return p}function E(e,t){if(typeof document>`u`)return!1;let n=document.activeElement,r=!n||n===document.body||n===document.documentElement;return!r&&e.container?.contains(n)?!0:!r&&e.onlyIfFocusInside?!1:!t()}function*
|
|
1
|
+
"use client";const e=require("../_virtual/_rolldown/runtime.cjs"),t=require("../lib/globalRegistry.cjs"),n=require("../lib/focus.cjs"),r=require("../lib/layers.cjs"),i=require("./useDismiss.cjs");let a=require("react");a=e.__toESM(a,1);var o=4,s=`[data-wave-portal]`;function c(e){return!e||!e.isConnected||!n.isFocusable(e)||e.closest(`[aria-hidden="true"]`)?!1:!r.isInsideOtherOpenModal(e)}function l(e){let t={path:[],next:[],previous:[]},n=e.ownerDocument.body;for(let r=e;r&&(t.path.push(r),t.next.push(r.nextElementSibling),t.previous.push(r.previousElementSibling),r!==n);r=r.parentElement);return t}function u(e,t){if(e.closest(`[data-wave-focus-trap-allow]`))return[];let n=r.getOpenLayers().filter(t=>r.isInsideLayerTree(t.id,e)).sort((e,t)=>r.compareLayers(t,e)),i=[];for(let r of n){let n=r.getAnchor();!n||n===e||t&&t.contains(n)||i.some(e=>e.element===n)||i.push({element:n,position:l(n)})}return i}function d(){let e=m();return e.surfaces??=new Set,e.surfaces}function f(e,t=new Set){if(t.has(e))return!1;if(t.add(e),e.isHoverClose())return!0;let n=e.getOpener();if(!n)return!1;for(let r of d()){let i=r===e?null:r.getContainer();if(i&&i.contains(n)&&f(r,t))return!0}return!1}function p(e,t){return e?f(e):t.isHoverClose?.()===!0}function m(){return t.getGlobalRegistry(`restoreFocusTracker`,()=>({users:0,last:null,uninstall:null}))}var h=1;function g(e){return!!e&&e.nodeType===h}function _(e,t){let n=t.ownerDocument;if(t===n.body||t===n.documentElement){e.last=null;return}e.last={element:t,position:l(t),anchors:u(t,null)}}function v(e){let t=e.last;if(!t||!t.element.isConnected)return;let n=u(t.element,null);for(let e of t.anchors)n.some(t=>t.element===e.element)||n.push(e);e.last={element:t.element,position:l(t.element),anchors:n}}function y(){if(typeof document>`u`)return()=>{};let e=m();if(e.users+=1,!e.uninstall){let t=document,i=t=>{g(t.target)&&_(e,t.target)},a=t=>{let r=t.target;!t.relatedTarget&&g(r)&&queueMicrotask(()=>{e.last?.element===r&&r.isConnected&&n.isFocusable(r)&&r.ownerDocument.activeElement!==r&&(e.last=null)})};t.addEventListener(`focusin`,i,!0),t.addEventListener(`focusout`,a,!0);let o=r.subscribeLayers(()=>v(e));g(t.activeElement)&&_(e,t.activeElement),e.uninstall=()=>{t.removeEventListener(`focusin`,i,!0),t.removeEventListener(`focusout`,a,!0),o(),e.last=null}}let t=!0;return()=>{t&&(t=!1,e.users=Math.max(0,e.users-1),!(e.users>0)&&(e.uninstall?.(),e.uninstall=null))}}function b(){let e=m().last;if(!e)return null;let{element:t}=e;return t.ownerDocument.activeElement===t||t.isConnected&&n.isFocusable(t)?null:e}function x(e){if(typeof document>`u`)return null;let{container:t,triggerRef:n}=e,r=e=>!!e&&e!==e.ownerDocument.body&&e!==e.ownerDocument.documentElement&&!(t&&t.contains(e)),i=n?.current,a=document.activeElement,o=null;if(r(i)?o=i:r(a)&&(o=a),o)return{element:o,position:l(o),anchors:u(o,t)};let s=b();return!s||!r(s.element)?null:{element:s.element,position:s.position,anchors:s.anchors.filter(e=>!(t&&t.contains(e.element)))}}function S(e){if(!e)return[];let t=[];for(let r of e.getElements()){if(!r)continue;t.push(r);let e=n.getFirstTabbable(r);e&&t.push(e)}return t}function C(e,t){let{ref:n,placement:r}=t;if(e===n)return r===`before`;let i=(n.compareDocumentPosition(e)&o)!==0;return r===`before`?i:i&&!n.contains(e)}function w(e){let{path:t}=e,n=t.findIndex(e=>e.isConnected);if(n===-1)return null;if(n===0){let e=t[0].parentElement;return e?{root:e,point:{ref:t[0],placement:`after`}}:null}if(t.slice(0,n).some(e=>e.matches(s)))return null;let r=t[n],i=e.next[n-1];if(i&&i.parentElement===r)return{root:r,point:{ref:i,placement:`before`}};let a=e.previous[n-1];return a&&a.parentElement===r?{root:r,point:{ref:a,placement:`after`}}:{root:r,point:{ref:r,placement:`before`}}}function T(e,t){let i=w(e);if(!i)return[];let{root:a,point:l}=i,u=a.ownerDocument.body,d=[];for(let e=a;e&&!(r.isInsideOtherOpenModal(e)||(d.push(e),e===u||e.matches(s)));e=e.parentElement);if(d.length===0)return[];let f=n.getTabbableElements(d[d.length-1]).filter(e=>!(t&&t.contains(e))&&c(e)).sort((e,t)=>(e.compareDocumentPosition(t)&o)===0?1:-1),p=[];for(let e of d){let t=f.filter(t=>e.contains(t)&&!p.includes(t)),n=t.find(e=>C(e,l)),r=t.filter(e=>!C(e,l)).pop();n&&p.push(n),r&&p.push(r)}return p}function E(e){if(!e)return!1;let t=b();return t?t.position.path.includes(e)?!0:t.anchors.some(t=>t.position.path.includes(e)):!1}function D(e,t,n){return!t||e.closest(`[data-wave-focus-trap-allow]`)?!1:r.getOpenLayers().some(i=>{if(i.id===n||!r.isInsideLayerTree(i.id,e))return!1;if(n!==void 0&&r.isDescendantLayer(i.id,n))return!0;let a=i.getAnchor();return!!a&&t.contains(a)})}function O(e,t){if(typeof document>`u`)return!1;let n=document.activeElement,r=!n||n===document.body||n===document.documentElement;return!r&&e.container?.contains(n)?!0:e.requireFocusInside?r?E(e.container)&&!t():D(n,e.container,e.layerId):!r&&e.onlyIfFocusInside?!1:!t()}function*k(e,t){yield*T(e.position,t);for(let t of e.anchors)yield t.element;for(let n of e.anchors)yield*T(n.position,t)}function*A(e,t){let{options:n,parentLayerId:i}=e;yield n.finalFocusRef?.current,yield t?.element,yield n.triggerRef?.current,yield n.fallback?.();let a=t?k(t,n.container):null,o=i===null?null:r.getLayer(i),s=[];if(o){for(let e of a??[])r.isInsideLayerTree(o.id,e)?yield e:s.push(e);yield*S(o),yield*s}else a&&(yield*a);yield*S(r.getTopmostLayer(e=>e.kind===`modal`))}function j(e,t){let r=e.options.container;for(let i of A(e,t))if(!(r&&i&&r.contains(i))&&c(i)&&n.focusElement(i,{preventScroll:!0}))return}function M(e){let t=a.useContext(i.DismissLayerContext),n=(0,a.useRef)({options:e,parentLayerId:t}),r=(0,a.useRef)(null),o=(0,a.useRef)(!1),s=(0,a.useRef)(!1),c=(0,a.useRef)(null),l=(0,a.useRef)(null),{enabled:u}=e;(0,a.useLayoutEffect)(()=>{let e=y(),t={isHoverClose:()=>n.current.options.isHoverClose?.()===!0,getContainer:()=>n.current.options.container??null,getOpener:()=>r.current?.element??n.current.options.triggerRef?.current??null};l.current=t;let i=d();return i.add(t),()=>{e(),queueMicrotask(()=>i.delete(t))}},[]),(0,a.useInsertionEffect)(()=>{n.current={options:e,parentLayerId:t};let i=o.current;o.current=e.enabled,e.enabled&&!i&&(r.current=x(e))}),(0,a.useLayoutEffect)(()=>{let e=s.current;if(s.current=u,u&&!e&&!r.current&&(r.current=x(n.current.options)),!e||u)return;let t=n.current,i=r.current,a=l.current,o=O(t.options,()=>p(a,t.options));r.current=null,o&&j(t,i)},[u]),(0,a.useLayoutEffect)(()=>{let e=n,t=r,i=c,a=l;return i.current=null,()=>{let n=e.current;if(!n.options.enabled)return;let r=a.current;if(!O(n.options,()=>p(r,n.options)))return;let o={};i.current=o;let s=t.current;queueMicrotask(()=>{if(i.current!==o)return;i.current=null;let e=typeof document>`u`?null:document.activeElement,t=n.options.container;(!e||e===document.body||e===document.documentElement||t&&t.contains(e))&&j(n,s)})}},[])}exports.useRestoreFocus=M;
|
|
2
2
|
//# sourceMappingURL=useRestoreFocus.cjs.map
|