mirror of
https://github.com/immich-app/immich.git
synced 2025-12-26 09:14:58 +03:00
59 lines
1.7 KiB
TypeScript
59 lines
1.7 KiB
TypeScript
import { shortcuts } from '$lib/actions/shortcut';
|
|
import { tick } from 'svelte';
|
|
|
|
const selectors =
|
|
'button:not([disabled]), [href], input:not([disabled]), select:not([disabled]), textarea:not([disabled]), [tabindex]:not([tabindex="-1"])';
|
|
|
|
export function focusTrap(container: HTMLElement) {
|
|
const triggerElement = document.activeElement;
|
|
|
|
const focusableElement = container.querySelector<HTMLElement>(selectors);
|
|
|
|
// Use tick() to ensure focus trap works correctly inside <Portal />
|
|
void tick().then(() => focusableElement?.focus());
|
|
|
|
const getFocusableElements = (): [HTMLElement | null, HTMLElement | null] => {
|
|
const focusableElements = container.querySelectorAll<HTMLElement>(selectors);
|
|
return [
|
|
focusableElements.item(0), //
|
|
focusableElements.item(focusableElements.length - 1),
|
|
];
|
|
};
|
|
|
|
const { destroy: destroyShortcuts } = shortcuts(container, [
|
|
{
|
|
ignoreInputFields: false,
|
|
preventDefault: false,
|
|
shortcut: { key: 'Tab' },
|
|
onShortcut: (event) => {
|
|
const [firstElement, lastElement] = getFocusableElements();
|
|
if (document.activeElement === lastElement) {
|
|
event.preventDefault();
|
|
firstElement?.focus();
|
|
}
|
|
},
|
|
},
|
|
{
|
|
ignoreInputFields: false,
|
|
preventDefault: false,
|
|
shortcut: { key: 'Tab', shift: true },
|
|
onShortcut: (event) => {
|
|
const [firstElement, lastElement] = getFocusableElements();
|
|
if (document.activeElement === firstElement) {
|
|
event.preventDefault();
|
|
lastElement?.focus();
|
|
}
|
|
},
|
|
},
|
|
]);
|
|
|
|
return {
|
|
destroy() {
|
|
destroyShortcuts?.();
|
|
if (triggerElement instanceof HTMLElement) {
|
|
triggerElement.focus();
|
|
}
|
|
},
|
|
};
|
|
}
|