refactor
This commit is contained in:
parent
25f719a5ec
commit
291161ca31
|
@ -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>
|
||||
|
||||
|
|
|
@ -1104,9 +1104,7 @@ onMounted(() => {
|
|||
});
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
// MkPostFormDialogでも発火しているが、Dialogではない場合は呼ばれないためこちらでも呼ぶ必要がある
|
||||
// なのでDialogの場合は2回発火されるが、ウィンドウを閉じる指示のため悪影響はない
|
||||
globalEvents.emit('requestCloseEmojiPickerWindow');
|
||||
emoijPicker.closeWindow();
|
||||
});
|
||||
|
||||
defineExpose({
|
||||
|
|
|
@ -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() {
|
||||
// MkPostFormでもonBeforeUnmountで発火しているが、Dialogの場合は閉じるまでのトランジションがあるので
|
||||
// 閉じるボタンが押された瞬間に先に発火する
|
||||
// なのでDialogの場合は2回発火されるが、ウィンドウを閉じる指示のため悪影響はない
|
||||
globalEvents.emit('requestCloseEmojiPickerWindow');
|
||||
emojiPicker.closeWindow();
|
||||
}
|
||||
|
||||
function onModalClosed() {
|
||||
|
|
|
@ -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<{
|
||||
|
|
|
@ -10,5 +10,4 @@ export const globalEvents = new EventEmitter<{
|
|||
themeChanging: () => void;
|
||||
themeChanged: () => void;
|
||||
clientNotification: (notification: Misskey.entities.Notification) => void;
|
||||
requestCloseEmojiPickerWindow: () => void;
|
||||
}>();
|
||||
|
|
|
@ -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();
|
||||
},
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -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"
|
||||
/>
|
||||
|
|
|
@ -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();
|
||||
|
|
Loading…
Reference in New Issue