Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(frontend): フォーカス/タブ移動に関する挙動を調整 #226

Merged
merged 1 commit into from
Jun 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion packages/frontend/src/components/MkButton.vue
Original file line number Diff line number Diff line change
Expand Up @@ -249,7 +249,6 @@ function onMousedown(evt: MouseEvent): void {
}

&:focus-visible {
outline: solid 2px var(--focus);
outline-offset: 2px;
}

Expand Down
12 changes: 1 addition & 11 deletions packages/frontend/src/components/MkChannelFollowButton.vue
Original file line number Diff line number Diff line change
Expand Up @@ -86,17 +86,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 {
Expand Down
3 changes: 2 additions & 1 deletion packages/frontend/src/components/MkContextMenu.vue
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ SPDX-License-Identifier: AGPL-3.0-only
:leaveToClass="defaultStore.state.animation ? $style.transition_fade_leaveTo : ''"
>
<div ref="rootEl" :class="$style.root" :style="{ zIndex }" @contextmenu.prevent.stop="() => {}">
<MkMenu :items="items" :align="'left'" @close="emit('closed')"/>
<MkMenu :items="items" :align="'left'" :returnFocusElement="returnFocusElement" @close="emit('closed')"/>
</div>
</Transition>
</template>
Expand All @@ -28,6 +28,7 @@ import * as os from '@/os.js';
const props = defineProps<{
items: MenuItem[];
ev: MouseEvent;
returnFocusElement?: HTMLElement | null;
}>();

const emit = defineEmits<{
Expand Down
5 changes: 0 additions & 5 deletions packages/frontend/src/components/MkEmojiPicker.vue
Original file line number Diff line number Diff line change
Expand Up @@ -700,11 +700,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);
}
Expand Down
12 changes: 1 addition & 11 deletions packages/frontend/src/components/MkFollowButton.vue
Original file line number Diff line number Diff line change
Expand Up @@ -183,17 +183,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 {
Expand Down
4 changes: 2 additions & 2 deletions packages/frontend/src/components/MkImgWithBlurhash.vue
Original file line number Diff line number Diff line change
Expand Up @@ -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"
>
<canvas v-show="hide" key="canvas" ref="canvas" :class="$style.canvas" :width="canvasWidth" :height="canvasHeight" :title="title ?? undefined"/>
<img v-show="!hide" key="img" ref="img" :height="imgHeight ?? undefined" :width="imgWidth ?? undefined" :class="$style.img" :src="src ?? undefined" :title="title ?? undefined" :alt="alt ?? undefined" loading="eager" decoding="async"/>
<canvas v-show="hide" key="canvas" ref="canvas" :class="$style.canvas" :width="canvasWidth" :height="canvasHeight" :title="title ?? undefined" tabindex="-1"/>
<img v-show="!hide" key="img" ref="img" :height="imgHeight ?? undefined" :width="imgWidth ?? undefined" :class="$style.img" :src="src ?? undefined" :title="title ?? undefined" :alt="alt ?? undefined" loading="eager" decoding="async" tabindex="-1"/>
</TransitionGroup>
</div>
</template>
Expand Down
25 changes: 21 additions & 4 deletions packages/frontend/src/components/MkMediaAudio.vue
Original file line number Diff line number Diff line change
Expand Up @@ -61,19 +61,32 @@ SPDX-License-Identifier: AGPL-3.0-only
<source :src="audioRef.url">
</audio>
<div :class="[$style.controlsChild, $style.controlsLeft]">
<button class="_button" :class="$style.controlButton" @click.stop="togglePlayPause">
<button
:class="['_button', $style.controlButton]"
tabindex="-1"
@click.stop="togglePlayPause"
>
<i v-if="isPlaying" class="ti ti-player-pause-filled"></i>
<i v-else class="ti ti-player-play-filled"></i>
</button>
</div>
<div :class="[$style.controlsChild, $style.controlsRight]">
<button class="_button" :class="$style.controlButton" @click.stop="showAudioMenu">
<button
:class="['_button', $style.controlButton]"
tabindex="-1"
@click.stop="() => {}"
@mousedown.prevent.stop="showAudioMenu"
>
<i class="ti ti-settings"></i>
</button>
</div>
<div :class="[$style.controlsChild, $style.controlsTime]">{{ hms(elapsedTimeMs) }}</div>
<div :class="[$style.controlsChild, $style.controlsVolume]">
<button class="_button" :class="$style.controlButton" @click.stop="toggleMute">
<button
:class="['_button', $style.controlButton]"
tabindex="-1"
@click.stop="toggleMute"
>
<i v-if="volume === 0" class="ti ti-volume-3"></i>
<i v-else class="ti ti-volume"></i>
</button>
Expand Down Expand Up @@ -366,7 +379,7 @@ onDeactivated(() => {
border: 0.5px solid var(--divider);
border-radius: var(--mediaList-radius, 8px);

&:focus {
&:focus-visible {
outline: none;
}
}
Expand Down Expand Up @@ -445,6 +458,10 @@ onDeactivated(() => {
color: var(--accent);
background-color: var(--accentedBg);
}

&:focus-visible {
outline: none;
}
}
}

Expand Down
13 changes: 11 additions & 2 deletions packages/frontend/src/components/MkMediaBanner.vue
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,12 @@ SPDX-License-Identifier: AGPL-3.0-only
</div>
<div :class="$style.downloadText">{{ mediaRef.name }}</div>
</a>
<button :class="['_button', $style.downloadMenu]" @click.stop="showMediaMenu">
<button
:class="['_button', $style.downloadMenu]"
tabindex="-1"
@click.stop="() => {}"
@mousedown.prevent.stop="showMediaMenu"
>
<i class="ti ti-settings"></i>
</button>
</div>
Expand Down Expand Up @@ -112,7 +117,7 @@ const showMediaMenu = (ev: MouseEvent) => {
border: 0.5px solid var(--divider);
border-radius: var(--mediaList-radius, 8px);

&:focus {
&:focus-visible {
outline: none;
}
}
Expand Down Expand Up @@ -215,6 +220,10 @@ const showMediaMenu = (ev: MouseEvent) => {
color: var(--accent);
background-color: var(--accentedBg);
}

&:focus-visible {
outline: none;
}
}

@container mediaBanner (max-width: 250px) {
Expand Down
25 changes: 21 additions & 4 deletions packages/frontend/src/components/MkMediaImage.vue
Original file line number Diff line number Diff line change
Expand Up @@ -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"
>
<MkImgWithBlurhash
:hash="imageRef.blurhash"
Expand Down Expand Up @@ -66,8 +67,9 @@ SPDX-License-Identifier: AGPL-3.0-only
<template v-else-if="props.controls">
<div :class="$style.controlsUpperRight">
<button
:class="['_button', $style.controlItem]"
v-tooltip="i18n.ts.hide"
:class="['_button', $style.controlItem]"
tabindex="-1"
@click.stop="hideRef = true"
>
<div :class="$style.controlButton"><i class="ti ti-eye-off"></i></div>
Expand All @@ -77,8 +79,9 @@ SPDX-License-Identifier: AGPL-3.0-only
<div :class="$style.controlsLowerRight">
<button
:class="['_button', $style.controlItem]"
v-tooltip="i18n.ts.menu"
@click.stop="showImageMenu"
tabindex="-1"
@click.stop="() => {}"
@mousedown.prevent.stop="showImageMenu"
>
<div :class="$style.controlButton"><i class="ti ti-dots"></i></div>
</button>
Expand All @@ -89,6 +92,8 @@ SPDX-License-Identifier: AGPL-3.0-only
v-if="imageRef.comment"
v-tooltip:dialog="imageRef.comment"
:class="['_button', $style.controlItem]"
tabindex="-1"
@click.stop="() => {}"
>
<div :class="$style.controlButton"><span>ALT</span></div>
</button>
Expand All @@ -99,13 +104,17 @@ SPDX-License-Identifier: AGPL-3.0-only
v-if="['image/gif', 'image/apng'].includes(imageRef.type)"
v-tooltip:dialog="i18n.ts._tms.displayingGifFiles"
:class="['_button', $style.controlItem]"
tabindex="-1"
@click.stop="() => {}"
>
<div :class="$style.controlButton"><span>GIF</span></div>
</button>
<button
v-if="imageRef.isSensitive"
v-tooltip:dialog="i18n.ts._tms.displayingSensitiveFiles"
:class="['_button', $style.controlItem]"
tabindex="-1"
@click.stop="() => {}"
>
<div :class="$style.controlButton"><span>NSFW</span></div>
</button>
Expand Down Expand Up @@ -196,6 +205,10 @@ const showImageMenu = (ev: MouseEvent) => {
overflow: hidden; // fallback (overflow: clip)
overflow: clip;
border-radius: var(--mediaList-radius, 8px);

&:focus-visible {
outline: none;
}
}

.rootVisible {
Expand Down Expand Up @@ -296,6 +309,10 @@ const showImageMenu = (ev: MouseEvent) => {
&:last-child {
padding-right: clamp(4px, calc(8px * var(--mediaImage-scale)), 8px);
}

&:focus-visible {
outline: none;
}
}

.controlsUpperRight {
Expand Down
54 changes: 38 additions & 16 deletions packages/frontend/src/components/MkMediaList.vue
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ import 'photoswipe/style.css';
import { FILE_TYPE_BROWSERSAFE } from '@/const.js';
import { claimZIndex } from '@/os.js';
import { defaultStore } from '@/store.js';
import { focusParent } from '@/scripts/tms/focus.js';
import XAudio from '@/components/MkMediaAudio.vue';
import XBanner from '@/components/MkMediaBanner.vue';
import XImage from '@/components/MkMediaImage.vue';
Expand All @@ -55,7 +56,9 @@ const gallery = shallowRef<HTMLDivElement>();
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) {
Expand All @@ -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 = '';
Expand Down Expand Up @@ -141,6 +144,7 @@ onMounted(() => {
bgOpacity: 1,
showAnimationDuration: 100,
hideAnimationDuration: 100,
returnFocus: false,
pswpModule: PhotoSwipe,
});

Expand Down Expand Up @@ -169,46 +173,64 @@ 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 => {
if (file.type === 'image/svg+xml') return true; // svgのwebpublic/thumbnailはpngなのでtrue
// 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,
});
</script>

<style lang="scss" module>
Expand Down Expand Up @@ -331,7 +353,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;
Expand All @@ -345,7 +367,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;
Expand Down
Loading