element-plus
Version:
A Component Library for Vue 3
1 lines • 3.41 kB
Source Map (JSON)
{"version":3,"file":"index.mjs","names":[],"sources":["../../../../../packages/directives/trap-focus/index.ts"],"sourcesContent":["import { nextTick } from 'vue'\nimport { getEventCode, obtainAllFocusableElements } from '@element-plus/utils'\nimport { EVENT_CODE } from '@element-plus/constants'\n\nimport type { ObjectDirective } from 'vue'\n\nexport const FOCUSABLE_CHILDREN = '_trap-focus-children'\nexport const TRAP_FOCUS_HANDLER = '_trap-focus-handler'\n\nexport interface TrapFocusElement extends HTMLElement {\n [FOCUSABLE_CHILDREN]: HTMLElement[]\n [TRAP_FOCUS_HANDLER]: (e: KeyboardEvent) => void\n}\n\nconst FOCUS_STACK: TrapFocusElement[] = []\n\nconst FOCUS_HANDLER = (e: KeyboardEvent) => {\n // Getting the top layer.\n if (FOCUS_STACK.length === 0) return\n const code = getEventCode(e)\n const focusableElement =\n FOCUS_STACK[FOCUS_STACK.length - 1][FOCUSABLE_CHILDREN]\n if (focusableElement.length > 0 && code === EVENT_CODE.tab) {\n if (focusableElement.length === 1) {\n e.preventDefault()\n if (document.activeElement !== focusableElement[0]) {\n focusableElement[0].focus()\n }\n return\n }\n const goingBackward = e.shiftKey\n const isFirst = e.target === focusableElement[0]\n const isLast = e.target === focusableElement[focusableElement.length - 1]\n if (isFirst && goingBackward) {\n e.preventDefault()\n focusableElement[focusableElement.length - 1].focus()\n }\n if (isLast && !goingBackward) {\n e.preventDefault()\n focusableElement[0].focus()\n }\n\n // the is critical since jsdom did not implement user actions, you can only mock it\n // DELETE ME: when testing env switches to puppeteer\n if (process.env.NODE_ENV === 'test') {\n const index = focusableElement.indexOf(e.target as HTMLElement)\n if (index !== -1) {\n focusableElement[goingBackward ? index - 1 : index + 1]?.focus()\n }\n }\n }\n}\n\nconst TrapFocus: ObjectDirective = {\n beforeMount(el: TrapFocusElement) {\n el[FOCUSABLE_CHILDREN] = obtainAllFocusableElements(el)\n FOCUS_STACK.push(el)\n if (FOCUS_STACK.length <= 1) {\n document.addEventListener('keydown', FOCUS_HANDLER)\n }\n },\n updated(el: TrapFocusElement) {\n nextTick(() => {\n el[FOCUSABLE_CHILDREN] = obtainAllFocusableElements(el)\n })\n },\n unmounted() {\n FOCUS_STACK.shift()\n if (FOCUS_STACK.length === 0) {\n document.removeEventListener('keydown', FOCUS_HANDLER)\n }\n },\n}\n\nexport default TrapFocus\n"],"mappings":";;;;;AAMA,MAAa,qBAAqB;AAClC,MAAa,qBAAqB;AAOlC,MAAM,cAAkC,EAAE;AAE1C,MAAM,iBAAiB,MAAqB;CAE1C,IAAI,YAAY,WAAW,GAAG;CAC9B,MAAM,OAAO,aAAa,EAAE;CAC5B,MAAM,mBACJ,YAAY,YAAY,SAAS,GAAG;CACtC,IAAI,iBAAiB,SAAS,KAAK,SAAS,WAAW,KAAK;EAC1D,IAAI,iBAAiB,WAAW,GAAG;GACjC,EAAE,gBAAgB;GAClB,IAAI,SAAS,kBAAkB,iBAAiB,IAC9C,iBAAiB,GAAG,OAAO;GAE7B;;EAEF,MAAM,gBAAgB,EAAE;EACxB,MAAM,UAAU,EAAE,WAAW,iBAAiB;EAC9C,MAAM,SAAS,EAAE,WAAW,iBAAiB,iBAAiB,SAAS;EACvE,IAAI,WAAW,eAAe;GAC5B,EAAE,gBAAgB;GAClB,iBAAiB,iBAAiB,SAAS,GAAG,OAAO;;EAEvD,IAAI,UAAU,CAAC,eAAe;GAC5B,EAAE,gBAAgB;GAClB,iBAAiB,GAAG,OAAO;;;;AAcjC,MAAM,YAA6B;CACjC,YAAY,IAAsB;EAChC,GAAG,sBAAsB,2BAA2B,GAAG;EACvD,YAAY,KAAK,GAAG;EACpB,IAAI,YAAY,UAAU,GACxB,SAAS,iBAAiB,WAAW,cAAc;;CAGvD,QAAQ,IAAsB;EAC5B,eAAe;GACb,GAAG,sBAAsB,2BAA2B,GAAG;IACvD;;CAEJ,YAAY;EACV,YAAY,OAAO;EACnB,IAAI,YAAY,WAAW,GACzB,SAAS,oBAAoB,WAAW,cAAc;;CAG3D"}