diff --git a/packages/frontend/src/components/MkImgWithBlurhash.vue b/packages/frontend/src/components/MkImgWithBlurhash.vue
index d40bf19f0dda..8ba48ae3fbf4 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/MkMediaImage.vue b/packages/frontend/src/components/MkMediaImage.vue
index 2e91e823126e..007180b16fa8 100644
--- a/packages/frontend/src/components/MkMediaImage.vue
+++ b/packages/frontend/src/components/MkMediaImage.vue
@@ -24,8 +24,9 @@ SPDX-License-Identifier: AGPL-3.0-only
title: imageRef.name,
class: $style.imageContainer,
href: imageRef.url,
- style: 'cursor: zoom-in;'
+ style: 'cursor: zoom-in;',
}"
+ tabindex="-1"
>
{
overflow: hidden; // fallback (overflow: clip)
overflow: clip;
border-radius: var(--mediaList-radius, 8px);
+
+ &:focus {
+ outline: none;
+ }
}
.rootVisible {
diff --git a/packages/frontend/src/components/MkMediaList.vue b/packages/frontend/src/components/MkMediaList.vue
index d9d2541fe21c..3637497063a7 100644
--- a/packages/frontend/src/components/MkMediaList.vue
+++ b/packages/frontend/src/components/MkMediaList.vue
@@ -43,6 +43,7 @@ import XAudio from '@/components/MkMediaAudio.vue';
import XBanner from '@/components/MkMediaBanner.vue';
import XImage from '@/components/MkMediaImage.vue';
import XVideo from '@/components/MkMediaVideo.vue';
+import { focusParent } from '@/scripts/focus.js';
const EXPANDED_MIN_HEIGHT = 80 as const;
@@ -55,7 +56,9 @@ const gallery = shallowRef();
const pswpZIndex = 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) {
@@ -66,7 +69,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 = '';
@@ -141,6 +144,7 @@ onMounted(() => {
bgOpacity: 1,
showAnimationDuration: 100,
hideAnimationDuration: 100,
+ returnFocus: false,
pswpModule: PhotoSwipe,
});
@@ -169,39 +173,46 @@ 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;
+ 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 => {
@@ -331,7 +342,7 @@ const previewable = (file: Misskey.entities.DriveFile): boolean => {
backdrop-filter: var(--modalBgFilter);
}
-.pwsp__alt-text-container {
+.pswp__alt-text-container {
display: flex;
flex-direction: row;
align-items: center;
@@ -345,7 +356,7 @@ const previewable = (file: Misskey.entities.DriveFile): boolean => {
max-width: 800px;
}
-.pwsp__alt-text {
+.pswp__alt-text {
color: var(--fg);
margin: 0 auto;
text-align: center;
diff --git a/packages/frontend/src/components/MkMenu.child.vue b/packages/frontend/src/components/MkMenu.child.vue
index dfb6d346182e..cc2de91d4e73 100644
--- a/packages/frontend/src/components/MkMenu.child.vue
+++ b/packages/frontend/src/components/MkMenu.child.vue
@@ -10,7 +10,7 @@ SPDX-License-Identifier: AGPL-3.0-only