{"version":3,"file":"useRepopOnFarTriggerSwitch.mjs","names":[],"sources":["../../src/utils/useRepopOnFarTriggerSwitch.ts"],"sourcesContent":["import { useLayoutEffect, useRef, useState } from 'react';\n\ntype PopupStoreLike = {\n  state: {\n    activeTriggerElement?: Element | null;\n    open?: boolean;\n    popupElement?: HTMLElement | null;\n  };\n  useState?: (...args: any[]) => unknown;\n};\n\nexport const FAR_TRIGGER_SWITCH_THRESHOLD = 280;\n\nconst REPOP_ANIMATION: [Keyframe[], KeyframeAnimationOptions] = [\n  [\n    { opacity: 0, scale: 0.97 },\n    { opacity: 1, scale: 1 },\n  ],\n  { duration: 200, easing: 'cubic-bezier(0.33, 1, 0.68, 1)' },\n];\n\nconst centerOf = (el: Element) => {\n  const rect = el.getBoundingClientRect();\n  return { x: rect.left + rect.width / 2, y: rect.top + rect.height / 2 };\n};\n\nconst prefersReducedMotion = () =>\n  typeof window !== 'undefined' &&\n  typeof window.matchMedia === 'function' &&\n  window.matchMedia('(prefers-reduced-motion: reduce)').matches;\n\n// A morph across a long distance reads as a stray box flying over the page, so past `threshold`\n// the switch is made instant and the popup re-plays a short enter animation at the new anchor.\nexport const useRepopOnFarTriggerSwitch = (\n  store: PopupStoreLike,\n  options?: { enabled?: boolean; threshold?: number },\n): boolean => {\n  const enabled = options?.enabled ?? true;\n  const threshold = options?.threshold ?? FAR_TRIGGER_SWITCH_THRESHOLD;\n\n  const activeTrigger =\n    (store.useState?.('activeTriggerElement') as Element | null | undefined) ??\n    store.state.activeTriggerElement ??\n    null;\n  const open = (store.useState?.('open') as boolean | undefined) ?? Boolean(store.state.open);\n  const popupElement =\n    (store.useState?.('popupElement') as HTMLElement | null | undefined) ??\n    store.state.popupElement ??\n    null;\n\n  const lastRef = useRef<{ center: { x: number; y: number } | null; el: Element | null }>({\n    center: null,\n    el: null,\n  });\n  const [repop, setRepop] = useState(false);\n\n  useLayoutEffect(() => {\n    if (!open || !enabled) {\n      lastRef.current = { center: null, el: null };\n      setRepop(false);\n      return;\n    }\n    const last = lastRef.current;\n    if (activeTrigger === last.el) return;\n\n    const center = activeTrigger ? centerOf(activeTrigger) : null;\n    const far = Boolean(\n      last.el &&\n      last.center &&\n      center &&\n      Math.hypot(center.x - last.center.x, center.y - last.center.y) > threshold,\n    );\n    lastRef.current = { center, el: activeTrigger };\n    setRepop(far);\n\n    if (far && popupElement && !prefersReducedMotion()) {\n      popupElement.animate?.(...REPOP_ANIMATION);\n    }\n  }, [activeTrigger, enabled, open, popupElement, threshold]);\n\n  return repop;\n};\n"],"mappings":";AAaA,MAAM,kBAA0D,CAC9D,CACE;CAAE,SAAS;CAAG,OAAO;AAAK,GAC1B;CAAE,SAAS;CAAG,OAAO;AAAE,CACzB,GACA;CAAE,UAAU;CAAK,QAAQ;AAAiC,CAC5D;AAEA,MAAM,YAAY,OAAgB;CAChC,MAAM,OAAO,GAAG,sBAAsB;CACtC,OAAO;EAAE,GAAG,KAAK,OAAO,KAAK,QAAQ;EAAG,GAAG,KAAK,MAAM,KAAK,SAAS;CAAE;AACxE;AAEA,MAAM,6BACJ,OAAO,WAAW,eAClB,OAAO,OAAO,eAAe,cAC7B,OAAO,WAAW,kCAAkC,CAAC,CAAC;AAIxD,MAAa,8BACX,OACA,YACY;CACZ,MAAM,UAAU,SAAS,WAAW;CACpC,MAAM,YAAY,SAAS,aAAA;CAE3B,MAAM,gBACH,MAAM,WAAW,sBAAsB,KACxC,MAAM,MAAM,wBACZ;CACF,MAAM,OAAQ,MAAM,WAAW,MAAM,KAA6B,QAAQ,MAAM,MAAM,IAAI;CAC1F,MAAM,eACH,MAAM,WAAW,cAAc,KAChC,MAAM,MAAM,gBACZ;CAEF,MAAM,UAAU,OAAwE;EACtF,QAAQ;EACR,IAAI;CACN,CAAC;CACD,MAAM,CAAC,OAAO,YAAY,SAAS,KAAK;CAExC,sBAAsB;EACpB,IAAI,CAAC,QAAQ,CAAC,SAAS;GACrB,QAAQ,UAAU;IAAE,QAAQ;IAAM,IAAI;GAAK;GAC3C,SAAS,KAAK;GACd;EACF;EACA,MAAM,OAAO,QAAQ;EACrB,IAAI,kBAAkB,KAAK,IAAI;EAE/B,MAAM,SAAS,gBAAgB,SAAS,aAAa,IAAI;EACzD,MAAM,MAAM,QACV,KAAK,MACL,KAAK,UACL,UACA,KAAK,MAAM,OAAO,IAAI,KAAK,OAAO,GAAG,OAAO,IAAI,KAAK,OAAO,CAAC,IAAI,SACnE;EACA,QAAQ,UAAU;GAAE;GAAQ,IAAI;EAAc;EAC9C,SAAS,GAAG;EAEZ,IAAI,OAAO,gBAAgB,CAAC,qBAAqB,GAC/C,aAAa,UAAU,GAAG,eAAe;CAE7C,GAAG;EAAC;EAAe;EAAS;EAAM;EAAc;CAAS,CAAC;CAE1D,OAAO;AACT"}