99 lines
2.7 KiB
TypeScript
99 lines
2.7 KiB
TypeScript
import { nextTick, ref } from 'vue';
|
||
|
||
/**
|
||
* Очередь подтверждающих диалогов с поддержкой async-onConfirm и анимаций.
|
||
* Перенесено из проекта onboard (Composables/useAppDialog.js).
|
||
*
|
||
* Использование:
|
||
* const ok = await useAppDialog({ title: 'Удалить?', content: '...' })
|
||
*/
|
||
export interface AppDialogButtonProps {
|
||
type?: 'default' | 'primary' | 'info' | 'success' | 'warning' | 'error';
|
||
secondary?: boolean;
|
||
[key: string]: unknown;
|
||
}
|
||
|
||
export interface AppDialogItem {
|
||
id: number;
|
||
show: boolean;
|
||
title?: string;
|
||
content?: string;
|
||
loading: boolean;
|
||
onConfirm?: () => unknown | Promise<unknown>;
|
||
positiveText?: string;
|
||
negativeText?: string;
|
||
positiveProps?: AppDialogButtonProps;
|
||
negativeProps?: AppDialogButtonProps;
|
||
maskClosable?: boolean;
|
||
resolve: (confirmed: boolean) => void;
|
||
}
|
||
|
||
export interface AppDialogOptions {
|
||
title?: string;
|
||
content?: string;
|
||
positiveText?: string;
|
||
negativeText?: string;
|
||
positiveProps?: AppDialogButtonProps;
|
||
negativeProps?: AppDialogButtonProps;
|
||
maskClosable?: boolean;
|
||
onConfirm?: () => unknown | Promise<unknown>;
|
||
}
|
||
|
||
export const dialogQueue = ref<AppDialogItem[]>([]);
|
||
let idCounter = 0;
|
||
|
||
/** Закрытие диалога (кнопка / Esc / клик по маске). */
|
||
export function closeDialog(id: number, confirmed = false): void {
|
||
const dialog = dialogQueue.value.find((d) => d.id === id);
|
||
|
||
if (dialog && dialog.show) {
|
||
dialog.show = false;
|
||
dialog.resolve(confirmed);
|
||
}
|
||
}
|
||
|
||
/** Удаление из очереди после завершения leave-анимации. */
|
||
export function cleanupDialog(id: number): void {
|
||
dialogQueue.value = dialogQueue.value.filter((d) => d.id !== id);
|
||
}
|
||
|
||
export function useAppDialog(options: AppDialogOptions = {}): Promise<boolean> {
|
||
const {
|
||
title,
|
||
content,
|
||
positiveProps,
|
||
negativeProps,
|
||
positiveText = 'Подтвердить',
|
||
negativeText = 'Отмена',
|
||
maskClosable = false,
|
||
onConfirm,
|
||
} = options;
|
||
|
||
return new Promise<boolean>((resolve) => {
|
||
const id = idCounter++;
|
||
|
||
dialogQueue.value.push({
|
||
id,
|
||
show: false,
|
||
title,
|
||
content,
|
||
loading: false,
|
||
onConfirm,
|
||
positiveText,
|
||
negativeText,
|
||
positiveProps,
|
||
negativeProps,
|
||
maskClosable,
|
||
resolve,
|
||
});
|
||
|
||
nextTick(() => {
|
||
const dialog = dialogQueue.value.find((d) => d.id === id);
|
||
|
||
if (dialog) {
|
||
dialog.show = true;
|
||
}
|
||
});
|
||
});
|
||
}
|