UNPKG

element-plus

Version:

A Component Library for Vue 3

1 lines 10.3 kB
{"version":3,"file":"focus-trap.mjs","sources":["../../../../../../packages/components/focus-trap/src/focus-trap.vue"],"sourcesContent":["<template>\n <slot />\n</template>\n<script lang=\"ts\">\nimport {\n defineComponent,\n nextTick,\n onBeforeUnmount,\n onMounted,\n provide,\n ref,\n unref,\n watch,\n} from 'vue'\nimport { EVENT_CODE } from '@element-plus/constants'\nimport {\n focusFirstDescendant,\n focusableStack,\n getEdges,\n obtainAllFocusableElements,\n tryFocus,\n} from './utils'\nimport {\n FOCUS_ON_MOUNT,\n FOCUS_ON_MOUNT_OPTS,\n FOCUS_ON_UNMOUNT,\n FOCUS_TRAP_INJECTION_KEY,\n ON_MOUNT_FOCUS_EVT,\n ON_UNMOUNT_FOCUS_EVT,\n} from './tokens'\n\nimport type { FocusLayer } from './utils'\n\nexport default defineComponent({\n name: 'ElFocusTrap',\n inheritAttrs: false,\n props: {\n loop: Boolean,\n trapped: Boolean,\n },\n emits: [ON_MOUNT_FOCUS_EVT, ON_UNMOUNT_FOCUS_EVT],\n setup(props, { emit }) {\n const focusTrapRef = ref<HTMLElement | null>()\n const forwardRef = ref<HTMLElement | null>(null)\n let lastFocusBeforeMounted: HTMLElement | null\n let lastFocusAfterMounted: HTMLElement | null\n\n const focusLayer: FocusLayer = {\n paused: false,\n pause() {\n this.paused = true\n },\n resume() {\n this.paused = false\n },\n }\n\n const onKeydown = (e: KeyboardEvent) => {\n if (!props.loop && !props.trapped) return\n if (focusLayer.paused) return\n\n const { key, altKey, ctrlKey, metaKey, currentTarget, shiftKey } = e\n const { loop } = props\n const isTabbing =\n key === EVENT_CODE.tab && !altKey && !ctrlKey && !metaKey\n\n const currentFocusingEl = document.activeElement\n if (isTabbing && currentFocusingEl) {\n const container = currentTarget as HTMLElement\n const [first, last] = getEdges(container)\n const isTabbable = first && last\n\n if (!isTabbable) {\n if (currentFocusingEl === container) e.preventDefault()\n } else {\n if (!shiftKey && currentFocusingEl === last) {\n e.preventDefault()\n if (loop) tryFocus(first, true)\n } else if (shiftKey && currentFocusingEl === first) {\n e.preventDefault()\n if (loop) tryFocus(last, true)\n }\n }\n }\n }\n\n provide(FOCUS_TRAP_INJECTION_KEY, {\n focusTrapRef: forwardRef,\n onKeydown,\n })\n\n const focusOnMount = (e: Event) => {\n emit(ON_MOUNT_FOCUS_EVT, e)\n }\n const focusOnUnmount = (e: Event) => emit(ON_UNMOUNT_FOCUS_EVT, e)\n const onFocusIn = (e: Event) => {\n const trapContainer = unref(forwardRef)\n if (focusLayer.paused || !trapContainer) return\n const target = e.target as HTMLElement | null\n if (target && trapContainer.contains(target)) {\n lastFocusAfterMounted = target\n } else {\n tryFocus(lastFocusAfterMounted, true)\n }\n }\n\n const onFocusOut = (e: Event) => {\n const trapContainer = unref(forwardRef)\n if (focusLayer.paused || !trapContainer) return\n\n if (\n !trapContainer.contains(\n (e as FocusEvent).relatedTarget as HTMLElement | null\n )\n ) {\n tryFocus(lastFocusAfterMounted, true)\n }\n }\n\n const cleanupDocumentListeners = () => {\n document.removeEventListener('focusin', onFocusIn)\n document.removeEventListener('focusout', onFocusOut)\n }\n\n onMounted(() => {\n const trapContainer = unref(forwardRef)\n if (trapContainer) {\n focusableStack.push(focusLayer)\n const prevFocusedElement = document.activeElement\n lastFocusBeforeMounted = prevFocusedElement as HTMLElement | null\n const isPrevFocusContained = trapContainer.contains(prevFocusedElement)\n if (!isPrevFocusContained) {\n const mountEvent = new Event(FOCUS_ON_MOUNT, FOCUS_ON_MOUNT_OPTS)\n trapContainer.addEventListener(FOCUS_ON_MOUNT, focusOnMount)\n trapContainer.dispatchEvent(mountEvent)\n if (!mountEvent.defaultPrevented) {\n nextTick(() => {\n focusFirstDescendant(\n obtainAllFocusableElements(trapContainer),\n true\n )\n if (document.activeElement === prevFocusedElement) {\n tryFocus(trapContainer)\n }\n })\n }\n }\n }\n\n watch(\n () => props.trapped,\n (trapped) => {\n if (trapped) {\n document.addEventListener('focusin', onFocusIn)\n document.addEventListener('focusout', onFocusOut)\n } else {\n cleanupDocumentListeners()\n }\n },\n { immediate: true }\n )\n })\n\n onBeforeUnmount(() => {\n cleanupDocumentListeners()\n const trapContainer = unref(forwardRef)\n\n if (trapContainer) {\n trapContainer.removeEventListener(FOCUS_ON_MOUNT, focusOnMount)\n const unmountEvent = new Event(FOCUS_ON_UNMOUNT, FOCUS_ON_MOUNT_OPTS)\n\n trapContainer.addEventListener(FOCUS_ON_UNMOUNT, focusOnUnmount)\n trapContainer.dispatchEvent(unmountEvent)\n\n if (!unmountEvent.defaultPrevented) {\n tryFocus(lastFocusBeforeMounted ?? document.body, true)\n }\n\n trapContainer.removeEventListener(FOCUS_ON_UNMOUNT, focusOnMount)\n focusableStack.remove(focusLayer)\n }\n })\n\n return {\n focusTrapRef,\n forwardRef,\n onKeydown,\n }\n },\n})\n</script>\n"],"names":["_renderSlot"],"mappings":"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"}