merge: upstream

This commit is contained in:
Marie 2024-02-03 20:19:44 +01:00
commit 11628e4b6a
No known key found for this signature in database
GPG key ID: 56569BBE47D2C828
285 changed files with 3413 additions and 1913 deletions

View file

@ -12,7 +12,7 @@ SPDX-License-Identifier: AGPL-3.0-only
:style="{ width: (width && !asDrawer) ? width + 'px' : '', maxHeight: maxHeight ? maxHeight + 'px' : '' }"
@contextmenu.self="e => e.preventDefault()"
>
<template v-for="(item, i) in items2">
<template v-for="(item, i) in (items2 ?? [])">
<div v-if="item.type === 'divider'" role="separator" :class="$style.divider"></div>
<span v-else-if="item.type === 'label'" role="menuitem" :class="[$style.label, $style.item]">
<span style="opacity: 0.7;">{{ item.text }}</span>
@ -54,7 +54,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<span :class="$style.caret" style="pointer-events: none;"><i class="ph-caret-right ph-bold ph-lg ti-fw"></i></span>
</div>
</button>
<button v-else :tabindex="i" class="_button" role="menuitem" :class="[$style.item, { [$style.danger]: item.danger, [$style.active]: item.active }]" :disabled="item.active" @click="clicked(item.action, $event)" @mouseenter.passive="onItemMouseEnter(item)" @mouseleave.passive="onItemMouseLeave(item)">
<button v-else :tabindex="i" class="_button" role="menuitem" :class="[$style.item, { [$style.danger]: item.danger, [$style.active]: getValue(item.active) }]" :disabled="getValue(item.active)" @click="clicked(item.action, $event)" @mouseenter.passive="onItemMouseEnter(item)" @mouseleave.passive="onItemMouseLeave(item)">
<i v-if="item.icon" class="ti-fw" :class="[$style.icon, item.icon]"></i>
<MkAvatar v-if="item.avatar" :user="item.avatar" :class="$style.avatar"/>
<div :class="$style.item_content">
@ -63,18 +63,18 @@ SPDX-License-Identifier: AGPL-3.0-only
</div>
</button>
</template>
<span v-if="items2.length === 0" :class="[$style.none, $style.item]">
<span v-if="items2 == null || items2.length === 0" :class="[$style.none, $style.item]">
<span>{{ i18n.ts.none }}</span>
</span>
</div>
<div v-if="childMenu">
<XChild ref="child" :items="childMenu" :targetElement="childTarget" :rootElement="itemsEl" showing @actioned="childActioned" @close="close(false)"/>
<XChild ref="child" :items="childMenu" :targetElement="childTarget!" :rootElement="itemsEl!" showing @actioned="childActioned" @close="close(false)"/>
</div>
</div>
</template>
<script lang="ts">
import { computed, defineAsyncComponent, nextTick, onBeforeUnmount, onMounted, ref, shallowRef, watch } from 'vue';
import { ComputedRef, computed, defineAsyncComponent, isRef, nextTick, onBeforeUnmount, onMounted, ref, shallowRef, watch } from 'vue';
import { focusPrev, focusNext } from '@/scripts/focus.js';
import MkSwitchButton from '@/components/MkSwitch.button.vue';
import { MenuItem, InnerMenuItem, MenuPending, MenuAction, MenuSwitch, MenuParent } from '@/types/menu.js';
@ -104,7 +104,7 @@ const emit = defineEmits<{
const itemsEl = shallowRef<HTMLDivElement>();
const items2 = ref<InnerMenuItem[]>([]);
const items2 = ref<InnerMenuItem[]>();
const child = shallowRef<InstanceType<typeof XChild>>();
@ -119,15 +119,15 @@ const childShowingItem = ref<MenuItem | null>();
let preferClick = isTouchUsing || props.asDrawer;
watch(() => props.items, () => {
const items: (MenuItem | MenuPending)[] = [...props.items].filter(item => item !== undefined);
const items = [...props.items].filter(item => item !== undefined) as (NonNullable<MenuItem> | MenuPending)[];
for (let i = 0; i < items.length; i++) {
const item = items[i];
if (item && 'then' in item) { // if item is Promise
if ('then' in item) { // if item is Promise
items[i] = { type: 'pending' };
item.then(actualItem => {
items2.value[i] = actualItem;
if (items2.value?.[i]) items2.value[i] = actualItem;
});
}
}
@ -151,7 +151,7 @@ function childActioned() {
}
const onGlobalMousedown = (event: MouseEvent) => {
if (childTarget.value && (event.target === childTarget.value || childTarget.value.contains(event.target))) return;
if (childTarget.value && (event.target === childTarget.value || childTarget.value.contains(event.target as Node))) return;
if (child.value && child.value.checkHit(event)) return;
closeChild();
};
@ -169,7 +169,7 @@ function onItemMouseLeave(item) {
}
async function showChildren(item: MenuParent, ev: MouseEvent) {
const children = await (async () => {
const children: MenuItem[] = await (async () => {
if (childrenCache.has(item)) {
return childrenCache.get(item)!;
} else {
@ -189,7 +189,7 @@ async function showChildren(item: MenuParent, ev: MouseEvent) {
});
emit('hide');
} else {
childTarget.value = ev.currentTarget ?? ev.target;
childTarget.value = (ev.currentTarget ?? ev.target) as HTMLElement;
//
childMenu.value = children;
childShowingItem.value = item;
@ -218,6 +218,10 @@ function switchItem(item: MenuSwitch & { ref: any }) {
item.ref = !item.ref;
}
function getValue<T>(item?: ComputedRef<T> | T) {
return isRef(item) ? item.value : item;
}
onMounted(() => {
if (props.viaKeyboard) {
nextTick(() => {