42 lines
1.1 KiB
TypeScript
42 lines
1.1 KiB
TypeScript
|
|
export type ConfirmOptions = {
|
||
|
|
title: string;
|
||
|
|
message?: string;
|
||
|
|
confirmLabel?: string;
|
||
|
|
cancelLabel?: string;
|
||
|
|
destructive?: boolean;
|
||
|
|
};
|
||
|
|
|
||
|
|
type PendingRequest = ConfirmOptions & {
|
||
|
|
resolve: (result: boolean) => void;
|
||
|
|
};
|
||
|
|
|
||
|
|
class ConfirmStore {
|
||
|
|
pending = $state<PendingRequest | null>(null);
|
||
|
|
|
||
|
|
ask(options: ConfirmOptions): Promise<boolean> {
|
||
|
|
// If another dialog is already open, close it as cancelled so we don't stack.
|
||
|
|
if (this.pending) this.pending.resolve(false);
|
||
|
|
return new Promise<boolean>((resolve) => {
|
||
|
|
this.pending = { ...options, resolve };
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
answer(result: boolean): void {
|
||
|
|
if (!this.pending) return;
|
||
|
|
const p = this.pending;
|
||
|
|
this.pending = null;
|
||
|
|
p.resolve(result);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
export const confirmStore = new ConfirmStore();
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Show a modal confirmation dialog. Resolves to true on confirm, false on cancel/Escape.
|
||
|
|
* Safe on the server: falls back to the native confirm() only in the browser.
|
||
|
|
*/
|
||
|
|
export function confirmAction(options: ConfirmOptions): Promise<boolean> {
|
||
|
|
if (typeof window === 'undefined') return Promise.resolve(false);
|
||
|
|
return confirmStore.ask(options);
|
||
|
|
}
|