UNPKG

@vue-material/core

Version:

Yet another 'Material Design Components' library for Vue3.

83 lines (82 loc) 2.58 kB
import { ref, watch, onMounted, onUnmounted } from "vue"; import { getParent, $ } from "../utils/dom/selector.js"; const focusableSelector = 'a[href], button, input, textarea, select, details, [tabindex]:not([tabindex="-1"])'; function focusFirstFocusable(element) { var _a; (_a = $(focusableSelector, element)) == null ? void 0 : _a.focus(); } function focusLastLockable() { const lastFocusLock = document.querySelectorAll("[focus-lock]"); if (lastFocusLock.length > 0) { focusFirstFocusable([...lastFocusLock].at(-1)); } } function focusDummy() { const focusDummy2 = document.createElement("div"); focusDummy2.setAttribute("tabindex", "0"); focusDummy2.setAttribute( "style", "position: absolute; opacity: 0; pointer-events: none;" ); return focusDummy2; } function useFocusLock(elem, state = true) { const dummy = focusDummy(); const enabled = ref(state); let ignore = false; function onClick(event) { if (!enabled.value) return; const root = elem.value; const target = event.target; if (root) { ignore = root.contains(target) || root === target; ignore || focusFirstFocusable(root); } } function onBlur(event) { if (!enabled.value) return; const root = event.currentTarget; const target = event.relatedTarget; if (ignore) { ignore = false; return; } if (root.contains(target)) return; if (getParent(target, "[focus-lock]")) return; event.preventDefault(); focusFirstFocusable(root); } function mountEvent(element) { element.setAttribute("focus-lock", ""); element.after(dummy); document.addEventListener("pointerdown", onClick); document.addEventListener("focusin", focusOther); element.addEventListener("focusout", onBlur); focusFirstFocusable(element); } function unmountEvent(element) { element.removeAttribute("focus-lock"); document.removeEventListener("pointerdown", onClick); document.removeEventListener("focusin", focusOther); element.removeEventListener("focusout", onBlur); } function focusOther(event) { if (!enabled.value) return; if (getParent(event.relatedTarget, "[focus-lock]")) return; focusLastLockable(); } watch(elem, (newElement, oldElement) => { oldElement && unmountEvent(oldElement); newElement && mountEvent(newElement); }); onMounted(() => elem.value && mountEvent(elem.value)); onUnmounted(() => { dummy.remove(); elem.value && unmountEvent(elem.value); focusLastLockable(); }); return enabled; } export { useFocusLock };