{"version":3,"file":"usePopoverPosition.mjs","names":[],"sources":["../../../../package/common/popover/usePopoverPosition.ts"],"sourcesContent":["import { useId, useRef, type RefObject } from 'react';\nimport { isHiddenByAnyAncestor } from 'components/common/utils/scrollAncestors';\nimport { getVisualViewportRect } from 'components/common/utils/visualViewport';\nimport { useAnchorTracking } from '../hooks/useAnchorTracking';\nimport { PopoverPlacement, PopoverAlign } from './popover.types';\n\ntype Axis = 'top' | 'bottom' | 'left' | 'right';\nconst OPPOSITE: Record<PopoverPlacement, Axis> = {\n  [PopoverPlacement.Top]: 'bottom',\n  [PopoverPlacement.Bottom]: 'top',\n  [PopoverPlacement.Left]: 'right',\n  [PopoverPlacement.Right]: 'left',\n};\n\nconst MARGIN = 8; // viewport gutter kept clear when shifting a panel back on-screen\n\n/**\n * Narrower than this and `shrinkToFit` gives up: a panel this size reads worse than\n * one that overhangs. Around four words a line for an error bubble, which is the\n * narrowest caller. A constant rather than an option, because the one caller that\n * shrinks has no reason to want a different floor; give it one the day a second\n * caller disagrees, as `shrinkToFit: boolean | number`.\n */\nconst MIN_SHRINK_WIDTH = 160;\n\n/** How far down to look for a box when the wrappers in between have none. */\nconst MAX_ANCHOR_DEPTH = 3;\n\n/**\n * The element to anchor to. A trigger with a box of its own is that element, which\n * is the case for a caller that hands over a real element (`Tooltip`).\n *\n * Popover's own trigger wrapper generates no box, deliberately, so that the\n * trigger keeps the place it would have had without Popover around it. Then the\n * real trigger is inside it, and this descends to find it, past any further\n * boxless element a consumer wrapped its trigger in: such an element has a zero\n * rect at the origin, which would otherwise send the panel to the top-left corner\n * of the screen.\n */\nfunction resolveAnchor(trigger: HTMLElement): { element: HTMLElement | null; rect: DOMRect } {\n  let el: HTMLElement = trigger;\n  for (let depth = 0; depth <= MAX_ANCHOR_DEPTH; depth++) {\n    const rect = el.getBoundingClientRect();\n    if (rect.width > 0 || rect.height > 0) return { element: el, rect };\n    const child = el.firstElementChild as HTMLElement | null;\n    if (!child) break;\n    el = child;\n  }\n  return { element: null, rect: trigger.getBoundingClientRect() };\n}\n\nlet anchorSupport: boolean | undefined;\n\n// Probed, not just parsed: Firefox 155 resolves `anchor()` without the anchor's transforms, which\n// put a Dropdown in a VirtualList row, placed by `translateY`, above the list.\nexport function supportsAnchoring(): boolean {\n  if (anchorSupport !== undefined) return anchorSupport;\n  if (typeof CSS === 'undefined' || !CSS.supports?.('top: anchor(top, 0px)')) return (anchorSupport = false);\n  const host = document.createElement('div');\n  host.style.cssText = 'position: fixed; top: 0; left: 0; transform: translateY(100px); visibility: hidden';\n  const anchor = document.createElement('div');\n  anchor.style.cssText = 'anchor-name: --popover-probe; width: 1px; height: 1px';\n  const probe = document.createElement('div');\n  probe.style.cssText =\n    'position: fixed; position-anchor: --popover-probe; top: anchor(top, 0px); left: 0; visibility: hidden';\n  host.append(anchor);\n  document.body.append(host, probe);\n  anchorSupport = Math.abs(probe.getBoundingClientRect().top - anchor.getBoundingClientRect().top) < 1;\n  host.remove();\n  probe.remove();\n  return anchorSupport;\n}\n\nfunction anchorNames(el: HTMLElement): string[] {\n  return el.style\n    .getPropertyValue('anchor-name')\n    .split(',')\n    .map((name) => name.trim())\n    .filter((name) => name && name !== 'none');\n}\n\n// Merged, not replaced: one trigger can carry a Tooltip and a Popover at once.\nfunction addAnchorName(el: HTMLElement, name: string) {\n  const names = anchorNames(el);\n  if (!names.includes(name)) el.style.setProperty('anchor-name', [...names, name].join(', '));\n}\n\nfunction removeAnchorName(el: HTMLElement, name: string) {\n  const names = anchorNames(el).filter((n) => n !== name);\n  if (names.length > 0) el.style.setProperty('anchor-name', names.join(', '));\n  else el.style.removeProperty('anchor-name');\n}\n\nconst MOVING_PROPERTIES = ['transform', 'translate', 'scale', 'rotate'];\n\n/**\n * Longer than this left to run and the panel shows anyway, mid-way, and is corrected when the\n * animation ends. A Modal or Drawer entrance is well under it; waiting out a long one read as\n * the panel not opening at all.\n */\nconst MAX_WAIT_MS = 1000;\n\n/** The running animations and transitions on ancestors of `trigger` that move it. */\nfunction animationsMoving(trigger: HTMLElement): Animation[] {\n  return (document.getAnimations?.() ?? []).filter((animation) => {\n    if (animation.playState !== 'running' || !(animation.effect instanceof KeyframeEffect)) return false;\n    const { target, pseudoElement } = animation.effect;\n    // A `::before` or `::after` is a box of its own: its transform moves nothing else.\n    if (!target || pseudoElement || target === trigger || !target.contains(trigger)) return false;\n    // Covers one that never ends, which would keep the panel hidden for good.\n    const { endTime, localTime } = animation.effect.getComputedTiming();\n    if (Number(endTime) - Number(localTime) > MAX_WAIT_MS) return false;\n    return animation.effect.getKeyframes().some((frame) => MOVING_PROPERTIES.some((property) => property in frame));\n  });\n}\n\n// Anchored, the browser moves the panel with the scroll in the same frame; the scroll listener\n// lands a frame or more later. The pixel fallback covers an anchor the browser refuses.\nfunction inset(side: 'top' | 'left', value: number, anchorEdge: number, anchored: boolean): string {\n  if (!anchored) return `${value}px`;\n  return `calc(anchor(${side}, ${anchorEdge}px) + ${value - anchorEdge}px)`;\n}\n\nexport interface UsePopoverPositionArgs {\n  isOpen: boolean;\n  placement: PopoverPlacement;\n  align: PopoverAlign;\n  offset: number;\n  triggerRef: RefObject<HTMLElement | null>;\n  /** `position: fixed` wrapper that receives top/left/visibility and the resolved-placement data attribute. */\n  floatingRef: RefObject<HTMLElement | null>;\n  /** Visible panel, measured to decide flip and shift. */\n  panelRef: RefObject<HTMLElement | null>;\n  /** Arrow element; gets `--arrow-x` / `--arrow-y` written to it. Pass a null ref when `withArrow` is false. */\n  arrowRef: RefObject<HTMLElement | null>;\n  /**\n   * Give the panel at least the trigger's width, for a list that lines up with\n   * the field it belongs to. A minimum rather than a fixed width: a menu on a\n   * narrow icon button still sizes to its own content.\n   */\n  matchTriggerWidth?: boolean;\n  /**\n   * When the panel does not fit on the side its alignment puts it, narrow it\n   * rather than sliding it away from the trigger. Sliding keeps the panel\n   * on-screen but detaches it: an end-aligned bubble stops ending where its\n   * trigger ends, and its arrow stops pointing at anything. Off by default, since\n   * a panel whose width is its content, a menu or a list, would rather overhang\n   * its trigger than wrap.\n   *\n   * Only down to `MIN_SHRINK_WIDTH`. Past that the panel is narrower than it is\n   * readable, and a trigger that close to the screen edge is better served by a\n   * panel that overhangs it.\n   */\n  shrinkToFit?: boolean;\n  /**\n   * Called when a newly opened panel first becomes visible. Focus has to wait for it: a panel\n   * still hidden, waiting out an ancestor's animation, takes none.\n   */\n  onShown?: () => void;\n}\n\n/**\n * Positions a portaled, `position: fixed` popover on any of the four sides of its trigger with\n * start/center/end cross-axis alignment. Flips to the opposite side when the preferred one has no\n * room, shifts back on-screen along the cross axis, points the arrow at the trigger centre, and\n * hides (not closes) the panel once the trigger scrolls behind a clipping ancestor.\n *\n * `useAnchorTracking` supplies the lifecycle around this: mount wait, ancestor resolution, and\n * re-running on scroll, viewport resize and panel size changes.\n */\nexport function usePopoverPosition({\n  isOpen,\n  placement,\n  align,\n  offset,\n  triggerRef,\n  floatingRef,\n  panelRef,\n  arrowRef,\n  matchTriggerWidth = false,\n  shrinkToFit = false,\n  onShown,\n}: UsePopoverPositionArgs) {\n  const anchorName = `--popover-${useId().replace(/[^\\w-]/g, '')}`;\n  const anchorRef = useRef<HTMLElement | null>(null);\n  const shownPanelRef = useRef<HTMLElement | null>(null);\n  // Every update before the first show finds the same animations again; one rerun each is enough.\n  // Keyed on `rerun`, since a restarted tracking brings a new one that has to be called too.\n  const awaitedRef = useRef(new WeakMap<Animation, () => void>());\n\n  function setAnchor(next: HTMLElement | null) {\n    if (anchorRef.current === next) return;\n    if (anchorRef.current) removeAnchorName(anchorRef.current, anchorName);\n    if (next) addAnchorName(next, anchorName);\n    anchorRef.current = next;\n  }\n\n  useAnchorTracking({\n    isOpen,\n    triggerRef,\n    elementRefs: [floatingRef, panelRef],\n    // The panel's own size feeds the flip decision and, on the `top`/`left` sides, the coordinate\n    // itself — so content that resizes while open has to be re-measured.\n    resizeRefs: [panelRef],\n    deps: [placement, align, offset, floatingRef, panelRef, arrowRef, matchTriggerWidth, shrinkToFit],\n\n    update: (trigger, ancestors, rerun) => {\n      const floating = floatingRef.current;\n      const panel = panelRef.current;\n      if (!floating || !panel) return;\n\n      const { element: anchorElement, rect: t } = resolveAnchor(trigger);\n      const anchored = anchorElement !== null && supportsAnchoring();\n      setAnchor(anchored ? anchorElement : null);\n      if (anchored) floating.style.setProperty('position-anchor', anchorName);\n      else floating.style.removeProperty('position-anchor');\n      // Written before the panel is measured, so `pw` below already accounts for it,\n      // and taken back off when it is no longer wanted: the panel outlives the\n      // switch, and an inline width would outrank whatever it switched to.\n      if (matchTriggerWidth) panel.style.minWidth = `${t.width}px`;\n      else panel.style.removeProperty('min-width');\n      // The wrapper's box, not the panel's: `offsetWidth` rounds to whole pixels, so\n      // aligning a panel 165.4px wide against a trigger edge at 406.47 left it 0.4px\n      // past that edge. The panel's own rect is fractional but carries the entrance\n      // animation's scale; the wrapper is the same layout box without the transform.\n      // Cleared before measuring, or a cap left over from a narrower screen would be\n      // read back as the panel's own width and never widen again.\n      if (shrinkToFit) panel.style.removeProperty('max-width');\n      let { width: pw, height: ph } = floating.getBoundingClientRect();\n      // The visible area, not the full layout viewport — shrinks on mobile when a keyboard is\n      // open, so the panel flips/clamps against what's actually on screen instead of ending up\n      // hidden behind the keyboard.\n      const vv = getVisualViewportRect();\n\n      // Flipping only swaps a side for its opposite, so which axis the alignment runs\n      // along is decided by the preferred placement alone, before any of that.\n      const alignsHorizontally = placement === PopoverPlacement.Top || placement === PopoverPlacement.Bottom;\n\n      if (shrinkToFit && alignsHorizontally) {\n        const alignedSide =\n          align === PopoverAlign.End\n            ? t.right - (vv.left + MARGIN)\n            : align === PopoverAlign.Start\n              ? vv.left + vv.width - MARGIN - t.left\n              : vv.width - 2 * MARGIN;\n        const room = Math.min(alignedSide, vv.width - 2 * MARGIN);\n        if (pw > room && room >= MIN_SHRINK_WIDTH) {\n          panel.style.maxWidth = `${room}px`;\n          // Wrapping makes it taller, and the height is what the flip below is decided on.\n          ({ width: pw, height: ph } = floating.getBoundingClientRect());\n        }\n      }\n\n      // Resolve the main-axis side, flipping when the preferred side lacks room and the\n      // opposite side has more.\n      const room: Record<Axis, number> = {\n        top: t.top - vv.top,\n        bottom: vv.top + vv.height - t.bottom,\n        left: t.left - vv.left,\n        right: vv.left + vv.width - t.right,\n      };\n      const need = placement === PopoverPlacement.Top || placement === PopoverPlacement.Bottom ? ph : pw;\n      let side: Axis = placement as unknown as Axis;\n      const opp = OPPOSITE[placement];\n      if (room[side] < need + offset && room[opp] > room[side]) side = opp;\n\n      const vertical = side === 'top' || side === 'bottom';\n\n      // Main axis: place the panel just outside the trigger on the resolved side.\n      let top: number;\n      let left: number;\n      if (side === 'bottom') {\n        top = t.bottom + offset;\n      } else if (side === 'top') {\n        top = t.top - offset - ph;\n      } else if (side === 'right') {\n        left = t.right + offset;\n      } else {\n        left = t.left - offset - pw;\n      }\n\n      // Cross axis: align start/center/end against the trigger, then shift on-screen.\n      let shiftedX = false;\n      let shiftedY = false;\n      if (vertical) {\n        if (align === PopoverAlign.Start) left = t.left;\n        else if (align === PopoverAlign.End) left = t.right - pw;\n        else left = t.left + t.width / 2 - pw / 2;\n        const clamped = Math.max(vv.left + MARGIN, Math.min(left!, vv.left + vv.width - pw - MARGIN));\n        shiftedX = clamped !== left!;\n        left = clamped;\n      } else {\n        if (align === PopoverAlign.Start) top = t.top;\n        else if (align === PopoverAlign.End) top = t.bottom - ph;\n        else top = t.top + t.height / 2 - ph / 2;\n        const clamped = Math.max(vv.top + MARGIN, Math.min(top!, vv.top + vv.height - ph - MARGIN));\n        shiftedY = clamped !== top!;\n        top = clamped;\n      }\n\n      // A shifted axis is pinned to the viewport edge, so it stays in pixels: anchored, the scroll\n      // would carry it off the edge until the next update pulled it back, which reads as shaking.\n      floating.style.top = inset('top', top!, t.top, anchored && !shiftedY);\n      floating.style.left = inset('left', left!, t.left, anchored && !shiftedX);\n      // Until first shown, it waits out an ancestor that is still moving the trigger, such as a\n      // Modal scaling in: placed mid-way, it showed away from the trigger and jumped at the end.\n      // Awaited through `finished`, since a Web Animation fires no `animationend`; a cancelled\n      // one stops moving the trigger too.\n      const firstShow = shownPanelRef.current !== panel;\n      const moving = firstShow ? animationsMoving(trigger) : [];\n      moving.forEach((animation) => {\n        if (awaitedRef.current.get(animation) === rerun) return;\n        awaitedRef.current.set(animation, rerun);\n        animation.finished.then(rerun, rerun);\n      });\n      const hidden = isHiddenByAnyAncestor(t, ancestors) || moving.length > 0;\n      floating.style.visibility = hidden ? 'hidden' : 'visible';\n      // The entrance animation starts on mount, so a panel first placed hidden played it unseen.\n      // Per panel, since a new one mounts on every open.\n      if (!hidden && firstShow) {\n        shownPanelRef.current = panel;\n        panel.getAnimations?.().forEach((animation) => {\n          animation.currentTime = 0;\n        });\n        onShown?.();\n      }\n      floating.dataset.placement = side;\n\n      // Arrow: centre it on the trigger along the cross axis, clamped inside the panel edges.\n      const arrow = arrowRef.current;\n      if (arrow) {\n        const half = arrow.offsetWidth / 2 || 5;\n        if (vertical) {\n          const x = t.left + t.width / 2 - left!;\n          arrow.style.setProperty('--arrow-x', `${Math.max(half + 2, Math.min(x, pw - half - 2))}px`);\n          arrow.style.removeProperty('--arrow-y');\n        } else {\n          const y = t.top + t.height / 2 - top!;\n          arrow.style.setProperty('--arrow-y', `${Math.max(half + 2, Math.min(y, ph - half - 2))}px`);\n          arrow.style.removeProperty('--arrow-x');\n        }\n      }\n    },\n\n    teardown: () => {\n      // Positioning is written as inline styles, which outrank any class the panel might\n      // switch to while it stays mounted — a popover turning into a bottom sheet (`useSheet`)\n      // would keep the coordinates computed for its anchored self.\n      setAnchor(null);\n      const floating = floatingRef.current;\n      if (!floating) return;\n      floating.style.top = '';\n      floating.style.left = '';\n      floating.style.visibility = '';\n      floating.style.removeProperty('position-anchor');\n      const panel = panelRef.current;\n      panel?.style.removeProperty('min-width');\n      panel?.style.removeProperty('max-width');\n    },\n  });\n}\n"],"mappings":"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"}