From d8cf64a2ca489b380be6606c2f31c3d3cccb5e26 Mon Sep 17 00:00:00 2001 From: kakkokari-gtyih <67428053+kakkokari-gtyih@users.noreply.github.com> Date: Tue, 9 Jul 2024 18:55:22 +0900 Subject: [PATCH] =?UTF-8?q?fix(frontend):=20=E3=83=95=E3=82=A9=E3=83=BC?= =?UTF-8?q?=E3=82=AB=E3=82=B9/=E3=82=BF=E3=83=96=E7=A7=BB=E5=8B=95?= =?UTF-8?q?=E3=81=AB=E9=96=A2=E3=81=99=E3=82=8B=E6=8C=99=E5=8B=95=E3=82=92?= =?UTF-8?q?=E8=AA=BF=E6=95=B4=20(#226)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cherry-pick commit e8c030673326871edf3623cf2b8675d68f9e1b13 Co-authored-by: taiyme <53635909+taiyme@users.noreply.github.com> --- packages/frontend/src/components/MkButton.vue | 1 - .../src/components/MkChannelFollowButton.vue | 12 +- .../frontend/src/components/MkContextMenu.vue | 3 +- .../frontend/src/components/MkEmojiPicker.vue | 5 - .../src/components/MkFollowButton.vue | 12 +- .../src/components/MkImgWithBlurhash.vue | 4 +- .../frontend/src/components/MkMediaAudio.vue | 30 +- .../frontend/src/components/MkMediaList.vue | 54 +++- .../frontend/src/components/MkMediaVideo.vue | 10 +- .../frontend/src/components/MkMenu.child.vue | 5 +- packages/frontend/src/components/MkMenu.vue | 296 ++++++++++-------- packages/frontend/src/components/MkNote.vue | 46 ++- .../src/components/MkNoteDetailed.vue | 64 ++-- .../frontend/src/components/MkPopupMenu.vue | 4 +- packages/frontend/src/components/MkSelect.vue | 27 +- packages/frontend/src/os.ts | 26 +- .../frontend/src/pages/drive.file.info.vue | 1 + packages/frontend/src/pages/page.vue | 1 + .../frontend/src/pages/settings/profile.vue | 1 + packages/frontend/src/scripts/focus.ts | 32 -- packages/frontend/src/scripts/tms/focus.ts | 70 +++++ .../frontend/src/scripts/tms/get-or-null.ts | 19 ++ packages/frontend/src/style.scss | 23 +- 23 files changed, 450 insertions(+), 296 deletions(-) delete mode 100644 packages/frontend/src/scripts/focus.ts create mode 100644 packages/frontend/src/scripts/tms/focus.ts create mode 100644 packages/frontend/src/scripts/tms/get-or-null.ts diff --git a/packages/frontend/src/components/MkButton.vue b/packages/frontend/src/components/MkButton.vue index 25b003ba5a..9560efb7d9 100644 --- a/packages/frontend/src/components/MkButton.vue +++ b/packages/frontend/src/components/MkButton.vue @@ -250,7 +250,6 @@ function onMousedown(evt: MouseEvent): void { } &:focus-visible { - outline: solid 2px var(--focus); outline-offset: 2px; } diff --git a/packages/frontend/src/components/MkChannelFollowButton.vue b/packages/frontend/src/components/MkChannelFollowButton.vue index 841d37a568..35dc3ad4bf 100644 --- a/packages/frontend/src/components/MkChannelFollowButton.vue +++ b/packages/frontend/src/components/MkChannelFollowButton.vue @@ -87,17 +87,7 @@ async function onClick() { } &:focus-visible { - &:after { - content: ""; - pointer-events: none; - position: absolute; - top: -5px; - right: -5px; - bottom: -5px; - left: -5px; - border: 2px solid var(--focus); - border-radius: 32px; - } + outline-offset: 2px; } &:hover { diff --git a/packages/frontend/src/components/MkContextMenu.vue b/packages/frontend/src/components/MkContextMenu.vue index a807742bb9..b0f6bc9d81 100644 --- a/packages/frontend/src/components/MkContextMenu.vue +++ b/packages/frontend/src/components/MkContextMenu.vue @@ -12,7 +12,7 @@ SPDX-License-Identifier: AGPL-3.0-only :leaveToClass="defaultStore.state.animation ? $style.transition_fade_leaveTo : ''" >
- +
@@ -28,6 +28,7 @@ import * as os from '@/os.js'; const props = defineProps<{ items: MenuItem[]; ev: MouseEvent; + returnFocusElement?: HTMLElement | null; }>(); const emit = defineEmits<{ diff --git a/packages/frontend/src/components/MkEmojiPicker.vue b/packages/frontend/src/components/MkEmojiPicker.vue index 4bd4bee1e5..1f7892fadb 100644 --- a/packages/frontend/src/components/MkEmojiPicker.vue +++ b/packages/frontend/src/components/MkEmojiPicker.vue @@ -702,11 +702,6 @@ defineExpose({ border-radius: 4px; font-size: 24px; - &:focus-visible { - outline: solid 2px var(--focus); - z-index: 1; - } - &:hover { background: rgba(0, 0, 0, 0.05); } diff --git a/packages/frontend/src/components/MkFollowButton.vue b/packages/frontend/src/components/MkFollowButton.vue index 6a4081079c..ea76950c0d 100644 --- a/packages/frontend/src/components/MkFollowButton.vue +++ b/packages/frontend/src/components/MkFollowButton.vue @@ -185,17 +185,7 @@ onBeforeUnmount(() => { } &:focus-visible { - &:after { - content: ""; - pointer-events: none; - position: absolute; - top: -5px; - right: -5px; - bottom: -5px; - left: -5px; - border: 2px solid var(--focus); - border-radius: 32px; - } + outline-offset: 2px; } &:hover { diff --git a/packages/frontend/src/components/MkImgWithBlurhash.vue b/packages/frontend/src/components/MkImgWithBlurhash.vue index 4e3fafe845..617404f5c4 100644 --- a/packages/frontend/src/components/MkImgWithBlurhash.vue +++ b/packages/frontend/src/components/MkImgWithBlurhash.vue @@ -14,8 +14,8 @@ SPDX-License-Identifier: AGPL-3.0-only :enterToClass="defaultStore.state.animation && props.transition?.enterToClass || undefined" :leaveFromClass="defaultStore.state.animation && props.transition?.leaveFromClass || undefined" > - - + + diff --git a/packages/frontend/src/components/MkMediaAudio.vue b/packages/frontend/src/components/MkMediaAudio.vue index e8dfcc7768..d392d1f3e9 100644 --- a/packages/frontend/src/components/MkMediaAudio.vue +++ b/packages/frontend/src/components/MkMediaAudio.vue @@ -39,23 +39,37 @@ SPDX-License-Identifier: AGPL-3.0-only
-
-
{{ hms(elapsedTimeMs) }}
- @@ -64,6 +78,10 @@ SPDX-License-Identifier: AGPL-3.0-only :class="$style.volumeSeekbar" />
+ { border-radius: var(--radius); overflow: clip; - &:focus { + &:focus-visible { outline: none; } } @@ -437,6 +455,10 @@ onDeactivated(() => { color: var(--accent); background-color: var(--accentedBg); } + + &:focus-visible { + outline: none; + } } } diff --git a/packages/frontend/src/components/MkMediaList.vue b/packages/frontend/src/components/MkMediaList.vue index b1321a8ef9..d890c5c869 100644 --- a/packages/frontend/src/components/MkMediaList.vue +++ b/packages/frontend/src/components/MkMediaList.vue @@ -39,6 +39,7 @@ import XVideo from '@/components/MkMediaVideo.vue'; import * as os from '@/os.js'; import { FILE_TYPE_BROWSERSAFE } from '@/const.js'; import { defaultStore } from '@/store.js'; +import { focusParent } from '@/scripts/tms/focus.js'; const props = defineProps<{ mediaList: Misskey.entities.DriveFile[]; @@ -49,7 +50,9 @@ const gallery = shallowRef(); const pswpZIndex = os.claimZIndex('middle'); document.documentElement.style.setProperty('--mk-pswp-root-z-index', pswpZIndex.toString()); const count = computed(() => props.mediaList.filter(media => previewable(media)).length); -let lightbox: PhotoSwipeLightbox | null; +let lightbox: PhotoSwipeLightbox | null = null; + +let activeEl: HTMLElement | null = null; const popstateHandler = (): void => { if (lightbox?.pswp && lightbox.pswp.isOpen === true) { @@ -60,7 +63,7 @@ const popstateHandler = (): void => { async function calcAspectRatio() { if (!gallery.value) return; - let img = props.mediaList[0]; + const img = props.mediaList[0]; if (props.mediaList.length !== 1 || !(img.properties.width && img.properties.height)) { gallery.value.style.aspectRatio = ''; @@ -131,6 +134,7 @@ onMounted(() => { bgOpacity: 1, showAnimationDuration: 100, hideAnimationDuration: 100, + returnFocus: false, pswpModule: PhotoSwipe, }); @@ -159,39 +163,47 @@ onMounted(() => { lightbox.on('uiRegister', () => { lightbox?.pswp?.ui?.registerElement({ name: 'altText', - className: 'pwsp__alt-text-container', + className: 'pswp__alt-text-container', appendTo: 'wrapper', - onInit: (el, pwsp) => { - let textBox = document.createElement('p'); - textBox.className = 'pwsp__alt-text _acrylic'; + onInit: (el, pswp) => { + const textBox = document.createElement('p'); + textBox.className = 'pswp__alt-text _acrylic'; el.appendChild(textBox); - pwsp.on('change', () => { - textBox.textContent = pwsp.currSlide?.data.comment; + pswp.on('change', () => { + textBox.textContent = pswp.currSlide?.data.comment; }); }, }); }); - lightbox.init(); - - window.addEventListener('popstate', popstateHandler); - - lightbox.on('beforeOpen', () => { + lightbox.on('afterInit', () => { + activeEl = document.activeElement instanceof HTMLElement ? document.activeElement : null; + focusParent(activeEl, true, true); + lightbox?.pswp?.element?.focus({ + preventScroll: true, + }); history.pushState(null, '', '#pswp'); }); - lightbox.on('close', () => { + lightbox.on('destroy', () => { + focusParent(activeEl, true, false); + activeEl = null; if (window.location.hash === '#pswp') { history.back(); } }); + + window.addEventListener('popstate', popstateHandler); + + lightbox.init(); }); onUnmounted(() => { window.removeEventListener('popstate', popstateHandler); lightbox?.destroy(); lightbox = null; + activeEl = null; }); const previewable = (file: Misskey.entities.DriveFile): boolean => { @@ -199,6 +211,16 @@ const previewable = (file: Misskey.entities.DriveFile): boolean => { // FILE_TYPE_BROWSERSAFEに適合しないものはブラウザで表示するのに不適切 return (file.type.startsWith('video') || file.type.startsWith('image')) && FILE_TYPE_BROWSERSAFE.includes(file.type); }; + +const openGallery = () => { + if (props.mediaList.filter(media => previewable(media)).length > 0) { + lightbox?.loadAndOpen(0); + } +}; + +defineExpose({ + openGallery, +});