Proper use of focus trap

This commit is contained in:
Freeplay 2023-06-20 14:13:05 -04:00
parent be6a640edb
commit c05f151b1a
4 changed files with 63 additions and 84 deletions

View file

@ -1,10 +1,12 @@
<template>
<FocusTrap
:active="false"
ref="focusTrap"
v-model:active="isActive"
:return-focus-on-deactivate="!noReturnFocus"
:initial-focus="() => itemsEl.children[0]"
@deactivate="emit('close')"
>
<div tabindex="-1">
<div>
<div
ref="itemsEl"
class="rrevdjwt _popup _shadow"
@ -14,6 +16,7 @@
maxHeight: maxHeight ? maxHeight + 'px' : '',
}"
@contextmenu.self="(e) => e.preventDefault()"
tabindex="-1"
>
<template v-for="(item, i) in items2">
<div v-if="item === null" class="divider"></div>
@ -173,6 +176,7 @@
:root-element="itemsEl"
showing
@actioned="childActioned"
@closed="closeChild"
/>
</div>
</div>
@ -303,23 +307,7 @@ function close(actioned = false) {
emit("close", actioned);
}
function focusUp() {
focusPrev(document.activeElement);
}
function focusDown() {
focusNext(document.activeElement);
}
onMounted(() => {
focusTrap.value.activate();
if (props.viaKeyboard) {
nextTick(() => {
focusNext(itemsEl.children[0], true, false);
});
}
document.addEventListener("mousedown", onGlobalMousedown, {
passive: true,
});

View file

@ -14,17 +14,17 @@
:duration="transitionDuration"
appear
@after-leave="emit('closed')"
@keyup.esc="emit('click')"
@enter="emit('opening')"
@after-enter="onOpened"
>
<FocusTrap
v-model:active="isActive"
:initial-focus="() => $refs.content"
:return-focus-on-deactivate="!noReturnFocus"
@deactivate="close"
>
<div
v-show="manualShowing != null ? manualShowing : showing"
v-hotkey.global="keymap"
:class="[
$style.root,
{
@ -44,7 +44,6 @@
'--transformOrigin': transformOrigin,
}"
tabindex="-1"
v-focus
>
<div
class="_modalBg data-cy-bg"
@ -180,7 +179,7 @@ let transitionDuration = $computed(() =>
let contentClicking = false;
const focusedElement = document.activeElement;
// const focusedElement = document.activeElement;
function close(ev, opts: { useSendAnimation?: boolean } = {}) {
// removeEventListener("popstate", close);
// if (props.preferType == "dialog") {
@ -194,16 +193,16 @@ function close(ev, opts: { useSendAnimation?: boolean } = {}) {
if (props.src) props.src.style.pointerEvents = "auto";
showing = false;
emit("close");
if (!props.noReturnFocus) {
focusedElement.focus();
}
// if (!props.noReturnFocus) {
// focusedElement.focus();
// }
}
function onBgClick() {
if (contentClicking) return;
if (!props.noReturnFocus) {
focusedElement.focus();
}
// if (!props.noReturnFocus) {
// focusedElement.focus();
// }
emit("click");
}
@ -211,10 +210,6 @@ if (type === "drawer") {
maxHeight = window.innerHeight / 1.5;
}
const keymap = {
esc: () => emit("esc"),
};
const MARGIN = 16;
const align = () => {

View file

@ -6,58 +6,55 @@
@keyup.esc="$emit('close')"
@closed="$emit('closed')"
>
<FocusTrap v-model:active="isActive">
<div
ref="rootEl"
class="ebkgoccj"
:style="{
width: `${width}px`,
height: scroll
? height
? `${height}px`
: null
: height
? `min(${height}px, 100%)`
: '100%',
}"
@keydown="onKeydown"
tabindex="-1"
>
<div ref="headerEl" class="header">
<button
v-if="withOkButton"
:aria-label="i18n.t('close')"
class="_button"
@click="$emit('close')"
>
<i class="ph-x ph-bold ph-lg"></i>
</button>
<span class="title">
<slot name="header"></slot>
</span>
<button
v-if="!withOkButton"
:aria-label="i18n.t('close')"
class="_button"
@click="$emit('close')"
>
<i class="ph-x ph-bold ph-lg"></i>
</button>
<button
v-if="withOkButton"
:aria-label="i18n.t('ok')"
class="_button"
:disabled="okButtonDisabled"
@click="$emit('ok')"
>
<i class="ph-check ph-bold ph-lg"></i>
</button>
</div>
<div class="body">
<slot></slot>
</div>
<div
ref="rootEl"
class="ebkgoccj"
:style="{
width: `${width}px`,
height: scroll
? height
? `${height}px`
: null
: height
? `min(${height}px, 100%)`
: '100%',
}"
tabindex="-1"
>
<div ref="headerEl" class="header">
<button
v-if="withOkButton"
:aria-label="i18n.t('close')"
class="_button"
@click="$emit('close')"
>
<i class="ph-x ph-bold ph-lg"></i>
</button>
<span class="title">
<slot name="header"></slot>
</span>
<button
v-if="!withOkButton"
:aria-label="i18n.t('close')"
class="_button"
@click="$emit('close')"
>
<i class="ph-x ph-bold ph-lg"></i>
</button>
<button
v-if="withOkButton"
:aria-label="i18n.t('ok')"
class="_button"
:disabled="okButtonDisabled"
@click="$emit('ok')"
>
<i class="ph-check ph-bold ph-lg"></i>
</button>
</div>
</FocusTrap>
<div class="body">
<slot></slot>
</div>
</div>
</MkModal>
</template>

View file

@ -8,7 +8,6 @@
@click="modal.close()"
@closed="emit('closed')"
tabindex="-1"
v-focus
>
<MkMenu
:items="items"