Declarative & Imperative Confirm Dialog
Relevant source files
The following files were used as context for generating this wiki page:
The Confirm Dialog system provides a unified interface for requesting user confirmation before executing high-risk or irreversible actions. It supports two distinct usage patterns: a declarative React component for state-driven UI and an imperative promise-based function for use within event callbacks or asynchronous logic. The system ensures visual consistency and safety by enforcing variants like "danger" and requiring explicit text input for critical operations.
Sources: src/primitives/confirm-dialog.tsx:17-37, README.md:36
Core Component Architecture
The ConfirmDialog component builds upon the base Dialog primitive. It enforces a strict layout comprising a title, an optional message, action buttons, and a specialized input field for "requireText" verification.
Component Logic
The component tracks the open state using a useRef and useState hook to ensure the input field clears every time the dialog opens. This prevents users from accidentally bypassing the "requireText" friction if a previous entry was cached.
Safety Features
The system prioritizes safety through three primary mechanisms:
- Variant Enforcement: The
variant="danger"prop automatically applies destructive styling and icons, preventing developers from accidentally using neutral colors for dangerous actions. - Required Text Input: For irreversible actions, the
requireTextproperty mandates that users type a specific word before the confirmation button enables. - Dismissibility Control: The
dismissibleprop allows developers to disable closing the dialog via clicking outside or pressing Escape, forcing a choice.
Sources: src/primitives/confirm-dialog.tsx:29-37, src/primitives/confirm-dialog.tsx:84-100
Imperative API Implementation
The imperative confirmDialog() function allows triggering a dialog from anywhere in the codebase without managing local React state. This is achieved through a module-level store and a host component that subscribes to updates.
Global State Management
The system uses a module-level pending object and a listeners Set to track the current active dialog request. The ConfirmDialogHost component uses useSyncExternalStore to subscribe to this store and render the ConfirmDialog when a request exists.
API Details
| Feature | Type | Description |
|---|---|---|
confirmDialog(options) | Promise<boolean> | Triggers the imperative dialog. Returns true if confirmed, false otherwise. |
<ConfirmDialogHost /> | JSX.Element | The listener component that must be mounted once at the application root. |
useConfirmPending() | boolean | A hook to check if a confirmation dialog is currently awaiting a response. |
Sources: src/primitives/confirm-dialog.tsx:156-165, src/primitives/confirm-dialog.tsx:173-195, src/primitives/confirm-dialog.tsx:206-208
Configuration and Props
The system uses a shared interface for both declarative and imperative calls to maintain consistency.
ConfirmDialogOptions
These options define the content and visual style of the dialog.
| Property | Type | Description |
|---|---|---|
title | ReactNode | The main heading of the dialog. |
message | ReactNode | Detailed explanation text. |
variant | "default" | "danger" | Sets the tone (danger adds red styling and triangle icon). |
requireText | string | The specific string the user must type to confirm. |
confirmLabel | string | Text for the action button (default: "确定"). |
cancelLabel | string | Text for the dismiss button (default: "取消"). |
Sources: src/primitives/confirm-dialog.tsx:40-51, src/primitives/confirm-dialog.tsx:131-137
Implementation Constraints
The system includes specific technical constraints to ensure reliability:
- Sequential Resolution: If a new
confirmDialog()call is made before a previous one is settled, the previous call is automatically resolved asfalseto prevent hung promises. - Styling: Danger variants utilize the
text-destructivecolor andicon-[solar--danger-triangle-linear]from the project's design system. - Base Dependencies: The component depends on the internal
Dialogprimitives andButtoncomponent.
Sources: src/primitives/confirm-dialog.tsx:166-167, src/primitives/confirm-dialog.tsx:89-94, src/primitives/dialog.tsx:1-125, src/primitives/button.tsx:1-50
Summary
The Confirm Dialog system bridges the gap between declarative React state and imperative event-driven logic. By enforcing safety patterns like "danger" variants and text-based verification at the component level, it reduces the risk of accidental destructive actions across the application while providing a flexible API for developers.