This commit is contained in:
kakkokari-gtyih 2025-03-20 15:57:48 +09:00
parent 25f719a5ec
commit 291161ca31
8 changed files with 41 additions and 27 deletions

View File

@ -52,16 +52,12 @@ function chosen(emoji: string) {
const windowEl = useTemplateRef('window');
function onCloseRequested() {
function close() {
windowEl.value?.close();
}
onMounted(() => {
globalEvents.on('requestCloseEmojiPickerWindow', onCloseRequested);
});
onBeforeUnmount(() => {
globalEvents.off('requestCloseEmojiPickerWindow', onCloseRequested);
defineExpose({
close,
});
</script>

View File

@ -1104,9 +1104,7 @@ onMounted(() => {
});
onBeforeUnmount(() => {
// MkPostFormDialogDialog
// Dialog2
globalEvents.emit('requestCloseEmojiPickerWindow');
emoijPicker.closeWindow();
});
defineExpose({

View File

@ -29,7 +29,7 @@ SPDX-License-Identifier: AGPL-3.0-only
import { useTemplateRef } from 'vue';
import MkModal from '@/components/MkModal.vue';
import MkPostForm from '@/components/MkPostForm.vue';
import { globalEvents } from '@/events.js';
import { emojiPicker } from '@/utility/emoji-picker.js';
import type { PostFormProps } from '@/types/post-form.js';
const props = withDefaults(defineProps<PostFormProps & {
@ -53,10 +53,7 @@ function onPosted() {
}
function onModalClose() {
// MkPostFormonBeforeUnmountDialog
//
// Dialog2
globalEvents.emit('requestCloseEmojiPickerWindow');
emojiPicker.closeWindow();
}
function onModalClosed() {

View File

@ -11,7 +11,7 @@ SPDX-License-Identifier: AGPL-3.0-only
:width="400"
:height="500"
@close="onCloseModalWindow"
@closed="console.log('MkRoleSelectDialog: closed') ; $emit('dispose')"
@closed="emit('closed')"
>
<template #header>{{ title }}</template>
<MkSpacer :marginMin="20" :marginMax="28">
@ -58,7 +58,7 @@ import MkLoading from '@/components/global/MkLoading.vue';
const emit = defineEmits<{
(ev: 'done', value: Misskey.entities.Role[]),
(ev: 'close'),
(ev: 'dispose'),
(ev: 'closed'),
}>();
const props = withDefaults(defineProps<{

View File

@ -10,5 +10,4 @@ export const globalEvents = new EventEmitter<{
themeChanging: () => void;
themeChanged: () => void;
clientNotification: (notification: Misskey.entities.Notification) => void;
requestCloseEmojiPickerWindow: () => void;
}>();

View File

@ -5,10 +5,10 @@
// TODO: なんでもかんでもos.tsに突っ込むのやめたいのでよしなに分割する
import { markRaw, ref, defineAsyncComponent, nextTick } from 'vue';
import { markRaw, ref, shallowRef, defineAsyncComponent, nextTick } from 'vue';
import { EventEmitter } from 'eventemitter3';
import * as Misskey from 'misskey-js';
import type { Component, Ref } from 'vue';
import type { Component, Ref, ShallowRef } from 'vue';
import type { ComponentProps as CP } from 'vue-component-type-helpers';
import type { Form, GetFormResultType } from '@/utility/form.js';
import type { MenuItem } from '@/types/menu.js';
@ -141,6 +141,7 @@ let popupIdCount = 0;
export const popups = ref<{
id: number;
component: Component;
componentRef: ShallowRef<Component | null>;
props: Record<string, any>;
events: Record<string, any>;
}[]>([]);
@ -178,13 +179,21 @@ type EmitsExtractor<T> = {
[K in keyof T as K extends `onVnode${string}` ? never : K extends `on${infer E}` ? Uncapitalize<E> : K extends string ? never : K]: T[K];
};
export function popup<T extends Component>(
export function popup<
T extends Component,
TI extends T extends new (...args: unknown[]) => infer I ? I : T,
>(
component: T,
props: ComponentProps<T>,
events: ComponentEmit<T> = {} as ComponentEmit<T>,
): { dispose: () => void } {
): {
dispose: () => void;
componentRef: ShallowRef<TI | null>;
} {
markRaw(component);
const componentRef = shallowRef<TI | null>(null);
const id = ++popupIdCount;
const dispose = () => {
// このsetTimeoutが無いと挙動がおかしくなる(autocompleteが閉じなくなる)。Vueのバグ
@ -194,6 +203,7 @@ export function popup<T extends Component>(
};
const state = {
component,
componentRef,
props,
events,
id,
@ -203,6 +213,7 @@ export function popup<T extends Component>(
return {
dispose,
componentRef,
};
}
@ -627,14 +638,17 @@ export async function selectRole(params: {
{ canceled: false; result: Misskey.entities.Role[] }
> {
return new Promise((resolve) => {
popup(defineAsyncComponent(() => import('@/components/MkRoleSelectDialog.vue')), params, {
const { dispose } = popup(defineAsyncComponent(() => import('@/components/MkRoleSelectDialog.vue')), params, {
done: roles => {
resolve({ canceled: false, result: roles });
},
close: () => {
resolve({ canceled: true, result: undefined });
},
}, 'dispose');
closed: () => {
dispose();
},
});
});
}

View File

@ -8,6 +8,7 @@ SPDX-License-Identifier: AGPL-3.0-only
:is="popup.component"
v-for="popup in popups"
:key="popup.id"
:ref="(el: Component | null) => popup.componentRef = el"
v-bind="popup.props"
v-on="popup.events"
/>

View File

@ -3,8 +3,9 @@
* SPDX-License-Identifier: AGPL-3.0-only
*/
import { defineAsyncComponent, ref, watch } from 'vue';
import type { Ref } from 'vue';
import { defineAsyncComponent, ref, shallowRef, watch } from 'vue';
import type { Ref, ShallowRef } from 'vue';
import type MkEmojiPickerWindow_TypeOnly from '@/components/MkEmojiPickerWindow.vue';
import { popup } from '@/os.js';
import { prefer } from '@/preferences.js';
@ -18,6 +19,7 @@ class EmojiPicker {
private src: Ref<HTMLElement | null> = ref(null);
private isWindow: boolean = false;
private windowComponentEl: ShallowRef<InstanceType<typeof MkEmojiPickerWindow_TypeOnly> | null> = shallowRef(null);
private windowShowing: boolean = false;
private dialogShowing = ref(false);
@ -73,7 +75,7 @@ class EmojiPicker {
if (this.isWindow) {
if (this.windowShowing) return;
this.windowShowing = true;
const { dispose } = popup(defineAsyncComponent(() => import('@/components/MkEmojiPickerWindow.vue')), {
const { dispose, componentRef } = popup(defineAsyncComponent(() => import('@/components/MkEmojiPickerWindow.vue')), {
src: opts.src,
pinnedEmojis: this.emojisRef,
asReactionPicker: false,
@ -87,6 +89,7 @@ class EmojiPicker {
dispose();
},
});
this.windowComponentEl.value = componentRef.value;
} else {
this.src.value = opts.src;
this.dialogShowing.value = true;
@ -94,6 +97,12 @@ class EmojiPicker {
this.onClosed = opts.onClosed;
}
}
public closeWindow() {
if (this.isWindow && this.windowComponentEl.value) {
this.windowComponentEl.value.close();
}
}
}
export const emojiPicker = new EmojiPicker();