@djangocfg/ui-core 2.1.148 → 2.1.150

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,263 @@
1
+ import { useCallback } from 'react';
2
+ import { defineStory } from '@djangocfg/playground';
3
+ import { Button } from '../../components/button';
4
+ import { DialogProvider } from './DialogProvider';
5
+ import { useDialog } from './hooks';
6
+
7
+ export default defineStory({
8
+ title: 'Lib/DialogService',
9
+ component: DialogProvider,
10
+ description: 'Global dialog service for alert, confirm, and prompt dialogs. Uses CustomEvents to work from anywhere in the app. Supports i18n and keyboard shortcuts.',
11
+ });
12
+
13
+ // Wrapper component to provide DialogProvider context
14
+ function StoryWrapper({ children }: { children: React.ReactNode }) {
15
+ return <DialogProvider>{children}</DialogProvider>;
16
+ }
17
+
18
+ // Demo component using the hook
19
+ function AlertDemo() {
20
+ const { alert } = useDialog();
21
+
22
+ const handleSimpleAlert = useCallback(async () => {
23
+ await alert('This is a simple alert message!');
24
+ console.log('Alert closed');
25
+ }, [alert]);
26
+
27
+ const handleAlertWithTitle = useCallback(async () => {
28
+ await alert({
29
+ title: 'Success!',
30
+ message: 'Your changes have been saved successfully.',
31
+ });
32
+ console.log('Alert with title closed');
33
+ }, [alert]);
34
+
35
+ return (
36
+ <div className="flex gap-2">
37
+ <Button onClick={handleSimpleAlert}>Simple Alert</Button>
38
+ <Button variant="outline" onClick={handleAlertWithTitle}>
39
+ Alert with Title
40
+ </Button>
41
+ </div>
42
+ );
43
+ }
44
+
45
+ export const Alert = () => (
46
+ <StoryWrapper>
47
+ <AlertDemo />
48
+ </StoryWrapper>
49
+ );
50
+
51
+ // Confirm demo
52
+ function ConfirmDemo() {
53
+ const { confirm, alert } = useDialog();
54
+
55
+ const handleSimpleConfirm = useCallback(async () => {
56
+ const result = await confirm('Are you sure you want to proceed?');
57
+ await alert(`You clicked: ${result ? 'Confirm' : 'Cancel'}`);
58
+ }, [confirm, alert]);
59
+
60
+ const handleDestructiveConfirm = useCallback(async () => {
61
+ const result = await confirm({
62
+ title: 'Delete Item',
63
+ message: 'This action cannot be undone. Are you sure you want to delete this item?',
64
+ confirmText: 'Yes, Delete',
65
+ cancelText: 'Keep It',
66
+ variant: 'destructive',
67
+ });
68
+ await alert(`You clicked: ${result ? 'Delete' : 'Keep'}`);
69
+ }, [confirm, alert]);
70
+
71
+ return (
72
+ <div className="flex gap-2">
73
+ <Button onClick={handleSimpleConfirm}>Simple Confirm</Button>
74
+ <Button variant="destructive" onClick={handleDestructiveConfirm}>
75
+ Destructive Confirm
76
+ </Button>
77
+ </div>
78
+ );
79
+ }
80
+
81
+ export const Confirm = () => (
82
+ <StoryWrapper>
83
+ <ConfirmDemo />
84
+ </StoryWrapper>
85
+ );
86
+
87
+ // Prompt demo
88
+ function PromptDemo() {
89
+ const { prompt, alert } = useDialog();
90
+
91
+ const handleSimplePrompt = useCallback(async () => {
92
+ const result = await prompt('What is your name?');
93
+ if (result) {
94
+ await alert(`Hello, ${result}!`);
95
+ } else {
96
+ await alert('You cancelled the prompt.');
97
+ }
98
+ }, [prompt, alert]);
99
+
100
+ const handlePromptWithDefault = useCallback(async () => {
101
+ const result = await prompt({
102
+ title: 'Edit Name',
103
+ message: 'Enter your display name:',
104
+ defaultValue: 'John Doe',
105
+ placeholder: 'Enter name...',
106
+ confirmText: 'Save',
107
+ cancelText: 'Cancel',
108
+ });
109
+ if (result) {
110
+ await alert(`Name updated to: ${result}`);
111
+ }
112
+ }, [prompt, alert]);
113
+
114
+ const handleEmailPrompt = useCallback(async () => {
115
+ const result = await prompt({
116
+ title: 'Subscribe',
117
+ message: 'Enter your email to subscribe to our newsletter:',
118
+ placeholder: 'email@example.com',
119
+ inputType: 'email',
120
+ confirmText: 'Subscribe',
121
+ });
122
+ if (result) {
123
+ await alert(`Subscribed with: ${result}`);
124
+ }
125
+ }, [prompt, alert]);
126
+
127
+ return (
128
+ <div className="flex gap-2 flex-wrap">
129
+ <Button onClick={handleSimplePrompt}>Simple Prompt</Button>
130
+ <Button variant="outline" onClick={handlePromptWithDefault}>
131
+ Prompt with Default
132
+ </Button>
133
+ <Button variant="secondary" onClick={handleEmailPrompt}>
134
+ Email Prompt
135
+ </Button>
136
+ </div>
137
+ );
138
+ }
139
+
140
+ export const Prompt = () => (
141
+ <StoryWrapper>
142
+ <PromptDemo />
143
+ </StoryWrapper>
144
+ );
145
+
146
+ // Queue demo - multiple dialogs in sequence
147
+ function QueueDemo() {
148
+ const { alert, confirm, prompt } = useDialog();
149
+
150
+ const handleQueue = useCallback(async () => {
151
+ await alert('This is step 1 of 3');
152
+ const proceed = await confirm('Do you want to continue to step 2?');
153
+ if (!proceed) {
154
+ await alert('You cancelled the sequence.');
155
+ return;
156
+ }
157
+ const name = await prompt({
158
+ title: 'Step 3',
159
+ message: 'Enter your name to complete:',
160
+ });
161
+ if (name) {
162
+ await alert(`Sequence complete! Hello, ${name}!`);
163
+ } else {
164
+ await alert('Sequence cancelled at step 3.');
165
+ }
166
+ }, [alert, confirm, prompt]);
167
+
168
+ return (
169
+ <Button onClick={handleQueue}>
170
+ Start Dialog Sequence
171
+ </Button>
172
+ );
173
+ }
174
+
175
+ export const Queue = () => (
176
+ <StoryWrapper>
177
+ <QueueDemo />
178
+ </StoryWrapper>
179
+ );
180
+
181
+ // Window.dialog API demo (vanilla JS style)
182
+ function WindowDialogDemo() {
183
+ const handleWindowAlert = useCallback(() => {
184
+ window.dialog.alert('Called via window.dialog.alert()');
185
+ }, []);
186
+
187
+ const handleWindowConfirm = useCallback(async () => {
188
+ const result = await window.dialog.confirm('Called via window.dialog.confirm()');
189
+ window.dialog.alert(`Result: ${result}`);
190
+ }, []);
191
+
192
+ const handleWindowPrompt = useCallback(async () => {
193
+ const result = await window.dialog.prompt({
194
+ title: 'window.dialog.prompt()',
195
+ message: 'This works from vanilla JS too!',
196
+ defaultValue: 'Hello',
197
+ });
198
+ if (result) {
199
+ window.dialog.alert(`You entered: ${result}`);
200
+ }
201
+ }, []);
202
+
203
+ return (
204
+ <div className="space-y-4">
205
+ <p className="text-sm text-muted-foreground">
206
+ These buttons use <code>window.dialog.*</code> directly - works from any JS code!
207
+ </p>
208
+ <div className="flex gap-2">
209
+ <Button variant="outline" onClick={handleWindowAlert}>
210
+ window.dialog.alert()
211
+ </Button>
212
+ <Button variant="outline" onClick={handleWindowConfirm}>
213
+ window.dialog.confirm()
214
+ </Button>
215
+ <Button variant="outline" onClick={handleWindowPrompt}>
216
+ window.dialog.prompt()
217
+ </Button>
218
+ </div>
219
+ </div>
220
+ );
221
+ }
222
+
223
+ export const WindowDialogAPI = () => (
224
+ <StoryWrapper>
225
+ <WindowDialogDemo />
226
+ </StoryWrapper>
227
+ );
228
+
229
+ // Keyboard shortcuts demo
230
+ function HotkeysDemo() {
231
+ const { alert, confirm } = useDialog();
232
+
233
+ const handleHotkeysDemo = useCallback(async () => {
234
+ await alert({
235
+ title: 'Keyboard Shortcuts',
236
+ message: 'Press Enter to close this alert, or wait and click OK.',
237
+ });
238
+
239
+ const result = await confirm({
240
+ title: 'Confirm with Keyboard',
241
+ message: 'Press Enter to confirm, Escape to cancel.',
242
+ });
243
+
244
+ await alert(`You pressed: ${result ? 'Enter (Confirm)' : 'Escape (Cancel)'}`);
245
+ }, [alert, confirm]);
246
+
247
+ return (
248
+ <div className="space-y-4">
249
+ <p className="text-sm text-muted-foreground">
250
+ Dialogs support keyboard shortcuts: <kbd className="px-1.5 py-0.5 bg-muted rounded text-xs">Enter</kbd> to confirm, <kbd className="px-1.5 py-0.5 bg-muted rounded text-xs">Escape</kbd> to cancel.
251
+ </p>
252
+ <Button onClick={handleHotkeysDemo}>
253
+ Test Keyboard Shortcuts
254
+ </Button>
255
+ </div>
256
+ );
257
+ }
258
+
259
+ export const KeyboardShortcuts = () => (
260
+ <StoryWrapper>
261
+ <HotkeysDemo />
262
+ </StoryWrapper>
263
+ );
@@ -0,0 +1,59 @@
1
+ 'use client';
2
+
3
+ import { useMemo } from 'react';
4
+ import { useT } from '@djangocfg/i18n';
5
+ import {
6
+ AlertDialog,
7
+ AlertDialogAction,
8
+ AlertDialogContent,
9
+ AlertDialogDescription,
10
+ AlertDialogFooter,
11
+ AlertDialogHeader,
12
+ AlertDialogTitle,
13
+ } from '../../../components/alert-dialog';
14
+ import { useHotkey } from '../../../hooks/useHotkey';
15
+ import { I18N_KEYS } from '../constants';
16
+ import type { DialogOptions } from '../types';
17
+
18
+ interface AlertDialogUIProps {
19
+ open: boolean;
20
+ options: DialogOptions;
21
+ onClose: () => void;
22
+ }
23
+
24
+ export function AlertDialogUI({ open, options, onClose }: AlertDialogUIProps) {
25
+ const t = useT();
26
+
27
+ // Prepare data before render
28
+ const dialogData = useMemo(() => ({
29
+ title: options.title || t(I18N_KEYS.alertTitle),
30
+ message: options.message,
31
+ confirmText: options.confirmText || t(I18N_KEYS.ok),
32
+ preventClose: options.preventClose ?? false,
33
+ }), [options, t]);
34
+
35
+ // Hotkey: Enter to confirm
36
+ useHotkey('enter', onClose, { enabled: open, preventDefault: true });
37
+
38
+ const handleOpenChange = (isOpen: boolean) => {
39
+ if (!isOpen && !dialogData.preventClose) {
40
+ onClose();
41
+ }
42
+ };
43
+
44
+ return (
45
+ <AlertDialog open={open} onOpenChange={handleOpenChange}>
46
+ <AlertDialogContent>
47
+ <AlertDialogHeader>
48
+ <AlertDialogTitle>{dialogData.title}</AlertDialogTitle>
49
+ <AlertDialogDescription>{dialogData.message}</AlertDialogDescription>
50
+ </AlertDialogHeader>
51
+ <AlertDialogFooter>
52
+ <AlertDialogAction onClick={onClose}>
53
+ {dialogData.confirmText}
54
+ </AlertDialogAction>
55
+ </AlertDialogFooter>
56
+ </AlertDialogContent>
57
+ </AlertDialog>
58
+ );
59
+ }
@@ -0,0 +1,81 @@
1
+ 'use client';
2
+
3
+ import { useMemo } from 'react';
4
+ import { useT } from '@djangocfg/i18n';
5
+ import {
6
+ AlertDialog,
7
+ AlertDialogAction,
8
+ AlertDialogCancel,
9
+ AlertDialogContent,
10
+ AlertDialogDescription,
11
+ AlertDialogFooter,
12
+ AlertDialogHeader,
13
+ AlertDialogTitle,
14
+ } from '../../../components/alert-dialog';
15
+ import { buttonVariants } from '../../../components/button';
16
+ import { useHotkey } from '../../../hooks/useHotkey';
17
+ import { cn } from '../../utils';
18
+ import { I18N_KEYS } from '../constants';
19
+ import type { DialogOptions } from '../types';
20
+
21
+ interface ConfirmDialogUIProps {
22
+ open: boolean;
23
+ options: DialogOptions;
24
+ onConfirm: () => void;
25
+ onCancel: () => void;
26
+ }
27
+
28
+ export function ConfirmDialogUI({
29
+ open,
30
+ options,
31
+ onConfirm,
32
+ onCancel,
33
+ }: ConfirmDialogUIProps) {
34
+ const t = useT();
35
+
36
+ // Prepare data before render
37
+ const dialogData = useMemo(() => {
38
+ const isDestructive = options.variant === 'destructive';
39
+ return {
40
+ title: options.title || t(I18N_KEYS.confirmTitle),
41
+ message: options.message,
42
+ confirmText: options.confirmText || t(I18N_KEYS.confirm),
43
+ cancelText: options.cancelText || t(I18N_KEYS.cancel),
44
+ preventClose: options.preventClose ?? false,
45
+ isDestructive,
46
+ confirmClassName: cn(isDestructive && buttonVariants({ variant: 'destructive' })),
47
+ };
48
+ }, [options, t]);
49
+
50
+ // Hotkey: Enter to confirm, Escape to cancel
51
+ useHotkey('enter', onConfirm, { enabled: open, preventDefault: true });
52
+ useHotkey('escape', onCancel, { enabled: open });
53
+
54
+ const handleOpenChange = (isOpen: boolean) => {
55
+ if (!isOpen && !dialogData.preventClose) {
56
+ onCancel();
57
+ }
58
+ };
59
+
60
+ return (
61
+ <AlertDialog open={open} onOpenChange={handleOpenChange}>
62
+ <AlertDialogContent>
63
+ <AlertDialogHeader>
64
+ <AlertDialogTitle>{dialogData.title}</AlertDialogTitle>
65
+ <AlertDialogDescription>{dialogData.message}</AlertDialogDescription>
66
+ </AlertDialogHeader>
67
+ <AlertDialogFooter>
68
+ <AlertDialogCancel onClick={onCancel}>
69
+ {dialogData.cancelText}
70
+ </AlertDialogCancel>
71
+ <AlertDialogAction
72
+ onClick={onConfirm}
73
+ className={dialogData.confirmClassName}
74
+ >
75
+ {dialogData.confirmText}
76
+ </AlertDialogAction>
77
+ </AlertDialogFooter>
78
+ </AlertDialogContent>
79
+ </AlertDialog>
80
+ );
81
+ }
@@ -0,0 +1,103 @@
1
+ 'use client';
2
+
3
+ import { useState, useEffect, useRef, useMemo, useCallback } from 'react';
4
+ import { useT } from '@djangocfg/i18n';
5
+ import {
6
+ Dialog,
7
+ DialogContent,
8
+ DialogDescription,
9
+ DialogFooter,
10
+ DialogHeader,
11
+ DialogTitle,
12
+ } from '../../../components/dialog';
13
+ import { Button } from '../../../components/button';
14
+ import { Input } from '../../../components/input';
15
+ import { useHotkey } from '../../../hooks/useHotkey';
16
+ import { I18N_KEYS } from '../constants';
17
+ import type { DialogOptions } from '../types';
18
+
19
+ interface PromptDialogUIProps {
20
+ open: boolean;
21
+ options: DialogOptions;
22
+ onConfirm: (value: string) => void;
23
+ onCancel: () => void;
24
+ }
25
+
26
+ export function PromptDialogUI({
27
+ open,
28
+ options,
29
+ onConfirm,
30
+ onCancel,
31
+ }: PromptDialogUIProps) {
32
+ const t = useT();
33
+ const [value, setValue] = useState(options.defaultValue || '');
34
+ const inputRef = useRef<HTMLInputElement>(null);
35
+
36
+ // Prepare data before render
37
+ const dialogData = useMemo(() => ({
38
+ title: options.title || t(I18N_KEYS.promptTitle),
39
+ message: options.message,
40
+ confirmText: options.confirmText || t(I18N_KEYS.ok),
41
+ cancelText: options.cancelText || t(I18N_KEYS.cancel),
42
+ placeholder: options.placeholder || t(I18N_KEYS.promptPlaceholder),
43
+ inputType: options.inputType || 'text',
44
+ preventClose: options.preventClose ?? false,
45
+ }), [options, t]);
46
+
47
+ // Reset value when dialog opens with new options
48
+ useEffect(() => {
49
+ if (open) {
50
+ setValue(options.defaultValue || '');
51
+ // Focus input after a short delay to ensure dialog is fully rendered
52
+ setTimeout(() => inputRef.current?.focus(), 50);
53
+ }
54
+ }, [open, options.defaultValue]);
55
+
56
+ const handleSubmit = useCallback((e?: React.FormEvent) => {
57
+ e?.preventDefault();
58
+ onConfirm(value);
59
+ }, [onConfirm, value]);
60
+
61
+ const handleChange = useCallback((e: React.ChangeEvent<HTMLInputElement>) => {
62
+ setValue(e.target.value);
63
+ }, []);
64
+
65
+ const handleOpenChange = useCallback((isOpen: boolean) => {
66
+ if (!isOpen && !dialogData.preventClose) {
67
+ onCancel();
68
+ }
69
+ }, [dialogData.preventClose, onCancel]);
70
+
71
+ // Hotkey: Escape to cancel (Enter is handled by form submit)
72
+ useHotkey('escape', onCancel, { enabled: open });
73
+
74
+ return (
75
+ <Dialog open={open} onOpenChange={handleOpenChange}>
76
+ <DialogContent>
77
+ <form onSubmit={handleSubmit}>
78
+ <DialogHeader>
79
+ <DialogTitle>{dialogData.title}</DialogTitle>
80
+ <DialogDescription>{dialogData.message}</DialogDescription>
81
+ </DialogHeader>
82
+ <div className="py-4">
83
+ <Input
84
+ ref={inputRef}
85
+ type={dialogData.inputType}
86
+ value={value}
87
+ onChange={handleChange}
88
+ placeholder={dialogData.placeholder}
89
+ />
90
+ </div>
91
+ <DialogFooter>
92
+ <Button type="button" variant="outline" onClick={onCancel}>
93
+ {dialogData.cancelText}
94
+ </Button>
95
+ <Button type="submit">
96
+ {dialogData.confirmText}
97
+ </Button>
98
+ </DialogFooter>
99
+ </form>
100
+ </DialogContent>
101
+ </Dialog>
102
+ );
103
+ }
@@ -0,0 +1,3 @@
1
+ export { AlertDialogUI } from './AlertDialogUI';
2
+ export { ConfirmDialogUI } from './ConfirmDialogUI';
3
+ export { PromptDialogUI } from './PromptDialogUI';
@@ -0,0 +1,73 @@
1
+ import { DIALOG_REQUEST_EVENT, DIALOG_RESPONSE_EVENT } from './constants';
2
+ import type {
3
+ DialogType,
4
+ DialogOptions,
5
+ DialogRequestPayload,
6
+ DialogResponsePayload,
7
+ } from './types';
8
+
9
+ let dialogIdCounter = 0;
10
+
11
+ function generateId(): string {
12
+ return `dialog-${Date.now()}-${++dialogIdCounter}`;
13
+ }
14
+
15
+ /**
16
+ * Dispatch dialog request and wait for response via CustomEvent
17
+ */
18
+ function showDialog(
19
+ type: DialogType,
20
+ messageOrOptions: string | DialogOptions
21
+ ): Promise<boolean | string | null> {
22
+ return new Promise((resolve) => {
23
+ const id = generateId();
24
+ const options: DialogOptions =
25
+ typeof messageOrOptions === 'string'
26
+ ? { message: messageOrOptions }
27
+ : messageOrOptions;
28
+
29
+ // Listen for response
30
+ const handleResponse = (event: Event) => {
31
+ const customEvent = event as CustomEvent<DialogResponsePayload>;
32
+ if (customEvent.detail.id === id) {
33
+ window.removeEventListener(DIALOG_RESPONSE_EVENT, handleResponse);
34
+ resolve(customEvent.detail.result);
35
+ }
36
+ };
37
+
38
+ window.addEventListener(DIALOG_RESPONSE_EVENT, handleResponse);
39
+
40
+ // Dispatch request
41
+ window.dispatchEvent(
42
+ new CustomEvent<DialogRequestPayload>(DIALOG_REQUEST_EVENT, {
43
+ detail: { id, type, options },
44
+ })
45
+ );
46
+ });
47
+ }
48
+
49
+ /**
50
+ * Initialize global window.dialog API
51
+ * Uses singleton pattern - only initializes once
52
+ */
53
+ export function initDialogAPI(): void {
54
+ if (typeof window === 'undefined') return;
55
+ if (window.dialog) return; // Already initialized
56
+
57
+ window.dialog = {
58
+ alert: (message) => showDialog('alert', message).then(() => undefined),
59
+ confirm: (message) => showDialog('confirm', message) as Promise<boolean>,
60
+ prompt: (message) => showDialog('prompt', message) as Promise<string | null>,
61
+ };
62
+ }
63
+
64
+ /**
65
+ * Dispatch response event (used by DialogProvider)
66
+ */
67
+ export function dispatchDialogResponse(id: string, result: boolean | string | null): void {
68
+ window.dispatchEvent(
69
+ new CustomEvent<DialogResponsePayload>(DIALOG_RESPONSE_EVENT, {
70
+ detail: { id, result },
71
+ })
72
+ );
73
+ }
@@ -0,0 +1 @@
1
+ export { useDialog } from './use-dialog';
@@ -0,0 +1,79 @@
1
+ 'use client';
2
+
3
+ import { useCallback } from 'react';
4
+ import type { DialogOptions } from '../types';
5
+
6
+ /**
7
+ * React hook for using dialog service
8
+ *
9
+ * Provides type-safe access to window.dialog with fallback to native dialogs.
10
+ *
11
+ * @example
12
+ * ```tsx
13
+ * function MyComponent() {
14
+ * const { confirm, alert, prompt } = useDialog();
15
+ *
16
+ * const handleDelete = async () => {
17
+ * const confirmed = await confirm({
18
+ * title: 'Delete Item',
19
+ * message: 'Are you sure?',
20
+ * variant: 'destructive',
21
+ * });
22
+ * if (confirmed) {
23
+ * // delete logic
24
+ * }
25
+ * };
26
+ *
27
+ * return <button onClick={handleDelete}>Delete</button>;
28
+ * }
29
+ * ```
30
+ */
31
+ export function useDialog() {
32
+ const alert = useCallback(
33
+ (message: string | DialogOptions): Promise<void> => {
34
+ if (typeof window === 'undefined') {
35
+ return Promise.resolve();
36
+ }
37
+ if (!window.dialog) {
38
+ // Fallback to native
39
+ window.alert(typeof message === 'string' ? message : message.message);
40
+ return Promise.resolve();
41
+ }
42
+ return window.dialog.alert(message);
43
+ },
44
+ []
45
+ );
46
+
47
+ const confirm = useCallback(
48
+ (message: string | DialogOptions): Promise<boolean> => {
49
+ if (typeof window === 'undefined') {
50
+ return Promise.resolve(false);
51
+ }
52
+ if (!window.dialog) {
53
+ // Fallback to native
54
+ return Promise.resolve(
55
+ window.confirm(typeof message === 'string' ? message : message.message)
56
+ );
57
+ }
58
+ return window.dialog.confirm(message);
59
+ },
60
+ []
61
+ );
62
+
63
+ const prompt = useCallback(
64
+ (message: string | DialogOptions): Promise<string | null> => {
65
+ if (typeof window === 'undefined') {
66
+ return Promise.resolve(null);
67
+ }
68
+ if (!window.dialog) {
69
+ // Fallback to native
70
+ const opts = typeof message === 'string' ? { message } : message;
71
+ return Promise.resolve(window.prompt(opts.message, opts.defaultValue));
72
+ }
73
+ return window.dialog.prompt(message);
74
+ },
75
+ []
76
+ );
77
+
78
+ return { alert, confirm, prompt };
79
+ }
@@ -0,0 +1,16 @@
1
+ // Types
2
+ export type {
3
+ DialogType,
4
+ DialogVariant,
5
+ DialogOptions,
6
+ DialogAPI,
7
+ } from './types';
8
+
9
+ // Provider
10
+ export { DialogProvider } from './DialogProvider';
11
+
12
+ // Hooks
13
+ export { useDialog } from './hooks';
14
+
15
+ // Events (for advanced usage)
16
+ export { initDialogAPI } from './events';