diff options
| author | かっこかり <67428053+kakkokari-gtyih@users.noreply.github.com> | 2024-07-12 16:25:44 +0900 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-07-12 16:25:44 +0900 |
| commit | 385969e9f56a39a1e5547b94901d155e1e811263 (patch) | |
| tree | c5c4082d99d97f3220efd4dfd0926b4e809cfd3b /packages/frontend/src/components/MkModal.vue | |
| parent | enhance(frontend): 未使用のサウンド設定を削除 (#14116) (diff) | |
| download | sharkey-385969e9f56a39a1e5547b94901d155e1e811263.tar.gz sharkey-385969e9f56a39a1e5547b94901d155e1e811263.tar.bz2 sharkey-385969e9f56a39a1e5547b94901d155e1e811263.zip | |
fix(frontend): フォーカスの挙動を修正 (#14158)
* fix(frontend): 直前のパターンを記録するように
* fix(frontend): フォーカス/タブ移動に関する挙動を調整 (#226)
Cherry-pick commit e8c030673326871edf3623cf2b8675d68f9e1b13
Co-authored-by: taiyme <53635909+taiyme@users.noreply.github.com>
* focusのデザイン修正
* move scripts
* Modalにfocus trapを追加
* 記録するホットキーはレートリミット式にする
* escキーのハンドリングをMkModalに統一
* fix
* enterで子メニューを開けるように
* lint
* fix focus trap
* improve switch accessibility
* 一部のmodalのフォーカストラップが外れない問題を修正
* fix
* fix
* Revert "記録するホットキーはレートリミット式にする"
This reverts commit 40a7509286a87911ad4cc06d9482e8a2e5d0e7e8.
* Revert "fix(frontend): 直前のパターンを記録するように"
This reverts commit 5372b2594023952cff34aa62253ed4efef15b5dd.
* Revert "Revert "fix(frontend): 直前のパターンを記録するように""
This reverts commit a9bb52e799e110927ad92cd8f26af980819334e1.
* Revert "Revert "記録するホットキーはレートリミット式にする""
This reverts commit bdac34273e0bc5f13604c7e2f9fa6b1321a0df3d.
* 試験的にCypressでのFocustrapを無効化
* fix
* fix focus-trap
* Update Changelog
* :v:
* fix focustrap invocation logic
* スクロールがsticky headerを考慮するように
* :art:
* スタイルの微調整
* :art:
* remove deprecated key aliases
* focusElementが足りなかったので修正
* preview系にfocus時スタイルが足りなかったので修正
* `returnFocusElement` -> `returnFocusTo`
* lint
* Update packages/frontend/src/components/MkModalWindow.vue
* Apply suggestions from code review
Co-authored-by: taiy <53635909+taiyme@users.noreply.github.com>
* keydownイベントをまとめる
* use correct pesudo-element selector
* fix
* rename
---------
Co-authored-by: taiyme <53635909+taiyme@users.noreply.github.com>
Co-authored-by: syuilo <4439005+syuilo@users.noreply.github.com>
Diffstat (limited to 'packages/frontend/src/components/MkModal.vue')
| -rw-r--r-- | packages/frontend/src/components/MkModal.vue | 28 |
1 files changed, 26 insertions, 2 deletions
diff --git a/packages/frontend/src/components/MkModal.vue b/packages/frontend/src/components/MkModal.vue index 264d8b6c9c..a5fbf8d365 100644 --- a/packages/frontend/src/components/MkModal.vue +++ b/packages/frontend/src/components/MkModal.vue @@ -30,9 +30,9 @@ SPDX-License-Identifier: AGPL-3.0-only [$style.transition_modal_leaveTo]: transitionName === 'modal', [$style.transition_send_leaveTo]: transitionName === 'send', })" - :duration="transitionDuration" appear @afterLeave="emit('closed')" @enter="emit('opening')" @afterEnter="onOpened" + :duration="transitionDuration" appear @afterLeave="onClosed" @enter="emit('opening')" @afterEnter="onOpened" > - <div v-show="manualShowing != null ? manualShowing : showing" v-hotkey.global="keymap" :class="[$style.root, { [$style.drawer]: type === 'drawer', [$style.dialog]: type === 'dialog', [$style.popup]: type === 'popup' }]" :style="{ zIndex, pointerEvents: (manualShowing != null ? manualShowing : showing) ? 'auto' : 'none', '--transformOrigin': transformOrigin }"> + <div v-show="manualShowing != null ? manualShowing : showing" ref="modalRootEl" v-hotkey.global="keymap" :class="[$style.root, { [$style.drawer]: type === 'drawer', [$style.dialog]: type === 'dialog', [$style.popup]: type === 'popup' }]" :style="{ zIndex, pointerEvents: (manualShowing != null ? manualShowing : showing) ? 'auto' : 'none', '--transformOrigin': transformOrigin }"> <div data-cy-bg :data-cy-transparent="isEnableBgTransparent" class="_modalBg" :class="[$style.bg, { [$style.bgTransparent]: isEnableBgTransparent }]" :style="{ zIndex }" @click="onBgClick" @mousedown="onBgClick" @contextmenu.prevent.stop="() => {}"></div> <div ref="content" :class="[$style.content, { [$style.fixed]: fixed }]" :style="{ zIndex }" @click.self="onBgClick"> <slot :max-height="maxHeight" :type="type"></slot> @@ -48,6 +48,8 @@ import { isTouchUsing } from '@/scripts/touch.js'; import { defaultStore } from '@/store.js'; import { deviceKind } from '@/scripts/device-kind.js'; import { type Keymap } from '@/scripts/hotkey.js'; +import { focusTrap } from '@/scripts/focus-trap.js'; +import { focusParent } from '@/scripts/focus.js'; function getFixedContainer(el: Element | null): Element | null { if (el == null || el.tagName === 'BODY') return null; @@ -69,6 +71,7 @@ const props = withDefaults(defineProps<{ zPriority?: 'low' | 'middle' | 'high'; noOverlap?: boolean; transparentBg?: boolean; + returnFocusTo?: HTMLElement | null; }>(), { manualShowing: null, src: null, @@ -77,6 +80,7 @@ const props = withDefaults(defineProps<{ zPriority: 'low', noOverlap: true, transparentBg: false, + returnFocusTo: null, }); const emit = defineEmits<{ @@ -94,6 +98,7 @@ const maxHeight = ref<number>(); const fixed = ref(false); const transformOrigin = ref('center'); const showing = ref(true); +const modalRootEl = shallowRef<HTMLElement>(); const content = shallowRef<HTMLElement>(); const zIndex = os.claimZIndex(props.zPriority); const useSendAnime = ref(false); @@ -132,6 +137,7 @@ const transitionDuration = computed((() => : 0 )); +let releaseFocusTrap: (() => void) | null = null; let contentClicking = false; function close(opts: { useSendAnimation?: boolean } = {}) { @@ -296,6 +302,10 @@ const onOpened = () => { }, { passive: true }); }; +const onClosed = () => { + emit('closed'); +}; + const alignObserver = new ResizeObserver((entries, observer) => { align(); }); @@ -313,6 +323,20 @@ onMounted(() => { align(); }, { immediate: true }); + watch([showing, () => props.manualShowing], ([showing, manualShowing]) => { + if (manualShowing === true || (manualShowing == null && showing === true)) { + if (modalRootEl.value != null) { + const { release } = focusTrap(modalRootEl.value); + + releaseFocusTrap = release; + modalRootEl.value.focus(); + } + } else { + releaseFocusTrap?.(); + focusParent(props.returnFocusTo ?? props.src, true, false); + } + }, { immediate: true }); + nextTick(() => { alignObserver.observe(content.value!); }); |