dashboard/shell/composables/focusTrap.ts

77 lines
2.3 KiB
TypeScript

/**
* focusTrap is a composable based on the "focus-trap" package that allows us to implement focus traps
* on components for keyboard navigation is a safe and reusable way
*/
import { watch, nextTick, onMounted, onBeforeUnmount } from 'vue';
import { createFocusTrap, FocusTrap } from 'focus-trap';
export function getFirstFocusableElement(element:any = document):any {
const focusableElements = element.querySelectorAll(
'a, button, input, textarea, select, details,[tabindex]:not([tabindex="-1"])'
);
const filteredFocusableElements:any = [];
focusableElements.forEach((el:any) => {
if (!el.hasAttribute('disabled')) {
filteredFocusableElements.push(el);
}
});
return filteredFocusableElements.length ? filteredFocusableElements[0] : document.body;
}
export const DEFAULT_FOCUS_TRAP_OPTS = {
escapeDeactivates: true,
allowOutsideClick: true
};
export function useBasicSetupFocusTrap(focusElement: string | HTMLElement, opts:any = DEFAULT_FOCUS_TRAP_OPTS) {
let focusTrapInstance: FocusTrap;
let focusEl;
onMounted(() => {
focusEl = typeof focusElement === 'string' ? document.querySelector(focusElement) as HTMLElement : focusElement;
focusTrapInstance = createFocusTrap(focusEl, opts);
nextTick(() => {
focusTrapInstance.activate();
});
});
onBeforeUnmount(() => {
if (Object.keys(focusTrapInstance).length) {
focusTrapInstance.deactivate();
}
});
}
export function useWatcherBasedSetupFocusTrapWithDestroyIncluded(watchVar:any, focusElement: string | HTMLElement, opts:any = DEFAULT_FOCUS_TRAP_OPTS, useUnmountHook = false) {
let focusTrapInstance: FocusTrap;
let focusEl;
watch(watchVar, (neu) => {
if (neu && !focusTrapInstance) {
nextTick(() => {
focusEl = typeof focusElement === 'string' ? document.querySelector(focusElement) as HTMLElement : focusElement;
focusTrapInstance = createFocusTrap(focusEl, opts);
nextTick(() => {
focusTrapInstance.activate();
});
});
} else if (!neu && focusTrapInstance && Object.keys(focusTrapInstance).length && !useUnmountHook) {
focusTrapInstance.deactivate();
}
}, { immediate: true });
if (useUnmountHook) {
onBeforeUnmount(() => {
if (focusTrapInstance && Object.keys(focusTrapInstance).length) {
focusTrapInstance.deactivate();
}
});
}
}