refactor
This commit is contained in:
parent
25f719a5ec
commit
291161ca31
packages/frontend/src
|
@ -52,16 +52,12 @@ function chosen(emoji: string) {
|
||||||
|
|
||||||
const windowEl = useTemplateRef('window');
|
const windowEl = useTemplateRef('window');
|
||||||
|
|
||||||
function onCloseRequested() {
|
function close() {
|
||||||
windowEl.value?.close();
|
windowEl.value?.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
onMounted(() => {
|
defineExpose({
|
||||||
globalEvents.on('requestCloseEmojiPickerWindow', onCloseRequested);
|
close,
|
||||||
});
|
|
||||||
|
|
||||||
onBeforeUnmount(() => {
|
|
||||||
globalEvents.off('requestCloseEmojiPickerWindow', onCloseRequested);
|
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
|
@ -1104,9 +1104,7 @@ onMounted(() => {
|
||||||
});
|
});
|
||||||
|
|
||||||
onBeforeUnmount(() => {
|
onBeforeUnmount(() => {
|
||||||
// MkPostFormDialogでも発火しているが、Dialogではない場合は呼ばれないためこちらでも呼ぶ必要がある
|
emoijPicker.closeWindow();
|
||||||
// なのでDialogの場合は2回発火されるが、ウィンドウを閉じる指示のため悪影響はない
|
|
||||||
globalEvents.emit('requestCloseEmojiPickerWindow');
|
|
||||||
});
|
});
|
||||||
|
|
||||||
defineExpose({
|
defineExpose({
|
||||||
|
|
|
@ -29,7 +29,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
import { useTemplateRef } from 'vue';
|
import { useTemplateRef } from 'vue';
|
||||||
import MkModal from '@/components/MkModal.vue';
|
import MkModal from '@/components/MkModal.vue';
|
||||||
import MkPostForm from '@/components/MkPostForm.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';
|
import type { PostFormProps } from '@/types/post-form.js';
|
||||||
|
|
||||||
const props = withDefaults(defineProps<PostFormProps & {
|
const props = withDefaults(defineProps<PostFormProps & {
|
||||||
|
@ -53,10 +53,7 @@ function onPosted() {
|
||||||
}
|
}
|
||||||
|
|
||||||
function onModalClose() {
|
function onModalClose() {
|
||||||
// MkPostFormでもonBeforeUnmountで発火しているが、Dialogの場合は閉じるまでのトランジションがあるので
|
emojiPicker.closeWindow();
|
||||||
// 閉じるボタンが押された瞬間に先に発火する
|
|
||||||
// なのでDialogの場合は2回発火されるが、ウィンドウを閉じる指示のため悪影響はない
|
|
||||||
globalEvents.emit('requestCloseEmojiPickerWindow');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function onModalClosed() {
|
function onModalClosed() {
|
||||||
|
|
|
@ -11,7 +11,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
:width="400"
|
:width="400"
|
||||||
:height="500"
|
:height="500"
|
||||||
@close="onCloseModalWindow"
|
@close="onCloseModalWindow"
|
||||||
@closed="console.log('MkRoleSelectDialog: closed') ; $emit('dispose')"
|
@closed="emit('closed')"
|
||||||
>
|
>
|
||||||
<template #header>{{ title }}</template>
|
<template #header>{{ title }}</template>
|
||||||
<MkSpacer :marginMin="20" :marginMax="28">
|
<MkSpacer :marginMin="20" :marginMax="28">
|
||||||
|
@ -58,7 +58,7 @@ import MkLoading from '@/components/global/MkLoading.vue';
|
||||||
const emit = defineEmits<{
|
const emit = defineEmits<{
|
||||||
(ev: 'done', value: Misskey.entities.Role[]),
|
(ev: 'done', value: Misskey.entities.Role[]),
|
||||||
(ev: 'close'),
|
(ev: 'close'),
|
||||||
(ev: 'dispose'),
|
(ev: 'closed'),
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const props = withDefaults(defineProps<{
|
const props = withDefaults(defineProps<{
|
||||||
|
|
|
@ -10,5 +10,4 @@ export const globalEvents = new EventEmitter<{
|
||||||
themeChanging: () => void;
|
themeChanging: () => void;
|
||||||
themeChanged: () => void;
|
themeChanged: () => void;
|
||||||
clientNotification: (notification: Misskey.entities.Notification) => void;
|
clientNotification: (notification: Misskey.entities.Notification) => void;
|
||||||
requestCloseEmojiPickerWindow: () => void;
|
|
||||||
}>();
|
}>();
|
||||||
|
|
|
@ -5,10 +5,10 @@
|
||||||
|
|
||||||
// TODO: なんでもかんでもos.tsに突っ込むのやめたいのでよしなに分割する
|
// TODO: なんでもかんでもos.tsに突っ込むのやめたいのでよしなに分割する
|
||||||
|
|
||||||
import { markRaw, ref, defineAsyncComponent, nextTick } from 'vue';
|
import { markRaw, ref, shallowRef, defineAsyncComponent, nextTick } from 'vue';
|
||||||
import { EventEmitter } from 'eventemitter3';
|
import { EventEmitter } from 'eventemitter3';
|
||||||
import * as Misskey from 'misskey-js';
|
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 { ComponentProps as CP } from 'vue-component-type-helpers';
|
||||||
import type { Form, GetFormResultType } from '@/utility/form.js';
|
import type { Form, GetFormResultType } from '@/utility/form.js';
|
||||||
import type { MenuItem } from '@/types/menu.js';
|
import type { MenuItem } from '@/types/menu.js';
|
||||||
|
@ -141,6 +141,7 @@ let popupIdCount = 0;
|
||||||
export const popups = ref<{
|
export const popups = ref<{
|
||||||
id: number;
|
id: number;
|
||||||
component: Component;
|
component: Component;
|
||||||
|
componentRef: ShallowRef<Component | null>;
|
||||||
props: Record<string, any>;
|
props: Record<string, any>;
|
||||||
events: 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];
|
[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,
|
component: T,
|
||||||
props: ComponentProps<T>,
|
props: ComponentProps<T>,
|
||||||
events: ComponentEmit<T> = {} as ComponentEmit<T>,
|
events: ComponentEmit<T> = {} as ComponentEmit<T>,
|
||||||
): { dispose: () => void } {
|
): {
|
||||||
|
dispose: () => void;
|
||||||
|
componentRef: ShallowRef<TI | null>;
|
||||||
|
} {
|
||||||
markRaw(component);
|
markRaw(component);
|
||||||
|
|
||||||
|
const componentRef = shallowRef<TI | null>(null);
|
||||||
|
|
||||||
const id = ++popupIdCount;
|
const id = ++popupIdCount;
|
||||||
const dispose = () => {
|
const dispose = () => {
|
||||||
// このsetTimeoutが無いと挙動がおかしくなる(autocompleteが閉じなくなる)。Vueのバグ?
|
// このsetTimeoutが無いと挙動がおかしくなる(autocompleteが閉じなくなる)。Vueのバグ?
|
||||||
|
@ -194,6 +203,7 @@ export function popup<T extends Component>(
|
||||||
};
|
};
|
||||||
const state = {
|
const state = {
|
||||||
component,
|
component,
|
||||||
|
componentRef,
|
||||||
props,
|
props,
|
||||||
events,
|
events,
|
||||||
id,
|
id,
|
||||||
|
@ -203,6 +213,7 @@ export function popup<T extends Component>(
|
||||||
|
|
||||||
return {
|
return {
|
||||||
dispose,
|
dispose,
|
||||||
|
componentRef,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -627,14 +638,17 @@ export async function selectRole(params: {
|
||||||
{ canceled: false; result: Misskey.entities.Role[] }
|
{ canceled: false; result: Misskey.entities.Role[] }
|
||||||
> {
|
> {
|
||||||
return new Promise((resolve) => {
|
return new Promise((resolve) => {
|
||||||
popup(defineAsyncComponent(() => import('@/components/MkRoleSelectDialog.vue')), params, {
|
const { dispose } = popup(defineAsyncComponent(() => import('@/components/MkRoleSelectDialog.vue')), params, {
|
||||||
done: roles => {
|
done: roles => {
|
||||||
resolve({ canceled: false, result: roles });
|
resolve({ canceled: false, result: roles });
|
||||||
},
|
},
|
||||||
close: () => {
|
close: () => {
|
||||||
resolve({ canceled: true, result: undefined });
|
resolve({ canceled: true, result: undefined });
|
||||||
},
|
},
|
||||||
}, 'dispose');
|
closed: () => {
|
||||||
|
dispose();
|
||||||
|
},
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
:is="popup.component"
|
:is="popup.component"
|
||||||
v-for="popup in popups"
|
v-for="popup in popups"
|
||||||
:key="popup.id"
|
:key="popup.id"
|
||||||
|
:ref="(el: Component | null) => popup.componentRef = el"
|
||||||
v-bind="popup.props"
|
v-bind="popup.props"
|
||||||
v-on="popup.events"
|
v-on="popup.events"
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -3,8 +3,9 @@
|
||||||
* SPDX-License-Identifier: AGPL-3.0-only
|
* SPDX-License-Identifier: AGPL-3.0-only
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { defineAsyncComponent, ref, watch } from 'vue';
|
import { defineAsyncComponent, ref, shallowRef, watch } from 'vue';
|
||||||
import type { Ref } from 'vue';
|
import type { Ref, ShallowRef } from 'vue';
|
||||||
|
import type MkEmojiPickerWindow_TypeOnly from '@/components/MkEmojiPickerWindow.vue';
|
||||||
import { popup } from '@/os.js';
|
import { popup } from '@/os.js';
|
||||||
import { prefer } from '@/preferences.js';
|
import { prefer } from '@/preferences.js';
|
||||||
|
|
||||||
|
@ -18,6 +19,7 @@ class EmojiPicker {
|
||||||
private src: Ref<HTMLElement | null> = ref(null);
|
private src: Ref<HTMLElement | null> = ref(null);
|
||||||
|
|
||||||
private isWindow: boolean = false;
|
private isWindow: boolean = false;
|
||||||
|
private windowComponentEl: ShallowRef<InstanceType<typeof MkEmojiPickerWindow_TypeOnly> | null> = shallowRef(null);
|
||||||
private windowShowing: boolean = false;
|
private windowShowing: boolean = false;
|
||||||
|
|
||||||
private dialogShowing = ref(false);
|
private dialogShowing = ref(false);
|
||||||
|
@ -73,7 +75,7 @@ class EmojiPicker {
|
||||||
if (this.isWindow) {
|
if (this.isWindow) {
|
||||||
if (this.windowShowing) return;
|
if (this.windowShowing) return;
|
||||||
this.windowShowing = true;
|
this.windowShowing = true;
|
||||||
const { dispose } = popup(defineAsyncComponent(() => import('@/components/MkEmojiPickerWindow.vue')), {
|
const { dispose, componentRef } = popup(defineAsyncComponent(() => import('@/components/MkEmojiPickerWindow.vue')), {
|
||||||
src: opts.src,
|
src: opts.src,
|
||||||
pinnedEmojis: this.emojisRef,
|
pinnedEmojis: this.emojisRef,
|
||||||
asReactionPicker: false,
|
asReactionPicker: false,
|
||||||
|
@ -87,6 +89,7 @@ class EmojiPicker {
|
||||||
dispose();
|
dispose();
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
this.windowComponentEl.value = componentRef.value;
|
||||||
} else {
|
} else {
|
||||||
this.src.value = opts.src;
|
this.src.value = opts.src;
|
||||||
this.dialogShowing.value = true;
|
this.dialogShowing.value = true;
|
||||||
|
@ -94,6 +97,12 @@ class EmojiPicker {
|
||||||
this.onClosed = opts.onClosed;
|
this.onClosed = opts.onClosed;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public closeWindow() {
|
||||||
|
if (this.isWindow && this.windowComponentEl.value) {
|
||||||
|
this.windowComponentEl.value.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const emojiPicker = new EmojiPicker();
|
export const emojiPicker = new EmojiPicker();
|
||||||
|
|
Loading…
Reference in New Issue