Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 14 additions & 1 deletion index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,13 +40,20 @@ function trapFocus(wrap: HTMLElement, active = true) {
const inCurrentTrap = (el: HTMLElement) => stack.at(-1)?.contains(el)

/** moves focus back to wrap if something outside the wrap is focused */
let recursionCount = 0; // state to prevent infinite recursion
const focusInListener = listen(document, 'focusin', (e: FocusEvent) => {
// return if ths trap is not active
// return if focus is inside the trap
if (!inCurrentTrap(wrap) || inCurrentTrap(e.target as HTMLElement)) {
return
}

if (recursionCount > 0) {
console.warn("trap-focus-svelte: focusin event listener called recursively")
return;
}
recursionCount += 1;

const [firstFocusable, lastFocusable] = getFirstAndLastFocusable()
const previousFocusable = e.relatedTarget as HTMLElement

Expand All @@ -59,16 +66,22 @@ function trapFocus(wrap: HTMLElement, active = true) {
previousFocusable === lastFocusable
) {
firstFocusable.focus()

recursionCount -= 1;
return
}

// if first element and shift tab within time, focus last element
if (previousFocusable === firstFocusable || previousFocusable === wrap) {
lastFocusable.focus()

recursionCount -= 1;
return
}
// fall back to focus on previousFocusable (we made sure it was in current trap above)
previousFocusable.focus()

recursionCount -= 1;
})

return {
Expand All @@ -90,4 +103,4 @@ function trapFocus(wrap: HTMLElement, active = true) {
}
}

export { trapFocus }
export { trapFocus }