import { reactive, readonly } from 'vue'; export type DialogResult = { status: boolean; value: T }; type BaseOptions = { /** * Title of the dialog */ title?: string; /** * Message to display in the dialog */ message?: string; /** * Text for the confirm button */ confirmText?: string; /** * Color class for the confirm button (e.g., 'is-primary', 'is-danger') */ confirmColor?: string; }; export type PromptOptions = BaseOptions & { /** * Text for the input field */ initial?: string; /** * Placeholder text for the input field */ placeholder?: string; /** * Text for the cancel button */ cancelText?: string; /** * Function to validate the input value * @returns true if valid, or an error message string if invalid */ validate?: (v: string) => true | string; }; export type ConfirmOptions = BaseOptions & { /** * Text for the confirm button */ cancelText?: string; /** * Raw HTML content to include in the dialog message. */ rawHTML?: string; }; export type AlertOptions = BaseOptions & {}; type QueueItem = { type: 'prompt' | 'confirm' | 'alert'; opts: PromptOptions | ConfirmOptions | AlertOptions; resolve: (r: DialogResult) => void; }; type DialogState = { current: QueueItem | null; queue: QueueItem[]; errorMsg: string | null; input: string; }; export const useDialog = () => { const raw = useState('dialog:state', () => reactive({ current: null, queue: [], errorMsg: null, input: '', } as DialogState), ); const state = raw.value; const _dequeue = () => { if (!state.current && state.queue.length) { state.current = state.queue.shift()!; state.errorMsg = null; state.input = state.current.type === 'prompt' ? ((state.current.opts as PromptOptions).initial ?? '') : ''; } }; const promptDialog = (opts: PromptOptions) => new Promise>((resolve) => { state.queue.push({ type: 'prompt', opts, resolve }); _dequeue(); }); const confirmDialog = (opts: ConfirmOptions) => new Promise>((resolve) => { state.queue.push({ type: 'confirm', opts, resolve }); _dequeue(); }); const alertDialog = (opts: AlertOptions) => new Promise>((resolve) => { state.queue.push({ type: 'alert', opts, resolve }); _dequeue(); }); const confirm = (value?: string) => { if (!state.current) return; if (state.current.type === 'prompt') { const val = value ?? state.input; const v = (state.current.opts as PromptOptions).validate?.(val); if (v && v !== true) { state.errorMsg = v; return; } state.current.resolve({ status: true, value: val }); } else { state.current.resolve({ status: true, value: null }); } state.current = null; _dequeue(); }; const cancel = () => { if (!state.current) return; state.current.resolve({ status: false, value: null }); state.current = null; _dequeue(); }; return { promptDialog, confirmDialog, alertDialog, confirm, cancel, state: readonly(state) as Readonly, }; };