@versini/ui-dialog 9.0.0 → 10.0.0
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.
- package/README.md +235 -72
- package/dist/index.d.ts +22 -22
- package/dist/index.js +226 -550
- package/package.json +7 -5
package/README.md
CHANGED
|
@@ -1,132 +1,295 @@
|
|
|
1
|
-
# @versini/ui-
|
|
1
|
+
# @versini/ui-dialog
|
|
2
2
|
|
|
3
|
-
[](https://www.npmjs.com/package/@versini/ui-dialog)
|
|
4
|
+
>)
|
|
5
5
|
|
|
6
|
-
>
|
|
6
|
+
> A lightweight and accessible React dialog component built with TypeScript and TailwindCSS.
|
|
7
7
|
|
|
8
|
-
The
|
|
8
|
+
The Dialog component is a minimal modal container leveraging the native HTML `<dialog>` element. It provides an efficient alternative to heavier modal libraries with built-in accessibility, focus management, and animation support.
|
|
9
9
|
|
|
10
10
|
## Table of Contents
|
|
11
11
|
|
|
12
|
-
- [Table of Contents](#table-of-contents)
|
|
13
12
|
- [Features](#features)
|
|
14
13
|
- [Installation](#installation)
|
|
15
14
|
- [Usage](#usage)
|
|
16
|
-
- [Examples](#examples)
|
|
17
|
-
- [Message Box Variant](#message-box-variant)
|
|
18
|
-
- [Animated Panel (Fade)](#animated-panel-fade)
|
|
19
15
|
- [API](#api)
|
|
20
|
-
- [Panel Props](#panel-props)
|
|
21
16
|
|
|
22
17
|
## Features
|
|
23
18
|
|
|
24
|
-
-
|
|
25
|
-
-
|
|
26
|
-
-
|
|
27
|
-
-
|
|
28
|
-
-
|
|
29
|
-
-
|
|
30
|
-
-
|
|
19
|
+
- **⚡ Lightweight**: Uses native HTML `<dialog>` element for minimal overhead
|
|
20
|
+
- **♿ Accessible**: WCAG compliant with built-in focus management and ARIA support
|
|
21
|
+
- **🎨 Flexible Layout**: Two layout kinds (panel and messagebox) to suit different use cases
|
|
22
|
+
- **✨ Animated**: Optional slide or fade animations for opening/closing
|
|
23
|
+
- **🎭 Theme Support**: Multiple border modes and blur effects
|
|
24
|
+
- **🌲 Tree-shakeable**: Optimized for bundle size
|
|
25
|
+
- **🔧 TypeScript**: Fully typed with comprehensive prop definitions
|
|
26
|
+
- **🎯 Focus Management**: Intelligent initial focus handling with customizable options
|
|
31
27
|
|
|
32
28
|
## Installation
|
|
33
29
|
|
|
34
30
|
```bash
|
|
35
|
-
npm install @versini/ui-
|
|
31
|
+
npm install @versini/ui-dialog
|
|
36
32
|
```
|
|
37
33
|
|
|
38
34
|
> **Note**: This component requires TailwindCSS and the `@versini/ui-styles` plugin for proper styling. See the [installation documentation](https://versini-org.github.io/ui-components/?path=/docs/getting-started-installation--docs) for complete setup instructions.
|
|
39
35
|
|
|
40
36
|
## Usage
|
|
41
37
|
|
|
38
|
+
### Basic Dialog
|
|
39
|
+
|
|
42
40
|
```tsx
|
|
43
|
-
import { Panel } from "@versini/ui-panel";
|
|
44
41
|
import { useState } from "react";
|
|
42
|
+
import { Dialog } from "@versini/ui-dialog";
|
|
45
43
|
|
|
46
44
|
function App() {
|
|
47
45
|
const [open, setOpen] = useState(false);
|
|
48
46
|
|
|
49
47
|
return (
|
|
50
48
|
<>
|
|
51
|
-
<button onClick={() => setOpen(true)}>Open
|
|
52
|
-
<
|
|
53
|
-
|
|
54
|
-
|
|
49
|
+
<button onClick={() => setOpen(true)}>Open Dialog</button>
|
|
50
|
+
<Dialog
|
|
51
|
+
open={open}
|
|
52
|
+
onOpenChange={setOpen}
|
|
53
|
+
title="Welcome"
|
|
54
|
+
>
|
|
55
|
+
<p>This is a simple dialog content.</p>
|
|
56
|
+
</Dialog>
|
|
55
57
|
</>
|
|
56
58
|
);
|
|
57
59
|
}
|
|
58
60
|
```
|
|
59
61
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
### Message Box Variant
|
|
62
|
+
### Dialog with Footer
|
|
63
63
|
|
|
64
64
|
```tsx
|
|
65
|
-
import { Panel } from "@versini/ui-panel";
|
|
66
65
|
import { useState } from "react";
|
|
66
|
+
import { Dialog } from "@versini/ui-dialog";
|
|
67
|
+
import { Button } from "@versini/ui-button";
|
|
67
68
|
|
|
68
|
-
function
|
|
69
|
+
function App() {
|
|
69
70
|
const [open, setOpen] = useState(false);
|
|
71
|
+
|
|
70
72
|
return (
|
|
71
73
|
<>
|
|
72
|
-
<button onClick={() => setOpen(true)}>
|
|
73
|
-
<
|
|
74
|
-
kind="messagebox"
|
|
75
|
-
title="Session Expired"
|
|
74
|
+
<button onClick={() => setOpen(true)}>Open Dialog</button>
|
|
75
|
+
<Dialog
|
|
76
76
|
open={open}
|
|
77
77
|
onOpenChange={setOpen}
|
|
78
|
+
title="Confirm Action"
|
|
78
79
|
footer={
|
|
79
|
-
<div className="flex justify-end
|
|
80
|
-
<
|
|
81
|
-
|
|
82
|
-
onClick={() => setOpen(false)}
|
|
83
|
-
>
|
|
84
|
-
Dismiss
|
|
85
|
-
</button>
|
|
86
|
-
<button className="px-3 py-1 rounded bg-blue-600 text-white">
|
|
87
|
-
Re‑authenticate
|
|
88
|
-
</button>
|
|
80
|
+
<div className="flex gap-2 justify-end">
|
|
81
|
+
<Button onClick={() => setOpen(false)}>Cancel</Button>
|
|
82
|
+
<Button variant="primary" onClick={() => setOpen(false)}>Confirm</Button>
|
|
89
83
|
</div>
|
|
90
84
|
}
|
|
91
85
|
>
|
|
92
|
-
|
|
93
|
-
</
|
|
86
|
+
<p>Are you sure you want to proceed?</p>
|
|
87
|
+
</Dialog>
|
|
88
|
+
</>
|
|
89
|
+
);
|
|
90
|
+
}
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
### Dialog with Animation
|
|
94
|
+
|
|
95
|
+
```tsx
|
|
96
|
+
import { useState } from "react";
|
|
97
|
+
import { Dialog } from "@versini/ui-dialog";
|
|
98
|
+
|
|
99
|
+
function App() {
|
|
100
|
+
const [open, setOpen] = useState(false);
|
|
101
|
+
|
|
102
|
+
return (
|
|
103
|
+
<>
|
|
104
|
+
<button onClick={() => setOpen(true)}>Open Dialog</button>
|
|
105
|
+
<Dialog
|
|
106
|
+
open={open}
|
|
107
|
+
onOpenChange={setOpen}
|
|
108
|
+
title="Animated Dialog"
|
|
109
|
+
animation
|
|
110
|
+
animationType="fade"
|
|
111
|
+
>
|
|
112
|
+
<p>This dialog slides in with a fade animation.</p>
|
|
113
|
+
</Dialog>
|
|
114
|
+
</>
|
|
115
|
+
);
|
|
116
|
+
}
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
### Messagebox Layout
|
|
120
|
+
|
|
121
|
+
```tsx
|
|
122
|
+
import { useState } from "react";
|
|
123
|
+
import { Dialog } from "@versini/ui-dialog";
|
|
124
|
+
|
|
125
|
+
function App() {
|
|
126
|
+
const [open, setOpen] = useState(false);
|
|
127
|
+
|
|
128
|
+
return (
|
|
129
|
+
<>
|
|
130
|
+
<button onClick={() => setOpen(true)}>Open Messagebox</button>
|
|
131
|
+
<Dialog
|
|
132
|
+
open={open}
|
|
133
|
+
onOpenChange={setOpen}
|
|
134
|
+
title="Important Message"
|
|
135
|
+
kind="messagebox"
|
|
136
|
+
>
|
|
137
|
+
<p>This uses the messagebox layout for centered, compact dialogs.</p>
|
|
138
|
+
</Dialog>
|
|
94
139
|
</>
|
|
95
140
|
);
|
|
96
141
|
}
|
|
97
142
|
```
|
|
98
143
|
|
|
99
|
-
###
|
|
144
|
+
### Custom Focus Management
|
|
100
145
|
|
|
101
146
|
```tsx
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
147
|
+
import { useRef, useState } from "react";
|
|
148
|
+
import { Dialog } from "@versini/ui-dialog";
|
|
149
|
+
|
|
150
|
+
function App() {
|
|
151
|
+
const [open, setOpen] = useState(false);
|
|
152
|
+
const submitButtonRef = useRef<HTMLButtonElement>(null);
|
|
153
|
+
|
|
154
|
+
return (
|
|
155
|
+
<>
|
|
156
|
+
<button onClick={() => setOpen(true)}>Open Dialog</button>
|
|
157
|
+
<Dialog
|
|
158
|
+
open={open}
|
|
159
|
+
onOpenChange={setOpen}
|
|
160
|
+
title="Focus Management"
|
|
161
|
+
initialFocus={submitButtonRef}
|
|
162
|
+
>
|
|
163
|
+
<input type="text" placeholder="This is skipped" />
|
|
164
|
+
<button ref={submitButtonRef}>This gets focus</button>
|
|
165
|
+
</Dialog>
|
|
166
|
+
</>
|
|
167
|
+
);
|
|
168
|
+
}
|
|
111
169
|
```
|
|
112
170
|
|
|
113
171
|
## API
|
|
114
172
|
|
|
115
|
-
###
|
|
116
|
-
|
|
117
|
-
| Prop
|
|
118
|
-
|
|
|
119
|
-
|
|
|
120
|
-
|
|
|
121
|
-
|
|
|
122
|
-
|
|
|
123
|
-
|
|
|
124
|
-
| `
|
|
125
|
-
|
|
|
126
|
-
|
|
|
127
|
-
|
|
|
128
|
-
|
|
|
129
|
-
|
|
|
130
|
-
|
|
|
131
|
-
|
|
132
|
-
|
|
173
|
+
### Dialog Props
|
|
174
|
+
|
|
175
|
+
| Prop | Type | Default | Description |
|
|
176
|
+
| ----------------- | ----------------------------------------------------------- | ------------ | ----------------------------------------------------------------------------------------------- |
|
|
177
|
+
| open | `boolean` | - | Controls whether the dialog is visible |
|
|
178
|
+
| onOpenChange | `(open: boolean) => void` | - | Callback fired when the dialog should open or close |
|
|
179
|
+
| title | `string` | - | The title displayed in the dialog header |
|
|
180
|
+
| children | `React.ReactNode` | - | The main content of the dialog |
|
|
181
|
+
| footer | `React.ReactNode` | - | Optional footer content, typically containing action buttons |
|
|
182
|
+
| kind | `"panel" \| "messagebox"` | `"panel"` | Layout type (panel for general content, messagebox for centered alerts) |
|
|
183
|
+
| borderMode | `"dark" \| "medium" \| "light"` | `"light"` | Border styling mode |
|
|
184
|
+
| animation | `boolean` | `false` | Enable animations for opening/closing |
|
|
185
|
+
| animationType | `"slide" \| "fade"` | `"slide"` | Animation style (only used when `animation` is true) |
|
|
186
|
+
| maxWidth | `"small" \| "medium" \| "large"` | `"medium"` | Maximum width for panel layout (does not affect messagebox) |
|
|
187
|
+
| maxHeight | `"small" \| "medium" \| "large"` | - | Maximum height (large for panel, small for messagebox) |
|
|
188
|
+
| blurEffect | `"none" \| "small" \| "medium" \| "large"` | `"none"` | Blur effect for header and footer backgrounds |
|
|
189
|
+
| initialFocus | `number \| React.RefObject<HTMLElement \| null> \| -1` | `0` | Element to focus on open: number = tabbable index, ref = element, -1 = no focus |
|
|
190
|
+
| className | `string` | - | CSS class(es) to add to the dialog element |
|
|
191
|
+
|
|
192
|
+
## Examples
|
|
193
|
+
|
|
194
|
+
### Responsive Dialog
|
|
195
|
+
|
|
196
|
+
```tsx
|
|
197
|
+
import { useState } from "react";
|
|
198
|
+
import { Dialog } from "@versini/ui-dialog";
|
|
199
|
+
|
|
200
|
+
function App() {
|
|
201
|
+
const [open, setOpen] = useState(false);
|
|
202
|
+
|
|
203
|
+
return (
|
|
204
|
+
<>
|
|
205
|
+
<button onClick={() => setOpen(true)}>Open Dialog</button>
|
|
206
|
+
<Dialog
|
|
207
|
+
open={open}
|
|
208
|
+
onOpenChange={setOpen}
|
|
209
|
+
title="Responsive Dialog"
|
|
210
|
+
maxWidth="large"
|
|
211
|
+
maxHeight="medium"
|
|
212
|
+
>
|
|
213
|
+
<p>This dialog adapts to different screen sizes.</p>
|
|
214
|
+
</Dialog>
|
|
215
|
+
</>
|
|
216
|
+
);
|
|
217
|
+
}
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
### Dialog with Blur Effect
|
|
221
|
+
|
|
222
|
+
```tsx
|
|
223
|
+
import { useState } from "react";
|
|
224
|
+
import { Dialog } from "@versini/ui-dialog";
|
|
225
|
+
|
|
226
|
+
function App() {
|
|
227
|
+
const [open, setOpen] = useState(false);
|
|
228
|
+
|
|
229
|
+
return (
|
|
230
|
+
<>
|
|
231
|
+
<button onClick={() => setOpen(true)}>Open Dialog</button>
|
|
232
|
+
<Dialog
|
|
233
|
+
open={open}
|
|
234
|
+
onOpenChange={setOpen}
|
|
235
|
+
title="Dialog with Blur"
|
|
236
|
+
blurEffect="medium"
|
|
237
|
+
>
|
|
238
|
+
<p>The header and footer have a blur effect applied.</p>
|
|
239
|
+
</Dialog>
|
|
240
|
+
</>
|
|
241
|
+
);
|
|
242
|
+
}
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
### Custom Styling
|
|
246
|
+
|
|
247
|
+
```tsx
|
|
248
|
+
import { useState } from "react";
|
|
249
|
+
import { Dialog } from "@versini/ui-dialog";
|
|
250
|
+
|
|
251
|
+
function App() {
|
|
252
|
+
const [open, setOpen] = useState(false);
|
|
253
|
+
|
|
254
|
+
return (
|
|
255
|
+
<>
|
|
256
|
+
<button onClick={() => setOpen(true)}>Open Dialog</button>
|
|
257
|
+
<Dialog
|
|
258
|
+
open={open}
|
|
259
|
+
onOpenChange={setOpen}
|
|
260
|
+
title="Styled Dialog"
|
|
261
|
+
className="rounded-lg shadow-2xl"
|
|
262
|
+
borderMode="dark"
|
|
263
|
+
>
|
|
264
|
+
<p>Custom styling applied to the dialog.</p>
|
|
265
|
+
</Dialog>
|
|
266
|
+
</>
|
|
267
|
+
);
|
|
268
|
+
}
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
### Accessibility
|
|
272
|
+
|
|
273
|
+
```tsx
|
|
274
|
+
import { useState } from "react";
|
|
275
|
+
import { Dialog } from "@versini/ui-dialog";
|
|
276
|
+
|
|
277
|
+
function App() {
|
|
278
|
+
const [open, setOpen] = useState(false);
|
|
279
|
+
|
|
280
|
+
return (
|
|
281
|
+
<>
|
|
282
|
+
<button onClick={() => setOpen(true)}>Open Dialog</button>
|
|
283
|
+
<Dialog
|
|
284
|
+
open={open}
|
|
285
|
+
onOpenChange={setOpen}
|
|
286
|
+
title="Accessible Dialog"
|
|
287
|
+
initialFocus={0}
|
|
288
|
+
>
|
|
289
|
+
<p>The first interactive element receives focus automatically.</p>
|
|
290
|
+
<input type="text" placeholder="Focus is managed for you" />
|
|
291
|
+
</Dialog>
|
|
292
|
+
</>
|
|
293
|
+
);
|
|
294
|
+
}
|
|
295
|
+
```
|
package/dist/index.d.ts
CHANGED
|
@@ -4,21 +4,13 @@ export declare const ANIMATION_FADE = "fade";
|
|
|
4
4
|
|
|
5
5
|
export declare const ANIMATION_SLIDE = "slide";
|
|
6
6
|
|
|
7
|
-
export declare const
|
|
8
|
-
|
|
9
|
-
export declare const MEDIUM = "medium";
|
|
10
|
-
|
|
11
|
-
export declare const MESSAGEBOX_CLASSNAME = "av-messagebox";
|
|
12
|
-
|
|
13
|
-
export declare const NONE = "none";
|
|
14
|
-
|
|
15
|
-
export declare const Panel: ({ open, onOpenChange, title, children, footer, borderMode, kind, className, animation, animationType, maxWidth, maxHeight, blurEffect, initialFocus, }: PanelProps) => JSX.Element;
|
|
7
|
+
export declare const Dialog: ({ open, onOpenChange, title, children, footer, borderMode, kind, className, animation, animationType, maxWidth, maxHeight, blurEffect, initialFocus, }: DialogProps) => JSX.Element;
|
|
16
8
|
|
|
17
|
-
export declare const
|
|
9
|
+
export declare const DIALOG_CLASSNAME = "av-dialog";
|
|
18
10
|
|
|
19
|
-
declare type
|
|
11
|
+
declare type DialogProps = {
|
|
20
12
|
/**
|
|
21
|
-
* Class name to apply to the
|
|
13
|
+
* Class name to apply to the Dialog.
|
|
22
14
|
*/
|
|
23
15
|
className?: string;
|
|
24
16
|
/**
|
|
@@ -36,40 +28,40 @@ declare type PanelProps = {
|
|
|
36
28
|
*/
|
|
37
29
|
open: boolean;
|
|
38
30
|
/**
|
|
39
|
-
* The title to use for the
|
|
31
|
+
* The title to use for the dialog.
|
|
40
32
|
*/
|
|
41
33
|
title: string;
|
|
42
34
|
/**
|
|
43
|
-
* The type of
|
|
35
|
+
* The type of Dialog border.
|
|
44
36
|
*/
|
|
45
|
-
borderMode?: "dark" | "light";
|
|
37
|
+
borderMode?: "dark" | "medium" | "light";
|
|
46
38
|
/**
|
|
47
39
|
* The content to render in the footer.
|
|
48
40
|
*/
|
|
49
41
|
footer?: React.ReactNode;
|
|
50
42
|
/**
|
|
51
|
-
* The type of
|
|
43
|
+
* The type of Dialog. This will change the layout of the Dialog.
|
|
52
44
|
*/
|
|
53
45
|
kind?: "panel" | "messagebox";
|
|
54
46
|
/**
|
|
55
|
-
* Whether or not to animate the opening and closing of the
|
|
47
|
+
* Whether or not to animate the opening and closing of the Dialog.
|
|
56
48
|
*/
|
|
57
49
|
animation?: boolean;
|
|
58
50
|
/**
|
|
59
|
-
* The type of animation to use when opening and closing the
|
|
51
|
+
* The type of animation to use when opening and closing the Dialog.
|
|
60
52
|
* NOTE: This is only used when `animation` is set to `true`.
|
|
61
53
|
* @default "slide"
|
|
62
54
|
*/
|
|
63
55
|
animationType?: "slide" | "fade";
|
|
64
56
|
/**
|
|
65
|
-
* The maximum width of the
|
|
57
|
+
* The maximum width of the Dialog when kind is "panel".
|
|
66
58
|
* NOTE: This does not affect messageboxes, which have a fixed width.
|
|
67
59
|
* @default "medium"
|
|
68
60
|
*/
|
|
69
61
|
maxWidth?: "small" | "medium" | "large";
|
|
70
62
|
/**
|
|
71
|
-
* The maximum height of the
|
|
72
|
-
* @default large for
|
|
63
|
+
* The maximum height of the Dialog or Messagebox.
|
|
64
|
+
* @default large for Dialog, small for Messagebox
|
|
73
65
|
*/
|
|
74
66
|
maxHeight?: "small" | "medium" | "large";
|
|
75
67
|
/**
|
|
@@ -78,7 +70,7 @@ declare type PanelProps = {
|
|
|
78
70
|
*/
|
|
79
71
|
blurEffect?: "none" | "small" | "medium" | "large";
|
|
80
72
|
/**
|
|
81
|
-
* Which element to initially focus when the
|
|
73
|
+
* Which element to initially focus when the Dialog opens.
|
|
82
74
|
* Can be a number (tabbable index, 0 = first tabbable element which is
|
|
83
75
|
* the close button), a ref to an element, or -1 to disable initial focus.
|
|
84
76
|
* @default 0
|
|
@@ -86,6 +78,14 @@ declare type PanelProps = {
|
|
|
86
78
|
initialFocus?: number | React.RefObject<HTMLElement | null>;
|
|
87
79
|
};
|
|
88
80
|
|
|
81
|
+
export declare const LARGE = "large";
|
|
82
|
+
|
|
83
|
+
export declare const MEDIUM = "medium";
|
|
84
|
+
|
|
85
|
+
export declare const MESSAGEBOX_CLASSNAME = "av-messagebox";
|
|
86
|
+
|
|
87
|
+
export declare const NONE = "none";
|
|
88
|
+
|
|
89
89
|
export declare const SMALL = "small";
|
|
90
90
|
|
|
91
91
|
export declare const TYPE_MESSAGEBOX = "messagebox";
|