element-plus
Version:
A Component Library for Vue 3
1 lines • 9.79 kB
Source Map (JSON)
{"version":3,"file":"utils.mjs","sources":["../../../../../../packages/components/focus-trap/src/utils.ts"],"sourcesContent":["import { onBeforeUnmount, onMounted, ref } from 'vue'\nimport { focusElement } from '@element-plus/utils'\nimport { FOCUSOUT_PREVENTED, FOCUSOUT_PREVENTED_OPTS } from './tokens'\n\nconst focusReason = ref<'pointer' | 'keyboard'>()\nconst lastUserFocusTimestamp = ref<number>(0)\nconst lastAutomatedFocusTimestamp = ref<number>(0)\nlet focusReasonUserCount = 0\n\nexport type FocusLayer = {\n paused: boolean\n pause: () => void\n resume: () => void\n}\n\nexport type FocusStack = FocusLayer[]\n\nexport const obtainAllFocusableElements = (\n element: HTMLElement\n): HTMLElement[] => {\n const nodes: HTMLElement[] = []\n const walker = document.createTreeWalker(element, NodeFilter.SHOW_ELEMENT, {\n acceptNode: (\n node: Element & {\n disabled: boolean\n hidden: boolean\n type: string\n tabIndex: number\n }\n ) => {\n const isHiddenInput = node.tagName === 'INPUT' && node.type === 'hidden'\n if (node.disabled || node.hidden || isHiddenInput)\n return NodeFilter.FILTER_SKIP\n return node.tabIndex >= 0 || node === document.activeElement\n ? NodeFilter.FILTER_ACCEPT\n : NodeFilter.FILTER_SKIP\n },\n })\n while (walker.nextNode()) nodes.push(walker.currentNode as HTMLElement)\n\n return nodes\n}\n\nexport const getVisibleElement = (\n elements: HTMLElement[],\n container: HTMLElement\n) => {\n for (const element of elements) {\n if (!isHidden(element, container)) return element\n }\n}\n\nexport const isHidden = (element: HTMLElement, container: HTMLElement) => {\n if (process.env.NODE_ENV === 'test') return false\n if (getComputedStyle(element).visibility === 'hidden') return true\n\n while (element) {\n if (container && element === container) return false\n if (getComputedStyle(element).display === 'none') return true\n element = element.parentElement as HTMLElement\n }\n\n return false\n}\n\nexport const getEdges = (container: HTMLElement) => {\n const focusable = obtainAllFocusableElements(container)\n const first = getVisibleElement(focusable, container)\n const last = getVisibleElement(focusable.reverse(), container)\n return [first, last]\n}\n\nconst isSelectable = (\n element: any\n): element is HTMLInputElement & { select: () => void } => {\n return element instanceof HTMLInputElement && 'select' in element\n}\n\nexport const tryFocus = (\n element?: HTMLElement | { focus: () => void } | null,\n shouldSelect?: boolean\n) => {\n if (element) {\n const prevFocusedElement = document.activeElement\n\n focusElement(element, { preventScroll: true })\n lastAutomatedFocusTimestamp.value = window.performance.now()\n\n if (\n element !== prevFocusedElement &&\n isSelectable(element) &&\n shouldSelect\n ) {\n element.select()\n }\n }\n}\n\nfunction removeFromStack<T>(list: T[], item: T) {\n const copy = [...list]\n\n const idx = list.indexOf(item)\n\n if (idx !== -1) {\n copy.splice(idx, 1)\n }\n return copy\n}\n\nconst createFocusableStack = () => {\n let stack = [] as FocusStack\n\n const push = (layer: FocusLayer) => {\n const currentLayer = stack[0]\n\n if (currentLayer && layer !== currentLayer) {\n currentLayer.pause()\n }\n\n stack = removeFromStack(stack, layer)\n stack.unshift(layer)\n }\n\n const remove = (layer: FocusLayer) => {\n stack = removeFromStack(stack, layer)\n stack[0]?.resume?.()\n }\n\n return {\n push,\n remove,\n }\n}\n\nexport const focusFirstDescendant = (\n elements: HTMLElement[],\n shouldSelect = false\n) => {\n const prevFocusedElement = document.activeElement\n for (const element of elements) {\n tryFocus(element, shouldSelect)\n if (document.activeElement !== prevFocusedElement) return\n }\n}\n\nexport const focusableStack = createFocusableStack()\n\nexport const isFocusCausedByUserEvent = (): boolean => {\n return lastUserFocusTimestamp.value > lastAutomatedFocusTimestamp.value\n}\n\nconst notifyFocusReasonPointer = () => {\n focusReason.value = 'pointer'\n lastUserFocusTimestamp.value = window.performance.now()\n}\n\nconst notifyFocusReasonKeydown = () => {\n focusReason.value = 'keyboard'\n lastUserFocusTimestamp.value = window.performance.now()\n}\n\nexport const useFocusReason = (): {\n focusReason: typeof focusReason\n lastUserFocusTimestamp: typeof lastUserFocusTimestamp\n lastAutomatedFocusTimestamp: typeof lastAutomatedFocusTimestamp\n} => {\n onMounted(() => {\n if (focusReasonUserCount === 0) {\n document.addEventListener('mousedown', notifyFocusReasonPointer)\n document.addEventListener('touchstart', notifyFocusReasonPointer)\n document.addEventListener('keydown', notifyFocusReasonKeydown)\n }\n focusReasonUserCount++\n })\n\n onBeforeUnmount(() => {\n focusReasonUserCount--\n if (focusReasonUserCount <= 0) {\n document.removeEventListener('mousedown', notifyFocusReasonPointer)\n document.removeEventListener('touchstart', notifyFocusReasonPointer)\n document.removeEventListener('keydown', notifyFocusReasonKeydown)\n }\n })\n\n return {\n focusReason,\n lastUserFocusTimestamp,\n lastAutomatedFocusTimestamp,\n }\n}\n\nexport const createFocusOutPreventedEvent = (\n detail: CustomEventInit['detail']\n) => {\n return new CustomEvent(FOCUSOUT_PREVENTED, {\n ...FOCUSOUT_PREVENTED_OPTS,\n detail,\n })\n}\n"],"names":[],"mappings":"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"}