131 lines · 3.5 KB · TypeScript
RawDownload
import type { ConfirmDialogOptions, ConfirmDialogVariant } from "@t3tools/contracts"; export type ConfirmDialogState =  | { readonly status: "idle" }  | {      readonly status: "confirming";      readonly message: string;      readonly variant: ConfirmDialogVariant;    }  | {      readonly status: "closing";      readonly message: string;      readonly variant: ConfirmDialogVariant;    }; type PendingConfirmation = {  readonly message: string;  readonly variant: ConfirmDialogVariant;  readonly resolve: (confirmed: boolean) => void;}; const idleState: ConfirmDialogState = { status: "idle" };let state: ConfirmDialogState = idleState;let activeConfirmation: PendingConfirmation | null = null;let queuedConfirmations: PendingConfirmation[] = [];let registeredHostCount = 0;const listeners = new Set<() => void>(); function publish(next: ConfirmDialogState): void {  state = next;  for (const listener of listeners) {    listener();  }} function resolvePendingConfirmations(confirmed: boolean): void {  activeConfirmation?.resolve(confirmed);  for (const confirmation of queuedConfirmations) {    confirmation.resolve(confirmed);  }  activeConfirmation = null;  queuedConfirmations = [];} export function readConfirmDialogState(): ConfirmDialogState {  return state;} export function subscribeConfirmDialog(listener: () => void): () => void {  listeners.add(listener);  return () => {    listeners.delete(listener);  };} /** * Registers the renderer host that can present themed confirmations. The * returned cleanup function also cancels any request left without a host. */export function registerConfirmDialogHost(): () => void {  registeredHostCount += 1;  let registered = true;   return () => {    if (!registered) return;    registered = false;    registeredHostCount = Math.max(0, registeredHostCount - 1);     if (registeredHostCount === 0) {      resolvePendingConfirmations(false);      publish(idleState);    }  };} /** * Requests a themed confirmation when a host is mounted. An undefined result * means no themed host is currently available. */export function requestConfirmDialog(  message: string,  options?: ConfirmDialogOptions,): Promise<boolean> | undefined {  if (registeredHostCount === 0) return undefined;   const confirmation = new Promise<boolean>((resolve) => {    const pending = {      message,      variant: options?.variant ?? "default",      resolve,    } satisfies PendingConfirmation;    if (activeConfirmation || state.status === "closing") {      queuedConfirmations.push(pending);      return;    }     activeConfirmation = pending;    publish({ status: "confirming", message, variant: pending.variant });  });   return confirmation;} export function respondToConfirmDialog(confirmed: boolean): void {  if (state.status !== "confirming" || !activeConfirmation) return;   const confirmation = activeConfirmation;  activeConfirmation = null;  confirmation.resolve(confirmed);  publish({ status: "closing", message: state.message, variant: state.variant });} export function completeConfirmDialogClose(): void {  if (state.status !== "closing") return;   const next = queuedConfirmations.shift();  if (!next) {    publish(idleState);    return;  }   activeConfirmation = next;  publish({ status: "confirming", message: next.message, variant: next.variant });} export function resetConfirmDialogForTests(): void {  resolvePendingConfirmations(false);  registeredHostCount = 0;  publish(idleState);  listeners.clear();}