@versini/ui-dialog 8.1.1 → 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 CHANGED
@@ -1,132 +1,295 @@
1
- # @versini/ui-panel
1
+ # @versini/ui-dialog
2
2
 
3
- [![npm version](https://img.shields.io/npm/v/@versini/ui-panel?style=flat-square)](https://www.npmjs.com/package/@versini/ui-panel)
4
- ![npm package minimized gzipped size](<https://img.shields.io/bundlejs/size/%40versini%2Fui-panel?style=flat-square&label=size%20(gzip)>)
3
+ [![npm version](https://img.shields.io/npm/v/@versini/ui-dialog?style=flat-square)](https://www.npmjs.com/package/@versini/ui-dialog)
4
+ ![npm package minimized gzipped size](<https://img.shields.io/bundlejs/size/%40versini%2Fui-dialog?style=flat-square&label=size%20(gzip)>)
5
5
 
6
- > An accessible React slide-out panel component built with TypeScript and TailwindCSS.
6
+ > A lightweight and accessible React dialog component built with TypeScript and TailwindCSS.
7
7
 
8
- The Panel component provides slide-out panels and drawers with focus management, keyboard navigation, document title management, optional animations, and customizable positioning / sizing.
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
- - **🪟 Versatile Layouts**: Standard panel and message box variants (`kind` prop)
25
- - **🎯 Focus Management**: Uses underlying modal primitives for proper focus trapping & return
26
- - **♿ Accessible**: ARIA compliant structure with heading, description, close control
27
- - **🎬 Optional Animations**: Slide or fade entrance animations (`animation` / `animationType`)
28
- - **📐 Responsive Sizing**: Predefined max widths (`small`, `medium`, `large`) above md breakpoint
29
- - **🧩 Composable**: Footer slot for actions / extra content
30
- - **🧪 Type Safe**: Fully typed props with inline documentation
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-panel
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 Panel</button>
52
- <Panel title="Panel Title" open={open} onOpenChange={setOpen}>
53
- Panel content goes here.
54
- </Panel>
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
- ## Examples
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 MessageBoxExample() {
69
+ function App() {
69
70
  const [open, setOpen] = useState(false);
71
+
70
72
  return (
71
73
  <>
72
- <button onClick={() => setOpen(true)}>Show Message</button>
73
- <Panel
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 gap-2">
80
- <button
81
- className="px-3 py-1 rounded bg-surface-lighter"
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
- Your session has expired. Please sign in again to continue.
93
- </Panel>
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
- ### Animated Panel (Fade)
144
+ ### Custom Focus Management
100
145
 
101
146
  ```tsx
102
- <Panel
103
- title="Animated Panel"
104
- open={open}
105
- onOpenChange={setOpen}
106
- animation
107
- animationType="fade"
108
- >
109
- Content with fade animation.
110
- </Panel>
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
- ### Panel Props
116
-
117
- | Prop | Type | Default | Description |
118
- | --------------- | ------------------------------------------------ | ---------- | ----------------------------------------------------------------------------------------------------------------------------------------- |
119
- | `open` | `boolean` | - | Whether the panel is open. |
120
- | `onOpenChange` | `(open: boolean) => void` | - | Callback fired when open state changes. |
121
- | `title` | `string` | - | Title displayed in the header (also used to augment `document.title`). |
122
- | `children` | `React.ReactNode` | - | Main content of the panel. |
123
- | `footer` | `React.ReactNode` | - | Optional footer content (actions, etc.). |
124
- | `className` | `string` | - | Extra classes applied to width wrapper (overrides default width). |
125
- | `borderMode` | `"dark" \| "light"` | `"light"` | Visual style of border / surface. |
126
- | `kind` | `"panel" \| "messagebox"` | `"panel"` | Layout variant. |
127
- | `animation` | `boolean` | `false` | Enable entrance animation. |
128
- | `animationType` | `"slide" \| "fade"` | `"slide"` | Animation style (only when `animation` is true). |
129
- | `maxWidth` | `"small" \| "medium" \| "large"` | `"medium"` | Max width applied ( md breakpoint) for `kind="panel"`. |
130
- | `initialFocus` | `number \| React.RefObject<HTMLElement \| null>` | `0` | Which element to initially focus when the Panel opens. Can be a tabbable index (0 = close button), a ref to an element, or -1 to disable. |
131
-
132
- > Also inherits any valid props for the underlying modal primitives where relevant.
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 LARGE = "large";
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 PANEL_CLASSNAME = "av-panel";
9
+ export declare const DIALOG_CLASSNAME = "av-dialog";
18
10
 
19
- declare type PanelProps = {
11
+ declare type DialogProps = {
20
12
  /**
21
- * Class name to apply to the Panel - this will ONLY override the default width styles.
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 panel.
31
+ * The title to use for the dialog.
40
32
  */
41
33
  title: string;
42
34
  /**
43
- * The type of Panel border.
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 Panel. This will change the layout of the Panel.
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 Panel.
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 Panel.
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 Panel when kind is "panel".
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 Panel or Messagebox.
72
- * @default large for Panel, small for Messagebox
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 Panel opens.
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";