Skip to content

Commit

Permalink
fix(focus-trap): focus trap issues with modal and offcanvas fixes #2064
Browse files Browse the repository at this point in the history
  • Loading branch information
VividLemon committed Jul 21, 2024
1 parent 7e7ad20 commit 91e7d04
Show file tree
Hide file tree
Showing 3 changed files with 43 additions and 36 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
v-bind="$attrs"
:style="computedZIndex"
>
<div class="modal-dialog" :class="modalDialogClasses">
<div class="modal-dialog" :class="modalDialogClasses" tabindex="0">
<div v-if="lazyShowing" class="modal-content" :class="props.contentClass">
<div v-if="!props.hideHeader" class="modal-header" :class="headerClasses">
<slot name="header" v-bind="sharedSlots">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,12 @@
</template>
</slot>
</div>
<div class="offcanvas-body" :class="props.bodyClass" v-bind="props.bodyAttrs">
<div
class="offcanvas-body"
tabindex="0"
:class="props.bodyClass"
v-bind="props.bodyAttrs"
>
<slot v-bind="sharedSlots" />
</div>
<div v-if="hasFooterSlot" :class="props.footerClass">
Expand Down Expand Up @@ -160,12 +165,6 @@ useSafeScrollLock(modelValue, () => props.bodyScrolling || isOpenByBreakpoint.va
const element = ref<HTMLElement | null>(null)
useActivatedFocusTrap({
element,
isActive: modelValue,
noTrap: () => props.noTrap || isOpenByBreakpoint.value,
})
onKeyStroke(
'Escape',
() => {
Expand All @@ -179,6 +178,13 @@ const {focused} = useFocus(element, {
})
const isActive = ref(modelValue.value)
useActivatedFocusTrap({
element,
isActive,
noTrap: () => props.noTrap || isOpenByBreakpoint.value,
})
const lazyLoadCompleted = ref(false)
const wasClosedByBreakpointChange = ref(false)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,35 +1,36 @@
import {type MaybeRefOrGetter, onMounted, readonly, type Ref, toRef, watch} from 'vue'
import {useFocusTrap} from '@vueuse/integrations/useFocusTrap'
import {type MaybeRefOrGetter, nextTick, readonly, type Ref, toRef, watch} from 'vue'
import {useFocusTrap, type UseFocusTrapOptions} from '@vueuse/integrations/useFocusTrap'

export const useActivatedFocusTrap = ({
element,
isActive,
noTrap,
}: {
element: Ref<HTMLElement | null>
isActive: MaybeRefOrGetter<boolean>
noTrap: MaybeRefOrGetter<boolean>
}) => {
export const useActivatedFocusTrap = (
{
element,
isActive,
noTrap,
}: {
element: Ref<HTMLElement | null>
isActive: MaybeRefOrGetter<boolean>
noTrap: MaybeRefOrGetter<boolean>
},
focusTrapOpts: UseFocusTrapOptions = {
allowOutsideClick: true,
}
) => {
const resolvedIsActive = readonly(toRef(isActive))
const resolvedNoTrap = readonly(toRef(noTrap))

onMounted(() => {
const trap = useFocusTrap(element, {
allowOutsideClick: true,
fallbackFocus: window?.document?.body,
})
watch(resolvedIsActive, (newValue) => {
if (newValue && resolvedNoTrap.value === false) {
trap.activate()
} else {
trap.deactivate()
}
})
const trap = useFocusTrap(element, focusTrapOpts)
watch(resolvedIsActive, async (newValue) => {
await nextTick()
if (newValue && resolvedNoTrap.value === false) {
trap.activate()
} else {
trap.deactivate()
}
})

watch(resolvedNoTrap, (newValue) => {
if (newValue === true) {
trap.deactivate()
}
})
watch(resolvedNoTrap, (newValue) => {
if (newValue === true) {
trap.deactivate()
}
})
}

0 comments on commit 91e7d04

Please sign in to comment.