vuestic-ui
Version:
Vue 3 UI Framework
1 lines • 3.53 kB
Source Map (JSON)
{"version":3,"file":"useTrapFocus.mjs","sources":["../../../../src/composables/useTrapFocus.ts"],"sourcesContent":["import { useAppGlobal } from './useAppGlobal'\nimport { useDocument } from './useDocument'\nimport { useWindow } from './useWindow'\n\nconst FOCUSABLE_ELEMENTS_SELECTOR = ':where(a, button, input, textarea, select):not([disabled]), *[tabindex]'\n\nexport const useTrapFocus = () => {\n const document = useDocument()\n const window = useWindow()\n\n const trapInEl = useAppGlobal<null | HTMLElement>('trapInEl', null)\n\n let focusableElements: HTMLElement[] = []\n let firstFocusableElement: HTMLElement | null = null\n let lastFocusableElement: HTMLElement | null = null\n\n const isFocusIn = (evt: Event) => {\n return trapInEl.value?.contains(evt.target as Node) || false\n }\n\n const focusFirstElement = () => {\n firstFocusableElement?.focus()\n }\n const focusLastElement = () => {\n lastFocusableElement?.focus()\n }\n\n const onKeydown = (evt: KeyboardEvent) => {\n const isTabPressed = evt.code === 'Tab'\n const isShiftPressed = evt.shiftKey\n\n if (!isTabPressed) {\n return\n }\n\n if (!isFocusIn(evt)) {\n evt.preventDefault()\n isShiftPressed ? focusLastElement() : focusFirstElement()\n\n return\n }\n\n if (document.value?.activeElement === lastFocusableElement && !isShiftPressed) {\n evt.preventDefault()\n focusFirstElement()\n return\n }\n\n if (document.value?.activeElement === firstFocusableElement && isShiftPressed) {\n evt.preventDefault()\n focusLastElement()\n }\n }\n\n const trapFocusIn = (el: HTMLElement) => {\n trapInEl.value = el\n\n freeFocus()\n trapFocus()\n }\n\n const trapFocus = () => {\n if (!trapInEl.value) {\n return\n }\n\n focusableElements = Array.from(trapInEl.value.querySelectorAll(FOCUSABLE_ELEMENTS_SELECTOR))\n firstFocusableElement = focusableElements[0]\n lastFocusableElement = focusableElements[focusableElements.length - 1]\n\n window.value?.addEventListener('keydown', onKeydown)\n }\n const freeFocus = () => {\n focusableElements = []\n firstFocusableElement = null\n lastFocusableElement = null\n\n window.value?.removeEventListener('keydown', onKeydown)\n }\n\n return {\n trapFocus,\n freeFocus,\n trapFocusIn,\n }\n}\n"],"names":[],"mappings":";;;AAIA,MAAM,8BAA8B;AAE7B,MAAM,eAAe,MAAM;AAChC,QAAM,WAAW;AACjB,QAAM,SAAS;AAET,QAAA,WAAW,aAAiC,YAAY,IAAI;AAElE,MAAI,oBAAmC,CAAA;AACvC,MAAI,wBAA4C;AAChD,MAAI,uBAA2C;AAEzC,QAAA,YAAY,CAAC,QAAe;;AAChC,aAAO,cAAS,UAAT,mBAAgB,SAAS,IAAI,YAAmB;AAAA,EAAA;AAGzD,QAAM,oBAAoB,MAAM;AAC9B,mEAAuB;AAAA,EAAM;AAE/B,QAAM,mBAAmB,MAAM;AAC7B,iEAAsB;AAAA,EAAM;AAGxB,QAAA,YAAY,CAAC,QAAuB;;AAClC,UAAA,eAAe,IAAI,SAAS;AAClC,UAAM,iBAAiB,IAAI;AAE3B,QAAI,CAAC,cAAc;AACjB;AAAA,IACF;AAEI,QAAA,CAAC,UAAU,GAAG,GAAG;AACnB,UAAI,eAAe;AACF,uBAAA,qBAAqB;AAEtC;AAAA,IACF;AAEA,UAAI,cAAS,UAAT,mBAAgB,mBAAkB,wBAAwB,CAAC,gBAAgB;AAC7E,UAAI,eAAe;AACD;AAClB;AAAA,IACF;AAEA,UAAI,cAAS,UAAT,mBAAgB,mBAAkB,yBAAyB,gBAAgB;AAC7E,UAAI,eAAe;AACF;IACnB;AAAA,EAAA;AAGI,QAAA,cAAc,CAAC,OAAoB;AACvC,aAAS,QAAQ;AAEP;AACA;EAAA;AAGZ,QAAM,YAAY,MAAM;;AAClB,QAAA,CAAC,SAAS,OAAO;AACnB;AAAA,IACF;AAEA,wBAAoB,MAAM,KAAK,SAAS,MAAM,iBAAiB,2BAA2B,CAAC;AAC3F,4BAAwB,kBAAkB,CAAC;AACpB,2BAAA,kBAAkB,kBAAkB,SAAS,CAAC;AAE9D,iBAAA,UAAA,mBAAO,iBAAiB,WAAW;AAAA,EAAS;AAErD,QAAM,YAAY,MAAM;;AACtB,wBAAoB,CAAA;AACI,4BAAA;AACD,2BAAA;AAEhB,iBAAA,UAAA,mBAAO,oBAAoB,WAAW;AAAA,EAAS;AAGjD,SAAA;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,EAAA;AAEJ;"}