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

View File

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

View File

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

View File

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

View File

@ -108,6 +108,7 @@ onMounted(() => {
}, },
imageClickAction: "close", imageClickAction: "close",
tapAction: "toggle-controls", tapAction: "toggle-controls",
preloadFirstSlide: false,
pswpModule: PhotoSwipe, 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(); lightbox.init();
function close() {
removeEventListener("popstate", close);
history.forward();
lightbox.pswp.close();
}
}); });
const previewable = (file: misskey.entities.DriveFile): boolean => { const previewable = (file: misskey.entities.DriveFile): boolean => {

View File

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

View File

@ -51,7 +51,7 @@
</button> </button>
</div> </div>
<div class="body"> <div class="body">
<slot :width="bodyWidth" :height="bodyHeight"></slot> <slot></slot>
</div> </div>
</div> </div>
</FocusTrap> </FocusTrap>
@ -59,7 +59,6 @@
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { onMounted, onUnmounted } from "vue";
import { FocusTrap } from "focus-trap-vue"; import { FocusTrap } from "focus-trap-vue";
import MkModal from "./MkModal.vue"; import MkModal from "./MkModal.vue";
@ -90,8 +89,6 @@ const emit = defineEmits<{
let modal = $shallowRef<InstanceType<typeof MkModal>>(); let modal = $shallowRef<InstanceType<typeof MkModal>>();
let rootEl = $shallowRef<HTMLElement>(); let rootEl = $shallowRef<HTMLElement>();
let headerEl = $shallowRef<HTMLElement>(); let headerEl = $shallowRef<HTMLElement>();
let bodyWidth = $ref(0);
let bodyHeight = $ref(0);
const close = () => { const close = () => {
modal.close(); modal.close();
@ -101,30 +98,6 @@ const onBgClick = () => {
emit("click"); 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({ defineExpose({
close, close,
}); });

View File

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

View File

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

View File

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

View File

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