@magic-spells/dialog-panel 0.3.0 → 1.0.1
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 +163 -114
- package/dist/dialog-panel.cjs.js +287 -219
- package/dist/dialog-panel.cjs.js.map +1 -1
- package/dist/dialog-panel.css +105 -59
- package/dist/dialog-panel.esm.js +287 -215
- package/dist/dialog-panel.esm.js.map +1 -1
- package/dist/dialog-panel.js +276 -405
- package/dist/dialog-panel.js.map +1 -1
- package/dist/dialog-panel.min.css +1 -1
- package/dist/dialog-panel.min.js +1 -1
- package/package.json +8 -17
- package/src/dialog-panel.css +117 -0
- package/src/dialog-panel.js +288 -216
- package/dist/dialog-panel.scss +0 -2
- package/dist/scss/dialog-panel.scss +0 -78
- package/dist/scss/variables.scss +0 -40
- package/src/index.scss +0 -2
- package/src/scss/dialog-panel.scss +0 -78
- package/src/scss/variables.scss +0 -40
package/README.md
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
|
-
# Dialog Panel
|
|
1
|
+
# Dialog Panel
|
|
2
2
|
|
|
3
|
-
A lightweight
|
|
3
|
+
A lightweight web component wrapper for native `<dialog>` elements with state-driven animations.
|
|
4
4
|
|
|
5
5
|
[**Live Demo**](https://magic-spells.github.io/dialog-panel/demo/)
|
|
6
6
|
|
|
7
7
|
## Features
|
|
8
8
|
|
|
9
|
-
-
|
|
10
|
-
- Lightweight
|
|
11
|
-
-
|
|
12
|
-
-
|
|
13
|
-
-
|
|
14
|
-
-
|
|
9
|
+
- **Zero dependencies** - Uses native `<dialog>` for focus trapping and accessibility
|
|
10
|
+
- **Lightweight** - ~3.4kb minified
|
|
11
|
+
- **State-driven animations** - CSS transitions based on `state` attribute
|
|
12
|
+
- **Cross-browser** - Custom `<dialog-backdrop>` for consistent animations (including Firefox)
|
|
13
|
+
- **Accessible** - Native dialog handles focus trap, escape key, and ARIA
|
|
14
|
+
- **Nested dialogs** - Proper stacking and event isolation
|
|
15
15
|
|
|
16
16
|
## Installation
|
|
17
17
|
|
|
@@ -20,172 +20,221 @@ npm install @magic-spells/dialog-panel
|
|
|
20
20
|
```
|
|
21
21
|
|
|
22
22
|
```javascript
|
|
23
|
-
//
|
|
23
|
+
// Import for side effects (registers custom elements)
|
|
24
24
|
import '@magic-spells/dialog-panel';
|
|
25
25
|
```
|
|
26
26
|
|
|
27
|
-
Or include directly in
|
|
27
|
+
Or include directly in HTML:
|
|
28
28
|
|
|
29
29
|
```html
|
|
30
30
|
<script src="https://unpkg.com/@magic-spells/dialog-panel"></script>
|
|
31
|
+
<link rel="stylesheet" href="https://unpkg.com/@magic-spells/dialog-panel/css/min" />
|
|
31
32
|
```
|
|
32
33
|
|
|
33
34
|
## Usage
|
|
34
35
|
|
|
35
36
|
```html
|
|
36
|
-
<button
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
role="dialog"
|
|
47
|
-
aria-modal="true"
|
|
48
|
-
aria-labelledby="dialog-title"
|
|
49
|
-
aria-describedby="dialog-description"
|
|
50
|
-
aria-hidden="true">
|
|
51
|
-
<dialog-overlay></dialog-overlay>
|
|
52
|
-
<dialog-content>
|
|
53
|
-
<button aria-label="Close dialog" data-action-hide-dialog>
|
|
54
|
-
×
|
|
55
|
-
</button>
|
|
56
|
-
<div>
|
|
57
|
-
<h2 id="dialog-title">Dialog Title</h2>
|
|
58
|
-
<p id="dialog-description">
|
|
59
|
-
This is a demonstration of the dialog panel component. Add
|
|
60
|
-
your content here.
|
|
61
|
-
</p>
|
|
62
|
-
</div>
|
|
63
|
-
</dialog-content>
|
|
37
|
+
<button id="open-btn">Open Dialog</button>
|
|
38
|
+
|
|
39
|
+
<dialog-panel id="my-dialog">
|
|
40
|
+
<dialog aria-labelledby="dialog-title">
|
|
41
|
+
<div class="dialog-content">
|
|
42
|
+
<h2 id="dialog-title">Hello!</h2>
|
|
43
|
+
<p>This is a modal dialog.</p>
|
|
44
|
+
<button data-action-hide-dialog>Close</button>
|
|
45
|
+
</div>
|
|
46
|
+
</dialog>
|
|
64
47
|
</dialog-panel>
|
|
65
48
|
|
|
66
49
|
<script>
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
50
|
+
const dialog = document.getElementById('my-dialog');
|
|
51
|
+
document.getElementById('open-btn').addEventListener('click', (e) => {
|
|
52
|
+
dialog.show(e.target);
|
|
53
|
+
});
|
|
70
54
|
</script>
|
|
71
55
|
```
|
|
72
56
|
|
|
73
57
|
## How It Works
|
|
74
58
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
-
|
|
80
|
-
- Pressing
|
|
81
|
-
-
|
|
59
|
+
1. Wrap a native `<dialog>` element inside `<dialog-panel>`
|
|
60
|
+
2. Call `show(triggerElement)` to open with animation
|
|
61
|
+
3. The `state` attribute transitions: `hidden` → `showing` → `shown`
|
|
62
|
+
4. Close via:
|
|
63
|
+
- Clicking backdrop
|
|
64
|
+
- Pressing Escape
|
|
65
|
+
- Clicking any element with `data-action-hide-dialog`
|
|
66
|
+
- Calling `hide()`
|
|
67
|
+
5. The `state` attribute transitions: `shown` → `hiding` → `hidden`
|
|
68
|
+
6. Focus returns to the trigger element
|
|
82
69
|
|
|
83
|
-
##
|
|
70
|
+
## State Machine
|
|
84
71
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
72
|
+
```
|
|
73
|
+
hidden → showing → shown → hiding → hidden
|
|
74
|
+
```
|
|
88
75
|
|
|
89
|
-
|
|
76
|
+
The `state` attribute on `<dialog-panel>` drives all CSS animations:
|
|
90
77
|
|
|
91
78
|
```css
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
79
|
+
dialog-panel[state='showing'] > dialog { /* entering */ }
|
|
80
|
+
dialog-panel[state='shown'] > dialog { /* fully visible */ }
|
|
81
|
+
dialog-panel[state='hiding'] > dialog { /* exiting */ }
|
|
82
|
+
dialog-panel[state='hidden'] > dialog { /* hidden */ }
|
|
83
|
+
```
|
|
95
84
|
|
|
96
|
-
|
|
97
|
-
--dp-overlay-background: rgba(0, 0, 0, 0.7);
|
|
98
|
-
--dp-overlay-backdrop-filter: blur(5px) saturate(120%);
|
|
85
|
+
## API
|
|
99
86
|
|
|
100
|
-
|
|
101
|
-
--dp-content-background: #f8f8f8;
|
|
87
|
+
### Methods
|
|
102
88
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
89
|
+
| Method | Description |
|
|
90
|
+
|--------|-------------|
|
|
91
|
+
| `show(triggerEl?)` | Opens the dialog. Pass trigger element for focus return. Returns `false` if cancelled. |
|
|
92
|
+
| `hide(triggerEl?)` | Closes the dialog. Returns `false` if cancelled. |
|
|
93
|
+
|
|
94
|
+
### Properties (read-only)
|
|
95
|
+
|
|
96
|
+
| Property | Type | Description |
|
|
97
|
+
|----------|------|-------------|
|
|
98
|
+
| `state` | `string` | Current state: `'hidden'`, `'showing'`, `'shown'`, `'hiding'` |
|
|
99
|
+
| `dialog` | `HTMLDialogElement` | Reference to inner `<dialog>` |
|
|
100
|
+
| `isOpen` | `boolean` | `true` if `showing` or `shown` |
|
|
101
|
+
| `triggerElement` | `HTMLElement \| null` | Element that triggered the current action |
|
|
102
|
+
|
|
103
|
+
### Events
|
|
108
104
|
|
|
109
|
-
|
|
105
|
+
| Event | Cancelable | Description |
|
|
106
|
+
|-------|------------|-------------|
|
|
107
|
+
| `beforeShow` | Yes | Fired before showing. Call `preventDefault()` to cancel. |
|
|
108
|
+
| `shown` | No | Fired after show animation completes. |
|
|
109
|
+
| `beforeHide` | Yes | Fired before hiding. Call `preventDefault()` to cancel. |
|
|
110
|
+
| `hidden` | No | Fired after hide animation completes. |
|
|
110
111
|
|
|
111
|
-
|
|
112
|
+
Event `detail` includes:
|
|
113
|
+
- `triggerElement` - Element that triggered the action
|
|
114
|
+
- `result` - Value from `data-result` attribute (if any)
|
|
115
|
+
- `state` - Current state
|
|
112
116
|
|
|
113
|
-
|
|
114
|
-
// Option 1: Import the compiled CSS
|
|
115
|
-
@import '@magic-spells/dialog-panel/css';
|
|
117
|
+
### Data Attributes
|
|
116
118
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
$content-background: #f8f8f8,
|
|
122
|
-
$transition-duration: 400ms,
|
|
123
|
-
$transition-timing: cubic-bezier(0.4, 0, 0.2, 1)
|
|
124
|
-
);
|
|
119
|
+
| Attribute | Description |
|
|
120
|
+
|-----------|-------------|
|
|
121
|
+
| `data-action-hide-dialog` | Clicking this element closes the dialog |
|
|
122
|
+
| `data-result` | Value passed to `hidden` event when this element triggers close |
|
|
125
123
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
124
|
+
## Styling
|
|
125
|
+
|
|
126
|
+
### Default CSS
|
|
127
|
+
|
|
128
|
+
Import the default styles:
|
|
129
|
+
|
|
130
|
+
```javascript
|
|
131
|
+
import '@magic-spells/dialog-panel';
|
|
132
|
+
import '@magic-spells/dialog-panel/css';
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
Or in HTML:
|
|
136
|
+
|
|
137
|
+
```html
|
|
138
|
+
<link rel="stylesheet" href="https://unpkg.com/@magic-spells/dialog-panel/css/min" />
|
|
131
139
|
```
|
|
132
140
|
|
|
133
|
-
|
|
141
|
+
### Custom Styling
|
|
134
142
|
|
|
135
|
-
|
|
143
|
+
Override styles using the `state` attribute:
|
|
136
144
|
|
|
137
145
|
```css
|
|
138
|
-
|
|
139
|
-
|
|
146
|
+
/* Custom backdrop */
|
|
147
|
+
dialog-backdrop {
|
|
148
|
+
background: rgba(0, 0, 0, 0.5);
|
|
149
|
+
backdrop-filter: blur(5px);
|
|
140
150
|
}
|
|
141
151
|
|
|
142
|
-
dialog
|
|
143
|
-
|
|
152
|
+
/* Custom dialog appearance */
|
|
153
|
+
dialog-panel > dialog {
|
|
154
|
+
border-radius: 1rem;
|
|
155
|
+
box-shadow: 0 25px 50px rgba(0, 0, 0, 0.25);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/* Custom animations */
|
|
159
|
+
dialog-panel[state='shown'] > dialog {
|
|
160
|
+
opacity: 1;
|
|
161
|
+
transform: scale(1);
|
|
162
|
+
transition: all 0.3s ease-out;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
dialog-panel[state='hiding'] > dialog {
|
|
166
|
+
opacity: 0;
|
|
167
|
+
transform: scale(0.95);
|
|
168
|
+
transition: all 0.2s ease-in;
|
|
144
169
|
}
|
|
145
170
|
```
|
|
146
171
|
|
|
147
|
-
|
|
172
|
+
## Nested Dialogs
|
|
148
173
|
|
|
149
|
-
|
|
174
|
+
Dialogs can be nested inside other dialogs:
|
|
150
175
|
|
|
151
|
-
|
|
152
|
-
-
|
|
176
|
+
```html
|
|
177
|
+
<dialog-panel id="outer">
|
|
178
|
+
<dialog>
|
|
179
|
+
<p>Outer dialog content</p>
|
|
180
|
+
<button id="open-inner">Open Inner</button>
|
|
181
|
+
|
|
182
|
+
<dialog-panel id="inner">
|
|
183
|
+
<dialog>
|
|
184
|
+
<p>Inner dialog content</p>
|
|
185
|
+
<button data-action-hide-dialog>Close Inner</button>
|
|
186
|
+
</dialog>
|
|
187
|
+
</dialog-panel>
|
|
188
|
+
</dialog>
|
|
189
|
+
</dialog-panel>
|
|
190
|
+
```
|
|
153
191
|
|
|
154
|
-
|
|
192
|
+
Each dialog manages its own backdrop and events independently.
|
|
155
193
|
|
|
156
|
-
|
|
194
|
+
## Dialog Backdrop
|
|
157
195
|
|
|
158
|
-
|
|
159
|
-
- `show`: Fired when the dialog has been shown (after transitions).
|
|
160
|
-
- `beforeHide`: Fired before the dialog starts to hide. Cancelable - you can call `preventDefault()` to prevent the dialog from closing.
|
|
161
|
-
- `hide`: Fired when the dialog has started hiding (transition begins).
|
|
162
|
-
- `afterHide`: Fired when the dialog has completed its hide transition.
|
|
196
|
+
The `<dialog-backdrop>` element is auto-created if not present. It provides:
|
|
163
197
|
|
|
164
|
-
|
|
198
|
+
- Consistent cross-browser animations (native `::backdrop` doesn't animate in Firefox)
|
|
199
|
+
- Click-to-close functionality
|
|
200
|
+
- Custom styling support
|
|
165
201
|
|
|
166
|
-
|
|
202
|
+
## Preventing Close
|
|
167
203
|
|
|
168
|
-
|
|
169
|
-
const dialog = document.getElementById('my-dialog');
|
|
204
|
+
Use `beforeHide` to prevent closing:
|
|
170
205
|
|
|
171
|
-
|
|
206
|
+
```javascript
|
|
172
207
|
dialog.addEventListener('beforeHide', (e) => {
|
|
173
|
-
if (
|
|
174
|
-
e.preventDefault();
|
|
175
|
-
|
|
208
|
+
if (formHasUnsavedChanges) {
|
|
209
|
+
e.preventDefault();
|
|
210
|
+
showConfirmation();
|
|
176
211
|
}
|
|
177
212
|
});
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
## Result Values
|
|
216
|
+
|
|
217
|
+
Track which button closed the dialog:
|
|
218
|
+
|
|
219
|
+
```html
|
|
220
|
+
<button data-action-hide-dialog data-result="save">Save</button>
|
|
221
|
+
<button data-action-hide-dialog data-result="cancel">Cancel</button>
|
|
222
|
+
```
|
|
178
223
|
|
|
179
|
-
|
|
180
|
-
dialog.addEventListener('
|
|
181
|
-
|
|
182
|
-
|
|
224
|
+
```javascript
|
|
225
|
+
dialog.addEventListener('hidden', (e) => {
|
|
226
|
+
if (e.detail.result === 'save') {
|
|
227
|
+
saveData();
|
|
228
|
+
}
|
|
183
229
|
});
|
|
184
230
|
```
|
|
185
231
|
|
|
186
232
|
## Browser Support
|
|
187
233
|
|
|
188
|
-
|
|
234
|
+
Modern browsers with support for:
|
|
235
|
+
- Custom Elements v1
|
|
236
|
+
- Native `<dialog>` element
|
|
237
|
+
- CSS `:has()` selector
|
|
189
238
|
|
|
190
239
|
## License
|
|
191
240
|
|