{"version":3,"file":"useTrapFocus-DXSX2lWD.cjs","sources":["../../src/composables/useTrapFocus.ts"],"sourcesContent":["/*****************************\n * vue v-trap-focus directive\n *****************************/\n\nimport type { DirectiveHook, ObjectDirective } from \"vue\";\n\nfunction findFocusable(element: HTMLElement): NodeListOf<HTMLElement> | null {\n    if (!element) return null;\n    return element.querySelectorAll(`a[href]:not([tabindex=\"-1\"]),\n                                 area[href],\n                                 input:not([disabled]):not([type=\"hidden\"]),\n                                 select:not([disabled]),\n                                 textarea:not([disabled]),\n                                 button:not([disabled]),\n                                 iframe,\n                                 object,\n                                 embed,\n                                 *[tabindex]:not([tabindex=\"-1\"]):not([disabled]),\n                                 *[contenteditable]`);\n}\n\nexport function useTrapFocus(): {\n    /** vue directive - trap focus on the current element */\n    vTrapFocus: ObjectDirective<HTMLElement>;\n} {\n    /** keydown event, which compares event target with trap element */\n    let onKeyDown: ((event: KeyboardEvent) => void) | null = null;\n\n    function applyHandler(el: HTMLElement, value: boolean): void {\n        if (value) {\n            // move focus inside the root element\n            el.focus({ preventScroll: true });\n\n            // set keydown event listener\n            if (typeof onKeyDown === \"function\")\n                el.addEventListener(\"keydown\", onKeyDown);\n        } else {\n            // remove keydown event listener\n            if (typeof onKeyDown === \"function\")\n                el.removeEventListener(\"keydown\", onKeyDown);\n        }\n    }\n\n    const onMounted: DirectiveHook<HTMLElement> = (el, { value }) => {\n        // create onKeyDown event listener\n        onKeyDown = (event: KeyboardEvent): void => {\n            const target = event.target as HTMLElement;\n            if (!target) return;\n\n            // Need to get focusable each time since it can change between key events\n            // ex. changing month in a datepicker\n            const focusable = findFocusable(el);\n            if (!focusable?.length) {\n                event.preventDefault();\n                return;\n            }\n\n            const firstFocusable = focusable[0];\n            const lastFocusable = focusable[focusable.length - 1];\n\n            if (\n                target === firstFocusable &&\n                event.shiftKey &&\n                event.key === \"Tab\"\n            ) {\n                // prevent moving focus outside by setting the focus to last focusable element\n                event.preventDefault();\n                lastFocusable.focus();\n            } else if (\n                target === lastFocusable &&\n                !event.shiftKey &&\n                event.key === \"Tab\"\n            ) {\n                // prevent moving focus outside by setting the focus to first focusable element\n                event.preventDefault();\n                firstFocusable.focus();\n            }\n        };\n\n        // apply handler when binding value is already true\n        if (value) applyHandler(el, value);\n    };\n\n    /** cleanup on beforeUnmount */\n    const onBeforeUnmount: DirectiveHook<HTMLElement> = (el) => {\n        // remove handler\n        applyHandler(el, false);\n        onKeyDown = null;\n    };\n\n    const onUpdate: DirectiveHook<HTMLElement> = (el, { value, oldValue }) => {\n        // check if binding value has changed\n        if (value !== oldValue)\n            // update handler based on binding value\n            applyHandler(el, value);\n    };\n\n    return {\n        vTrapFocus: {\n            mounted: onMounted,\n            beforeUnmount: onBeforeUnmount,\n            updated: onUpdate,\n        },\n    };\n}\n"],"names":[],"mappings":";;AAMA,SAAS,cAAc,SAAsD;AACrE,MAAA,CAAC,QAAgB,QAAA;AACrB,SAAO,QAAQ,iBAAiB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,oDAUgB;AACpD;AAEO,SAAS,eAGd;AAEE,MAAI,YAAqD;AAEhD,WAAA,aAAa,IAAiB,OAAsB;AACzD,QAAI,OAAO;AAEP,SAAG,MAAM,EAAE,eAAe,KAAA,CAAM;AAGhC,UAAI,OAAO,cAAc;AAClB,WAAA,iBAAiB,WAAW,SAAS;AAAA,IAAA,OACzC;AAEH,UAAI,OAAO,cAAc;AAClB,WAAA,oBAAoB,WAAW,SAAS;AAAA,IAAA;AAAA,EACnD;AAGJ,QAAM,YAAwC,CAAC,IAAI,EAAE,YAAY;AAE7D,gBAAY,CAAC,UAA+B;AACxC,YAAM,SAAS,MAAM;AACrB,UAAI,CAAC,OAAQ;AAIP,YAAA,YAAY,cAAc,EAAE;AAC9B,UAAA,EAAC,uCAAW,SAAQ;AACpB,cAAM,eAAe;AACrB;AAAA,MAAA;AAGE,YAAA,iBAAiB,UAAU,CAAC;AAClC,YAAM,gBAAgB,UAAU,UAAU,SAAS,CAAC;AAEpD,UACI,WAAW,kBACX,MAAM,YACN,MAAM,QAAQ,OAChB;AAEE,cAAM,eAAe;AACrB,sBAAc,MAAM;AAAA,MAAA,WAEpB,WAAW,iBACX,CAAC,MAAM,YACP,MAAM,QAAQ,OAChB;AAEE,cAAM,eAAe;AACrB,uBAAe,MAAM;AAAA,MAAA;AAAA,IAE7B;AAGI,QAAA,MAAoB,cAAA,IAAI,KAAK;AAAA,EACrC;AAGM,QAAA,kBAA8C,CAAC,OAAO;AAExD,iBAAa,IAAI,KAAK;AACV,gBAAA;AAAA,EAChB;AAEA,QAAM,WAAuC,CAAC,IAAI,EAAE,OAAO,eAAe;AAEtE,QAAI,UAAU;AAEV,mBAAa,IAAI,KAAK;AAAA,EAC9B;AAEO,SAAA;AAAA,IACH,YAAY;AAAA,MACR,SAAS;AAAA,MACT,eAAe;AAAA,MACf,SAAS;AAAA,IAAA;AAAA,EAEjB;AACJ;;"}