UNPKG

@vuesax-alpha/nightly

Version:
258 lines (253 loc) • 9.36 kB
'use strict'; Object.defineProperty(exports, '__esModule', { value: true }); var vue = require('vue'); var lodashUnified = require('lodash-unified'); require('../../../constants/index.js'); require('../../../hooks/index.js'); require('../../../utils/index.js'); require('../../../tokens/index.js'); var focusTrap = require('./focus-trap.js'); var utils = require('./utils.js'); var pluginVue_exportHelper = require('../../../_virtual/plugin-vue_export-helper.js'); var index = require('../../../hooks/use-escape-keydown/index.js'); var aria = require('../../../constants/aria.js'); var focusTrap$1 = require('../../../tokens/focus-trap.js'); var shared = require('@vue/shared'); const __default__ = vue.defineComponent({ name: "VsFocusTrap", inheritAttrs: false }); const _sfc_main = vue.defineComponent({ ...__default__, props: focusTrap.focusTrapProps, emits: focusTrap.focusTrapEmits, setup(__props, { emit }) { const props = __props; const forwardRef = vue.ref(); let lastFocusBeforeTrapped = null; let lastFocusAfterTrapped = null; const { focusReason } = utils.useFocusReason(); index.useEscapeKeydown((event) => { if (props.trapped && !focusLayer.paused) { emit("releaseRequested", event); } }); const focusLayer = { paused: false, pause() { this.paused = true; }, resume() { this.paused = false; } }; const onKeydown = (e) => { if (!props.loop && !props.trapped) return; if (focusLayer.paused) return; const { key, altKey, ctrlKey, metaKey, currentTarget, shiftKey } = e; const { loop } = props; const isTabbing = key === aria.EVENT_CODE.tab && !altKey && !ctrlKey && !metaKey; const currentFocusingEl = document.activeElement; if (isTabbing && currentFocusingEl) { const container = currentTarget; const [first, last] = utils.getEdges(container); const isTabbable = first && last; if (!isTabbable) { if (currentFocusingEl === container) { const focusoutPreventedEvent = utils.createFocusOutPreventedEvent({ focusReason: focusReason.value }); emit("focusoutPrevented", focusoutPreventedEvent); if (!focusoutPreventedEvent.defaultPrevented) { e.preventDefault(); } } } else { if (!shiftKey && currentFocusingEl === last) { const focusoutPreventedEvent = utils.createFocusOutPreventedEvent({ focusReason: focusReason.value }); emit("focusoutPrevented", focusoutPreventedEvent); if (!focusoutPreventedEvent.defaultPrevented) { e.preventDefault(); if (loop) utils.tryFocus(first, true); } } else if (shiftKey && [first, container].includes(currentFocusingEl)) { const focusoutPreventedEvent = utils.createFocusOutPreventedEvent({ focusReason: focusReason.value }); emit("focusoutPrevented", focusoutPreventedEvent); if (!focusoutPreventedEvent.defaultPrevented) { e.preventDefault(); if (loop) utils.tryFocus(last, true); } } } } }; vue.provide(focusTrap$1.focusTrapInjectionKey, { focusTrapRef: forwardRef, onKeydown }); vue.watch( () => props.focusTrapEl, (focusTrapEl) => { if (focusTrapEl) { forwardRef.value = focusTrapEl; } }, { immediate: true } ); vue.watch(forwardRef, (forwardRef2, oldForwardRef) => { if (forwardRef2) { forwardRef2.addEventListener("keydown", onKeydown); forwardRef2.addEventListener("focusin", onFocusIn); forwardRef2.addEventListener("focusout", onFocusOut); } if (oldForwardRef instanceof HTMLElement) { oldForwardRef.removeEventListener("keydown", onKeydown); oldForwardRef.removeEventListener("focusin", onFocusIn); oldForwardRef.removeEventListener("focusout", onFocusOut); } }); const trapOnFocus = (e) => { emit(focusTrap$1.onTrapFocusEvent, e); }; const releaseOnFocus = (e) => emit(focusTrap$1.onReleaseFocusEvent, e); const onFocusIn = (e) => { const trapContainer = vue.unref(forwardRef); if (!trapContainer) return; const target = e.target; const relatedTarget = e.relatedTarget; const isFocusedInTrap = target && trapContainer.contains(target); if (!props.trapped) { const isPrevFocusedInTrap = relatedTarget && trapContainer.contains(relatedTarget); if (!isPrevFocusedInTrap) { lastFocusBeforeTrapped = relatedTarget; } } if (isFocusedInTrap) emit("focusin", e); if (focusLayer.paused) return; if (props.trapped) { if (isFocusedInTrap) { lastFocusAfterTrapped = target; } else { utils.tryFocus(lastFocusAfterTrapped, true); } } }; const onFocusOut = (e) => { const trapContainer = vue.unref(forwardRef); if (focusLayer.paused || !trapContainer) return; if (props.trapped) { const relatedTarget = e.relatedTarget; if (!lodashUnified.isNil(relatedTarget) && !trapContainer.contains(relatedTarget)) { setTimeout(() => { if (!focusLayer.paused && props.trapped) { const focusoutPreventedEvent = utils.createFocusOutPreventedEvent({ focusReason: focusReason.value }); emit("focusoutPrevented", focusoutPreventedEvent); if (!focusoutPreventedEvent.defaultPrevented) { utils.tryFocus(lastFocusAfterTrapped, true); } } }, 0); } } else { const target = e.target; const isFocusedInTrap = target && trapContainer.contains(target); if (!isFocusedInTrap) emit("focusout", e); } }; const startTrap = async () => { await vue.nextTick(); const trapContainer = vue.unref(forwardRef); if (trapContainer) { utils.focusableStack.push(focusLayer); const prevFocusedElement = trapContainer.contains(document.activeElement) ? lastFocusBeforeTrapped : document.activeElement; lastFocusBeforeTrapped = prevFocusedElement; const isPrevFocusContained = trapContainer.contains(prevFocusedElement); if (!isPrevFocusContained) { const focusEvent = new Event(focusTrap$1.focusAfterTrapped, focusTrap$1.focusAfterTrappedOpts); trapContainer.addEventListener(focusTrap$1.focusAfterTrapped, trapOnFocus); trapContainer.dispatchEvent(focusEvent); if (!focusEvent.defaultPrevented) { vue.nextTick(() => { let focusStartEl = props.focusStartEl; if (!shared.isString(focusStartEl)) { utils.tryFocus(focusStartEl); if (document.activeElement !== focusStartEl) { focusStartEl = "first"; } } if (focusStartEl === "first") { utils.focusFirstDescendant( utils.obtainAllFocusableElements(trapContainer), true ); } if (document.activeElement === prevFocusedElement || focusStartEl === "container") { utils.tryFocus(trapContainer); } }); } } } }; const stopTrap = () => { const trapContainer = vue.unref(forwardRef); if (trapContainer) { trapContainer.removeEventListener(focusTrap$1.focusAfterTrapped, trapOnFocus); const releasedEvent = new CustomEvent(focusTrap$1.focusAfterReleased, { ...focusTrap$1.focusAfterTrappedOpts, detail: { focusReason: focusReason.value } }); trapContainer.addEventListener(focusTrap$1.focusAfterReleased, releaseOnFocus); trapContainer.dispatchEvent(releasedEvent); if (!releasedEvent.defaultPrevented && (focusReason.value == "keyboard" || !utils.isFocusCausedByUserEvent())) { utils.tryFocus(lastFocusBeforeTrapped != null ? lastFocusBeforeTrapped : document.body); } trapContainer.removeEventListener(focusTrap$1.focusAfterReleased, trapOnFocus); utils.focusableStack.remove(focusLayer); } }; vue.onMounted(() => { if (props.trapped) { startTrap(); } vue.watch( () => props.trapped, (trapped) => { if (trapped) { startTrap(); } else { stopTrap(); } } ); }); vue.onBeforeUnmount(() => { if (props.trapped) { stopTrap(); } }); return (_ctx, _cache) => { return vue.renderSlot(_ctx.$slots, "default", { handleKeydown: onKeydown }); }; } }); var FocusTrap = /* @__PURE__ */ pluginVue_exportHelper["default"](_sfc_main, [["__file", "/home/runner/work/vuesax-alpha/vuesax-alpha/packages/components/focus-trap/src/focus-trap.vue"]]); exports["default"] = FocusTrap; //# sourceMappingURL=focus-trap2.js.map