{"version":3,"file":"usePopupFocus.mjs","sources":["../../../packages/popup-menu/usePopupFocus.ts"],"sourcesContent":["import {\n  KeyboardEvent,\n  KeyboardEventHandler,\n  MouseEventHandler,\n  RefObject,\n  useCallback,\n  useRef,\n} from 'react'\nimport { useInterceptFocus } from '../hooks/index.js'\nimport { FOCUSABLE_ELEMENTS } from './constants.js'\nimport { PopupMenuProps } from './types.js'\n\nexport const usePopupFocus = <T extends HTMLDivElement>({\n  onMouseMove,\n  onKeyDown,\n}: Pick<PopupMenuProps, 'onMouseMove' | 'onKeyDown'>): {\n  ref: RefObject<T>\n  handleMouseMove: MouseEventHandler<T>\n  handleKeyDown: KeyboardEventHandler<T>\n  handleEnter: () => void\n  handleExit: () => void\n} => {\n  const ref = useRef<T>(null)\n\n  const getFocusableNodes = useCallback(() => {\n    const nodes =\n      ref.current?.querySelectorAll(FOCUSABLE_ELEMENTS.join(',')) ?? []\n\n    return Array.from(nodes).filter(\n      (node): node is HTMLElement =>\n        node && node instanceof HTMLElement && node.offsetParent !== null,\n    )\n  }, [])\n\n  const handleFocusTo = useCallback(\n    (event: KeyboardEvent<T>, offset = 1) => {\n      const focusableNodes = getFocusableNodes()\n\n      if (focusableNodes.length === 0) return\n\n      const currentElement = document.activeElement\n      const focusedItemIndex =\n        currentElement instanceof HTMLElement\n          ? focusableNodes.indexOf(currentElement)\n          : -1\n\n      const activeItemIndex = focusableNodes.findIndex(\n        (node) => node.getAttribute('aria-selected') === 'true',\n      )\n\n      const currentIndex =\n        focusedItemIndex === -1 ? activeItemIndex : focusedItemIndex\n\n      let nextIndex = currentIndex + offset\n      if (nextIndex < 0) nextIndex = focusableNodes.length - 1\n      if (nextIndex >= focusableNodes.length) nextIndex = 0\n\n      focusableNodes[nextIndex].focus()\n      event.preventDefault()\n    },\n    [getFocusableNodes],\n  )\n\n  const handleMouseMove: MouseEventHandler<T> = useCallback(\n    (event) => {\n      onMouseMove?.(event)\n\n      const { target } = event\n      if (!(target instanceof HTMLElement)) return\n\n      const focusableNodes = getFocusableNodes()\n      const overed = target.closest(FOCUSABLE_ELEMENTS.join(','))\n\n      if (!(overed instanceof HTMLElement)) return\n\n      const isNotFocusable = !focusableNodes.includes(overed)\n      const isActive = overed === document.activeElement\n\n      if (isActive || isNotFocusable) return\n\n      overed.focus()\n    },\n    [getFocusableNodes, onMouseMove],\n  )\n\n  const handleKeyDown: KeyboardEventHandler<T> = useCallback(\n    (event) => {\n      onKeyDown?.(event)\n      const code = event.code ?? event.key\n\n      if (code === 'Tab') event.preventDefault()\n      if (code === 'ArrowDown') handleFocusTo(event, +1)\n      if (code === 'ArrowUp') handleFocusTo(event, -1)\n    },\n    [handleFocusTo, onKeyDown],\n  )\n\n  const [interceptFocus, restoreFocus] = useInterceptFocus()\n\n  const handleEnter = useCallback(() => {\n    if (ref.current) interceptFocus(ref.current)\n  }, [interceptFocus])\n\n  const handleExit = useCallback(() => {\n    restoreFocus()\n  }, [restoreFocus])\n\n  return {\n    ref,\n    handleMouseMove,\n    handleKeyDown,\n    handleEnter,\n    handleExit,\n  }\n}\n"],"names":["usePopupFocus","_ref","onMouseMove","onKeyDown","ref","useRef","getFocusableNodes","useCallback","nodes","current","querySelectorAll","FOCUSABLE_ELEMENTS","join","Array","from","filter","node","HTMLElement","offsetParent","handleFocusTo","event","offset","arguments","length","undefined","focusableNodes","currentElement","document","activeElement","focusedItemIndex","indexOf","activeItemIndex","findIndex","getAttribute","currentIndex","nextIndex","focus","preventDefault","handleMouseMove","target","overed","closest","isNotFocusable","includes","isActive","handleKeyDown","code","key","interceptFocus","restoreFocus","useInterceptFocus","handleEnter","handleExit"],"mappings":";;;;;;;;;;;;;;;AAYaA,MAAAA,aAAa,GAAGC,IAAA,IASxB;EAAA,IATmD;IACtDC,WAAW;AACXC,IAAAA,SAAAA;AACiD,GAAC,GAAAF,IAAA,CAAA;AAOlD,EAAA,MAAMG,GAAG,GAAGC,MAAM,CAAI,IAAI,CAAC,CAAA;AAE3B,EAAA,MAAMC,iBAAiB,GAAGC,WAAW,CAAC,MAAM;AAC1C,IAAA,MAAMC,KAAK,GACTJ,GAAG,CAACK,OAAO,EAAEC,gBAAgB,CAACC,kBAAkB,CAACC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,CAAA;IAEnE,OAAOC,KAAK,CAACC,IAAI,CAACN,KAAK,CAAC,CAACO,MAAM,CAC5BC,IAAI,IACHA,IAAI,IAAIA,IAAI,YAAYC,WAAW,IAAID,IAAI,CAACE,YAAY,KAAK,IACjE,CAAC,CAAA;GACF,EAAE,EAAE,CAAC,CAAA;AAEN,EAAA,MAAMC,aAAa,GAAGZ,WAAW,CAC/B,UAACa,KAAuB,EAAiB;AAAA,IAAA,IAAfC,MAAM,GAAAC,SAAA,CAAAC,MAAA,GAAA,CAAA,IAAAD,SAAA,CAAA,CAAA,CAAA,KAAAE,SAAA,GAAAF,SAAA,CAAA,CAAA,CAAA,GAAG,CAAC,CAAA;AAClC,IAAA,MAAMG,cAAc,GAAGnB,iBAAiB,EAAE,CAAA;AAE1C,IAAA,IAAImB,cAAc,CAACF,MAAM,KAAK,CAAC,EAAE,OAAA;AAEjC,IAAA,MAAMG,cAAc,GAAGC,QAAQ,CAACC,aAAa,CAAA;AAC7C,IAAA,MAAMC,gBAAgB,GACpBH,cAAc,YAAYT,WAAW,GACjCQ,cAAc,CAACK,OAAO,CAACJ,cAAc,CAAC,GACtC,CAAC,CAAC,CAAA;AAER,IAAA,MAAMK,eAAe,GAAGN,cAAc,CAACO,SAAS,CAC7ChB,IAAI,IAAKA,IAAI,CAACiB,YAAY,CAAC,eAAe,CAAC,KAAK,MACnD,CAAC,CAAA;IAED,MAAMC,YAAY,GAChBL,gBAAgB,KAAK,CAAC,CAAC,GAAGE,eAAe,GAAGF,gBAAgB,CAAA;AAE9D,IAAA,IAAIM,SAAS,GAAGD,YAAY,GAAGb,MAAM,CAAA;IACrC,IAAIc,SAAS,GAAG,CAAC,EAAEA,SAAS,GAAGV,cAAc,CAACF,MAAM,GAAG,CAAC,CAAA;IACxD,IAAIY,SAAS,IAAIV,cAAc,CAACF,MAAM,EAAEY,SAAS,GAAG,CAAC,CAAA;AAErDV,IAAAA,cAAc,CAACU,SAAS,CAAC,CAACC,KAAK,EAAE,CAAA;IACjChB,KAAK,CAACiB,cAAc,EAAE,CAAA;AACxB,GAAC,EACD,CAAC/B,iBAAiB,CACpB,CAAC,CAAA;AAED,EAAA,MAAMgC,eAAqC,GAAG/B,WAAW,CACtDa,KAAK,IAAK;IACTlB,WAAW,GAAGkB,KAAK,CAAC,CAAA;IAEpB,MAAM;AAAEmB,MAAAA,MAAAA;AAAO,KAAC,GAAGnB,KAAK,CAAA;AACxB,IAAA,IAAI,EAAEmB,MAAM,YAAYtB,WAAW,CAAC,EAAE,OAAA;AAEtC,IAAA,MAAMQ,cAAc,GAAGnB,iBAAiB,EAAE,CAAA;AAC1C,IAAA,MAAMkC,MAAM,GAAGD,MAAM,CAACE,OAAO,CAAC9B,kBAAkB,CAACC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAA;AAE3D,IAAA,IAAI,EAAE4B,MAAM,YAAYvB,WAAW,CAAC,EAAE,OAAA;IAEtC,MAAMyB,cAAc,GAAG,CAACjB,cAAc,CAACkB,QAAQ,CAACH,MAAM,CAAC,CAAA;AACvD,IAAA,MAAMI,QAAQ,GAAGJ,MAAM,KAAKb,QAAQ,CAACC,aAAa,CAAA;IAElD,IAAIgB,QAAQ,IAAIF,cAAc,EAAE,OAAA;IAEhCF,MAAM,CAACJ,KAAK,EAAE,CAAA;AAChB,GAAC,EACD,CAAC9B,iBAAiB,EAAEJ,WAAW,CACjC,CAAC,CAAA;AAED,EAAA,MAAM2C,aAAsC,GAAGtC,WAAW,CACvDa,KAAK,IAAK;IACTjB,SAAS,GAAGiB,KAAK,CAAC,CAAA;IAClB,MAAM0B,IAAI,GAAG1B,KAAK,CAAC0B,IAAI,IAAI1B,KAAK,CAAC2B,GAAG,CAAA;IAEpC,IAAID,IAAI,KAAK,KAAK,EAAE1B,KAAK,CAACiB,cAAc,EAAE,CAAA;IAC1C,IAAIS,IAAI,KAAK,WAAW,EAAE3B,aAAa,CAACC,KAAK,EAAE,CAAC,CAAC,CAAC,CAAA;IAClD,IAAI0B,IAAI,KAAK,SAAS,EAAE3B,aAAa,CAACC,KAAK,EAAE,CAAC,CAAC,CAAC,CAAA;AAClD,GAAC,EACD,CAACD,aAAa,EAAEhB,SAAS,CAC3B,CAAC,CAAA;EAED,MAAM,CAAC6C,cAAc,EAAEC,YAAY,CAAC,GAAGC,iBAAiB,EAAE,CAAA;AAE1D,EAAA,MAAMC,WAAW,GAAG5C,WAAW,CAAC,MAAM;IACpC,IAAIH,GAAG,CAACK,OAAO,EAAEuC,cAAc,CAAC5C,GAAG,CAACK,OAAO,CAAC,CAAA;AAC9C,GAAC,EAAE,CAACuC,cAAc,CAAC,CAAC,CAAA;AAEpB,EAAA,MAAMI,UAAU,GAAG7C,WAAW,CAAC,MAAM;AACnC0C,IAAAA,YAAY,EAAE,CAAA;AAChB,GAAC,EAAE,CAACA,YAAY,CAAC,CAAC,CAAA;EAElB,OAAO;IACL7C,GAAG;IACHkC,eAAe;IACfO,aAAa;IACbM,WAAW;AACXC,IAAAA,UAAAA;GACD,CAAA;AACH;;;;"}