import type { Directive } from 'vue' /** * Vue directive that locks keyboard focus within the bound element. * * ! Be careful to always allow the user to escape the focus trap as this directive does not handle that. * * @example * ```vue * * ``` */ const vLockFocus: Directive = { mounted(el, binding) { if (binding.value === false) return el.addEventListener('keydown', handleFocus) }, unmounted(el) { el.removeEventListener('keydown', handleFocus) }, updated(el, binding) { if (binding.value === false) { el.removeEventListener('keydown', handleFocus) } else { el.addEventListener('keydown', handleFocus) } }, } function handleFocus(event: KeyboardEvent) { if (event.key !== 'Tab') return const target = event.currentTarget as HTMLElement const focusableElements = target.querySelectorAll( 'a[href], area[href], input:not([disabled]), select:not([disabled]), textarea:not([disabled]), button:not([disabled]), iframe, object, embed, [tabindex]:not([tabindex="-1"]), [contenteditable]', ) const firstElement = focusableElements[0] as HTMLElement const lastElement = focusableElements[focusableElements.length - 1] as HTMLElement if (event.shiftKey && document.activeElement === firstElement) { event.preventDefault() lastElement.focus() } else if (!event.shiftKey && document.activeElement === lastElement) { event.preventDefault() firstElement.focus() } } export default vLockFocus