Merge pull request 'More focusable elements + allow closing modal's w/ browser back & esc' (#10142) from Freeplay/calckey:keyboard into develop

Reviewed-on: https://codeberg.org/calckey/calckey/pulls/10142
This commit is contained in:
Kainoa Kanter 2023-05-18 05:43:55 +00:00
commit 3fc94f9348
11 changed files with 69 additions and 44 deletions

View file

@ -1,7 +1,6 @@
<template>
<MkA
class="rivslvers"
tabindex="-1"
:class="{
isMe: isMe(message),
isRead: message.groupId
@ -27,6 +26,7 @@
: message.user
"
:show-indicator="true"
disableLink
/>
<header v-if="message.groupId">
<span class="name">{{ message.group.name }}</span>

View file

@ -59,6 +59,7 @@ defineExpose({
<style lang="scss" scoped>
._button {
font-weight: 700;
z-index: 2;
> span {
background: var(--cwBg) !important;
color: var(--cwFg);

View file

@ -1,5 +1,5 @@
<template>
<MkA :to="`/gallery/${post.id}`" class="ttasepnz _panel" tabindex="-1">
<MkA :to="`/gallery/${post.id}`" class="ttasepnz _panel">
<div class="thumbnail">
<ImgWithBlurhash
class="img"
@ -34,7 +34,7 @@ const props = defineProps<{
position: relative;
height: 200px;
&:hover {
&:hover, &:focus {
text-decoration: none;
color: var(--accent);

View file

@ -1,5 +1,5 @@
<template>
<div class="mk-media-banner">
<div class="mk-media-banner" @click.stop>
<div
v-if="media.isSensitive && hide"
class="sensitive"

View file

@ -108,6 +108,7 @@ onMounted(() => {
},
imageClickAction: "close",
tapAction: "toggle-controls",
preloadFirstSlide: false,
pswpModule: PhotoSwipe,
});
@ -162,7 +163,24 @@ onMounted(() => {
});
});
lightbox.on("afterInit", () => {
history.pushState(null, "", location.href);
addEventListener("popstate", close);
// This is a workaround. Not sure why, but when clicking to open, it doesn't move focus to the photoswipe. Preventing using esc to close. However when using keyboard to open it already focuses the lightbox fine.
lightbox.pswp.element.focus();
})
lightbox.on("close", () => {
removeEventListener("popstate", close);
history.back();
})
lightbox.init();
function close() {
removeEventListener("popstate", close);
history.forward();
lightbox.pswp.close();
}
});
const previewable = (file: misskey.entities.DriveFile): boolean => {

View file

@ -74,7 +74,7 @@
</template>
<script lang="ts" setup>
import { nextTick, onMounted, watch, provide } from "vue";
import { nextTick, onMounted, watch, provide, onUnmounted } from "vue";
import * as os from "@/os";
import { isTouchUsing } from "@/scripts/touch";
import { defaultStore } from "@/store";
@ -176,7 +176,11 @@ let transitionDuration = $computed(() =>
let contentClicking = false;
const focusedElement = document.activeElement;
function close(opts: { useSendAnimation?: boolean } = {}) {
function close(ev, opts: { useSendAnimation?: boolean } = {}) {
removeEventListener("popstate", close);
if (props.preferType == "dialog") {
history.forward();
}
if (opts.useSendAnimation) {
useSendAnime = true;
}
@ -354,6 +358,10 @@ const onOpened = () => {
},
{ passive: true }
);
if (props.preferType == "dialog") {
history.pushState(null, "", location.href);
}
addEventListener("popstate", close);
};
onMounted(() => {
@ -379,6 +387,12 @@ onMounted(() => {
}).observe(content!);
});
});
onUnmounted(() => {
removeEventListener("popstate", close);
if (props.preferType == "dialog") {
history.back();
}
});
defineExpose({
close,

View file

@ -51,7 +51,7 @@
</button>
</div>
<div class="body">
<slot :width="bodyWidth" :height="bodyHeight"></slot>
<slot></slot>
</div>
</div>
</FocusTrap>
@ -59,7 +59,6 @@
</template>
<script lang="ts" setup>
import { onMounted, onUnmounted } from "vue";
import { FocusTrap } from "focus-trap-vue";
import MkModal from "./MkModal.vue";
@ -90,8 +89,6 @@ const emit = defineEmits<{
let modal = $shallowRef<InstanceType<typeof MkModal>>();
let rootEl = $shallowRef<HTMLElement>();
let headerEl = $shallowRef<HTMLElement>();
let bodyWidth = $ref(0);
let bodyHeight = $ref(0);
const close = () => {
modal.close();
@ -101,30 +98,6 @@ const onBgClick = () => {
emit("click");
};
const onKeydown = (evt) => {
if (evt.which === 27) {
// Esc
evt.preventDefault();
evt.stopPropagation();
close();
}
};
const ro = new ResizeObserver((entries, observer) => {
bodyWidth = rootEl.offsetWidth;
bodyHeight = rootEl.offsetHeight - headerEl.offsetHeight;
});
onMounted(() => {
bodyWidth = rootEl.offsetWidth;
bodyHeight = rootEl.offsetHeight - headerEl.offsetHeight;
ro.observe(rootEl);
});
onUnmounted(() => {
ro.disconnect();
});
defineExpose({
close,
});

View file

@ -1,18 +1,18 @@
<template>
<button v-if="modelValue" class="fade _button" @click.stop="toggle">
<span>{{ i18n.ts.showMore }}</span>
</button>
<button v-if="!modelValue" class="showLess _button" @click.stop="toggle">
<span>{{ i18n.ts.showLess }}</span>
<button ref="el" class="_button" :class="{ fade: modelValue, showLess: !modelValue }" @click.stop="toggle">
<span>{{ modelValue ? i18n.ts.showMore : i18n.ts.showLess }}</span>
</button>
</template>
<script lang="ts" setup>
import { i18n } from "@/i18n";
import { ref } from "vue";
const props = defineProps<{
modelValue: boolean;
}>();
const el = ref<HTMLElement>();
const emit = defineEmits<{
(ev: "update:modelValue", v: boolean): void;
}>();
@ -20,6 +20,14 @@ const emit = defineEmits<{
const toggle = () => {
emit("update:modelValue", !props.modelValue);
};
function focus() {
el.value.focus();
}
defineExpose({
focus,
});
</script>
<style lang="scss" scoped>
.fade {
@ -28,6 +36,7 @@ const toggle = () => {
bottom: 0;
left: 0;
width: 100%;
z-index: 2;
> span {
display: inline-block;
background: var(--panel);

View file

@ -40,6 +40,12 @@
disableAnim: disableMfm,
}"
>
<XShowMoreButton
ref="showMoreButton"
v-if="isLong && collapsed"
v-model="collapsed"
v-on:keydown="focusFooter"
></XShowMoreButton>
<XCwButton
ref="cwButton"
v-if="note.cw && !showContent"
@ -50,7 +56,7 @@
<div
class="body"
v-bind="{
'aria-label': !showContent ? '' : null,
'aria-hidden': !showContent ? 'true' : null,
tabindex: !showContent ? '-1' : null,
}"
>
@ -115,16 +121,16 @@
</div>
</template>
<div
v-if="note.cw && !showContent"
v-if="note.cw && !showContent || showMoreButton && collapsed"
tabindex="0"
v-on:focus="cwButton?.focus()"
v-on:focus="cwButton?.focus(); showMoreButton?.focus()"
></div>
</div>
<XShowMoreButton
v-if="isLong"
v-if="isLong && !collapsed"
v-model="collapsed"
></XShowMoreButton>
<XCwButton v-if="note.cw" v-model="showContent" :note="note" />
<XCwButton v-if="note.cw && showContent" v-model="showContent" :note="note" />
</div>
<MkButton
v-if="hasMfm && defaultStore.state.animatedMfm"
@ -171,6 +177,7 @@ const emit = defineEmits<{
}>();
const cwButton = ref<HTMLElement>();
const showMoreButton = ref<HTMLElement>();
const isLong =
!props.detailedView &&
props.note.cw == null &&

View file

@ -15,6 +15,8 @@
v-on:change="(x) => onChange(x)"
@focus="tooltipShow"
@blur="tooltipHide"
@touchstart="tooltipShow"
@touchend="tooltipHide"
@mouseenter="tooltipShow"
@mouseleave="tooltipHide"
@input="(x) => (inputVal = x.target.value)"

View file

@ -52,6 +52,7 @@ html {
line-height: 1.6;
text-size-adjust: 100%;
tab-size: 2;
scroll-padding: 60px;
&.f-1 {
font-size: 15px;