@magic-spells/dialog-panel 0.1.0 → 0.2.2

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,511 @@
1
+ (function (global, factory) {
2
+ typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
3
+ typeof define === 'function' && define.amd ? define(['exports'], factory) :
4
+ (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.DialogPanel = {}));
5
+ })(this, (function (exports) { 'use strict';
6
+
7
+ /**
8
+ * Retrieves all focusable elements within a given container.
9
+ *
10
+ * @param {HTMLElement} container - The container element to search for focusable elements.
11
+ * @returns {HTMLElement[]} An array of focusable elements found within the container.
12
+ */
13
+ const getFocusableElements = (container) => {
14
+ const focusableSelectors =
15
+ 'summary, a[href], button:not(:disabled), [tabindex]:not([tabindex^="-"]):not(focus-trap-start):not(focus-trap-end), [draggable], area, input:not([type=hidden]):not(:disabled), select:not(:disabled), textarea:not(:disabled), object, iframe';
16
+ return Array.from(container.querySelectorAll(focusableSelectors));
17
+ };
18
+
19
+ class FocusTrap extends HTMLElement {
20
+ /** @type {boolean} Indicates whether the styles have been injected into the DOM. */
21
+ static styleInjected = false;
22
+
23
+ constructor() {
24
+ super();
25
+ this.trapStart = null;
26
+ this.trapEnd = null;
27
+
28
+ // Inject styles only once, when the first FocusTrap instance is created.
29
+ if (!FocusTrap.styleInjected) {
30
+ this.injectStyles();
31
+ FocusTrap.styleInjected = true;
32
+ }
33
+ }
34
+
35
+ /**
36
+ * Injects necessary styles for the focus trap into the document's head.
37
+ * This ensures that focus-trap-start and focus-trap-end elements are hidden.
38
+ */
39
+ injectStyles() {
40
+ const style = document.createElement('style');
41
+ style.textContent = `
42
+ focus-trap-start,
43
+ focus-trap-end {
44
+ position: absolute;
45
+ width: 1px;
46
+ height: 1px;
47
+ margin: -1px;
48
+ padding: 0;
49
+ border: 0;
50
+ clip: rect(0, 0, 0, 0);
51
+ overflow: hidden;
52
+ white-space: nowrap;
53
+ }
54
+ `;
55
+ document.head.appendChild(style);
56
+ }
57
+
58
+ /**
59
+ * Called when the element is connected to the DOM.
60
+ * Sets up the focus trap and adds the keydown event listener.
61
+ */
62
+ connectedCallback() {
63
+ this.setupTrap();
64
+ this.addEventListener('keydown', this.handleKeyDown);
65
+ }
66
+
67
+ /**
68
+ * Called when the element is disconnected from the DOM.
69
+ * Removes the keydown event listener.
70
+ */
71
+ disconnectedCallback() {
72
+ this.removeEventListener('keydown', this.handleKeyDown);
73
+ }
74
+
75
+ /**
76
+ * Sets up the focus trap by adding trap start and trap end elements.
77
+ * Focuses the trap start element to initiate the focus trap.
78
+ */
79
+ setupTrap() {
80
+ // check to see it there are any focusable children
81
+ const focusableElements = getFocusableElements(this);
82
+ // exit if there aren't any
83
+ if (focusableElements.length === 0) return;
84
+
85
+ // create trap start and end elements
86
+ this.trapStart = document.createElement('focus-trap-start');
87
+ this.trapEnd = document.createElement('focus-trap-end');
88
+
89
+ // add to DOM
90
+ this.prepend(this.trapStart);
91
+ this.append(this.trapEnd);
92
+ }
93
+
94
+ /**
95
+ * Handles the keydown event. If the Escape key is pressed, the focus trap is exited.
96
+ *
97
+ * @param {KeyboardEvent} e - The keyboard event object.
98
+ */
99
+ handleKeyDown = (e) => {
100
+ if (e.key === 'Escape') {
101
+ e.preventDefault();
102
+ this.exitTrap();
103
+ }
104
+ };
105
+
106
+ /**
107
+ * Exits the focus trap by hiding the current container and shifting focus
108
+ * back to the trigger element that opened the trap.
109
+ */
110
+ exitTrap() {
111
+ const container = this.closest('[aria-hidden="false"]');
112
+ if (!container) return;
113
+
114
+ container.setAttribute('aria-hidden', 'true');
115
+
116
+ const trigger = document.querySelector(
117
+ `[aria-expanded="true"][aria-controls="${container.id}"]`
118
+ );
119
+ if (trigger) {
120
+ trigger.setAttribute('aria-expanded', 'false');
121
+ trigger.focus();
122
+ }
123
+ }
124
+ }
125
+
126
+ class FocusTrapStart extends HTMLElement {
127
+ /**
128
+ * Called when the element is connected to the DOM.
129
+ * Sets the tabindex and adds the focus event listener.
130
+ */
131
+ connectedCallback() {
132
+ this.setAttribute('tabindex', '0');
133
+ this.addEventListener('focus', this.handleFocus);
134
+ }
135
+
136
+ /**
137
+ * Called when the element is disconnected from the DOM.
138
+ * Removes the focus event listener.
139
+ */
140
+ disconnectedCallback() {
141
+ this.removeEventListener('focus', this.handleFocus);
142
+ }
143
+
144
+ /**
145
+ * Handles the focus event. If focus moves backwards from the first focusable element,
146
+ * it is cycled to the last focusable element, and vice versa.
147
+ *
148
+ * @param {FocusEvent} e - The focus event object.
149
+ */
150
+ handleFocus = (e) => {
151
+ const trap = this.closest('focus-trap');
152
+ const focusableElements = getFocusableElements(trap);
153
+
154
+ if (focusableElements.length === 0) return;
155
+
156
+ const firstElement = focusableElements[0];
157
+ const lastElement =
158
+ focusableElements[focusableElements.length - 1];
159
+
160
+ if (e.relatedTarget === firstElement) {
161
+ lastElement.focus();
162
+ } else {
163
+ firstElement.focus();
164
+ }
165
+ };
166
+ }
167
+
168
+ class FocusTrapEnd extends HTMLElement {
169
+ /**
170
+ * Called when the element is connected to the DOM.
171
+ * Sets the tabindex and adds the focus event listener.
172
+ */
173
+ connectedCallback() {
174
+ this.setAttribute('tabindex', '0');
175
+ this.addEventListener('focus', this.handleFocus);
176
+ }
177
+
178
+ /**
179
+ * Called when the element is disconnected from the DOM.
180
+ * Removes the focus event listener.
181
+ */
182
+ disconnectedCallback() {
183
+ this.removeEventListener('focus', this.handleFocus);
184
+ }
185
+
186
+ /**
187
+ * Handles the focus event. When the trap end is focused, focus is shifted back to the trap start.
188
+ */
189
+ handleFocus = () => {
190
+ const trap = this.closest('focus-trap');
191
+ const trapStart = trap.querySelector('focus-trap-start');
192
+ trapStart.focus();
193
+ };
194
+ }
195
+
196
+ customElements.define('focus-trap', FocusTrap);
197
+ customElements.define('focus-trap-start', FocusTrapStart);
198
+ customElements.define('focus-trap-end', FocusTrapEnd);
199
+
200
+ /**
201
+ * Custom element that creates an accessible modal dialog panel with focus management
202
+ * @extends HTMLElement
203
+ */
204
+ class DialogPanel extends HTMLElement {
205
+ #handleTransitionEnd;
206
+ #scrollPosition = 0;
207
+
208
+ /**
209
+ * Clean up event listeners when component is removed from DOM
210
+ */
211
+ disconnectedCallback() {
212
+ const _ = this;
213
+ if (_.contentPanel) {
214
+ _.contentPanel.removeEventListener(
215
+ 'transitionend',
216
+ _.#handleTransitionEnd
217
+ );
218
+ }
219
+
220
+ // Ensure body scroll is restored if component is removed while open
221
+ document.body.classList.remove('overflow-hidden');
222
+ this.#restoreScroll();
223
+ }
224
+
225
+ /**
226
+ * Saves current scroll position and locks body scrolling
227
+ * @private
228
+ */
229
+ #lockScroll() {
230
+ const _ = this;
231
+ // Save current scroll position
232
+ _.#scrollPosition = window.pageYOffset;
233
+
234
+ // Apply fixed position to body
235
+ document.body.classList.add('overflow-hidden');
236
+ document.body.style.top = `-${_.#scrollPosition}px`;
237
+ }
238
+
239
+ /**
240
+ * Restores scroll position when dialog is closed
241
+ * @private
242
+ */
243
+ #restoreScroll() {
244
+ const _ = this;
245
+ // Remove fixed positioning
246
+ document.body.classList.remove('overflow-hidden');
247
+ document.body.style.removeProperty('top');
248
+
249
+ // Restore scroll position
250
+ window.scrollTo(0, _.#scrollPosition);
251
+ }
252
+ /**
253
+ * Initializes the dialog panel, sets up focus trap and overlay
254
+ */
255
+ constructor() {
256
+ super();
257
+ const _ = this;
258
+ _.id = _.getAttribute('id');
259
+ _.setAttribute('role', 'dialog');
260
+ _.setAttribute('aria-modal', 'true');
261
+ _.setAttribute('aria-hidden', 'true');
262
+
263
+ _.contentPanel = _.querySelector('dialog-content');
264
+ _.focusTrap = document.createElement('focus-trap');
265
+ _.triggerEl = null;
266
+
267
+ // Create a handler for transition end events
268
+ _.#handleTransitionEnd = (e) => {
269
+ if (
270
+ e.propertyName === 'opacity' &&
271
+ _.getAttribute('aria-hidden') === 'true'
272
+ ) {
273
+ _.contentPanel.classList.add('hidden');
274
+
275
+ // Dispatch afterHide event - dialog has completed its transition
276
+ _.dispatchEvent(
277
+ new CustomEvent('afterHide', {
278
+ bubbles: true,
279
+ detail: { triggerElement: _.triggerEl },
280
+ })
281
+ );
282
+ }
283
+ };
284
+
285
+ // Ensure we have labelledby and describedby references
286
+ if (!_.getAttribute('aria-labelledby')) {
287
+ const heading = _.querySelector('h1, h2, h3');
288
+ if (heading && !heading.id) {
289
+ heading.id = `${_.id}-title`;
290
+ }
291
+ if (heading?.id) {
292
+ _.setAttribute('aria-labelledby', heading.id);
293
+ }
294
+ }
295
+
296
+ _.contentPanel.parentNode.insertBefore(
297
+ _.focusTrap,
298
+ _.contentPanel
299
+ );
300
+ _.focusTrap.appendChild(_.contentPanel);
301
+
302
+ _.focusTrap.setupTrap();
303
+
304
+ // Add modal overlay
305
+ _.prepend(document.createElement('dialog-overlay'));
306
+ _.#bindUI();
307
+ _.#bindKeyboard();
308
+ }
309
+
310
+ /**
311
+ * Binds click events for showing and hiding the dialog
312
+ * @private
313
+ */
314
+ #bindUI() {
315
+ const _ = this;
316
+
317
+ // Handle trigger buttons
318
+ document.addEventListener('click', (e) => {
319
+ const trigger = e.target.closest(`[aria-controls="${_.id}"]`);
320
+ if (!trigger) return;
321
+
322
+ if (trigger.getAttribute('data-prevent-default') === 'true') {
323
+ e.preventDefault();
324
+ }
325
+
326
+ _.show(trigger);
327
+ });
328
+
329
+ // Handle close buttons
330
+ _.addEventListener('click', (e) => {
331
+ if (!e.target.closest('[data-action="hide-dialog"]')) return;
332
+ _.hide();
333
+ });
334
+
335
+ // Add transition end listener
336
+ _.contentPanel.addEventListener(
337
+ 'transitionend',
338
+ _.#handleTransitionEnd
339
+ );
340
+ }
341
+
342
+ /**
343
+ * Binds keyboard events for accessibility
344
+ * @private
345
+ */
346
+ #bindKeyboard() {
347
+ this.addEventListener('keydown', (e) => {
348
+ if (e.key === 'Escape') {
349
+ this.hide();
350
+ }
351
+ });
352
+ }
353
+
354
+ /**
355
+ * Shows the dialog and traps focus within it
356
+ * @param {HTMLElement} [triggerEl=null] - The element that triggered the dialog
357
+ * @fires DialogPanel#beforeShow - Fired before the dialog starts to show
358
+ * @fires DialogPanel#show - Fired when the dialog has been shown
359
+ * @returns {boolean} False if the show was prevented by a beforeShow event handler
360
+ */
361
+ show(triggerEl = null) {
362
+ const _ = this;
363
+ _.triggerEl = triggerEl || false;
364
+
365
+ // Dispatch beforeShow event - allows preventing the dialog from opening
366
+ const beforeShowEvent = new CustomEvent('beforeShow', {
367
+ bubbles: true,
368
+ cancelable: true,
369
+ detail: { triggerElement: _.triggerEl },
370
+ });
371
+
372
+ const showAllowed = _.dispatchEvent(beforeShowEvent);
373
+
374
+ // If event was canceled (preventDefault was called), don't show the dialog
375
+ if (!showAllowed) return false;
376
+
377
+ // Remove the hidden class first to ensure content is rendered
378
+ _.contentPanel.classList.remove('hidden');
379
+
380
+ // Give the browser a moment to process before starting animation
381
+ requestAnimationFrame(() => {
382
+ // Update ARIA states
383
+ _.setAttribute('aria-hidden', 'false');
384
+ if (_.triggerEl) {
385
+ _.triggerEl.setAttribute('aria-expanded', 'true');
386
+ }
387
+
388
+ // Lock body scrolling and save scroll position
389
+ _.#lockScroll();
390
+
391
+ // Focus management
392
+ const firstFocusable = _.querySelector(
393
+ 'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])'
394
+ );
395
+ if (firstFocusable) {
396
+ requestAnimationFrame(() => {
397
+ firstFocusable.focus();
398
+ });
399
+ }
400
+
401
+ // Dispatch show event - dialog is now visible
402
+ _.dispatchEvent(
403
+ new CustomEvent('show', {
404
+ bubbles: true,
405
+ detail: { triggerElement: _.triggerEl },
406
+ })
407
+ );
408
+ });
409
+
410
+ return true;
411
+ }
412
+
413
+ /**
414
+ * Hides the dialog and restores focus
415
+ * @fires DialogPanel#beforeHide - Fired before the dialog starts to hide
416
+ * @fires DialogPanel#hide - Fired when the dialog has started hiding (transition begins)
417
+ * @fires DialogPanel#afterHide - Fired when the dialog has completed its hide transition
418
+ * @returns {boolean} False if the hide was prevented by a beforeHide event handler
419
+ */
420
+ hide() {
421
+ const _ = this;
422
+
423
+ // Dispatch beforeHide event - allows preventing the dialog from closing
424
+ const beforeHideEvent = new CustomEvent('beforeHide', {
425
+ bubbles: true,
426
+ cancelable: true,
427
+ detail: { triggerElement: _.triggerEl },
428
+ });
429
+
430
+ const hideAllowed = _.dispatchEvent(beforeHideEvent);
431
+
432
+ // If event was canceled (preventDefault was called), don't hide the dialog
433
+ if (!hideAllowed) return false;
434
+
435
+ // Restore body scroll and scroll position
436
+ _.#restoreScroll();
437
+
438
+ // Update ARIA states
439
+ if (_.triggerEl) {
440
+ // remove focus from modal panel first
441
+ _.triggerEl.focus();
442
+ // mark trigger as no longer expanded
443
+ _.triggerEl.setAttribute('aria-expanded', 'false');
444
+ }
445
+
446
+ // Set aria-hidden to start transition
447
+ // The transitionend event handler will add display:none when complete
448
+ _.setAttribute('aria-hidden', 'true');
449
+
450
+ // Dispatch hide event - dialog is now starting to hide
451
+ _.dispatchEvent(
452
+ new CustomEvent('hide', {
453
+ bubbles: true,
454
+ detail: { triggerElement: _.triggerEl },
455
+ })
456
+ );
457
+
458
+ return true;
459
+ }
460
+ }
461
+
462
+ /**
463
+ * Custom element that creates a clickable overlay for the dialog
464
+ * @extends HTMLElement
465
+ */
466
+ class DialogOverlay extends HTMLElement {
467
+ constructor() {
468
+ super();
469
+ this.setAttribute('tabindex', '-1'); // Changed to -1 as it shouldn't be focusable
470
+ this.setAttribute('aria-hidden', 'true');
471
+ this.dialogPanel = this.closest('dialog-panel');
472
+ this.#bindUI();
473
+ }
474
+
475
+ #bindUI() {
476
+ this.addEventListener('click', () => {
477
+ this.dialogPanel.hide();
478
+ });
479
+ }
480
+ }
481
+
482
+ /**
483
+ * Custom element that wraps the content of the dialog
484
+ * @extends HTMLElement
485
+ */
486
+ class DialogContent extends HTMLElement {
487
+ constructor() {
488
+ super();
489
+ this.setAttribute('role', 'document'); // Optional: helps with document structure
490
+ }
491
+ }
492
+
493
+ if (!customElements.get('dialog-panel')) {
494
+ customElements.define('dialog-panel', DialogPanel);
495
+ }
496
+ if (!customElements.get('dialog-overlay')) {
497
+ customElements.define('dialog-overlay', DialogOverlay);
498
+ }
499
+ if (!customElements.get('dialog-content')) {
500
+ customElements.define('dialog-content', DialogContent);
501
+ }
502
+
503
+ exports.DialogContent = DialogContent;
504
+ exports.DialogOverlay = DialogOverlay;
505
+ exports.DialogPanel = DialogPanel;
506
+ exports.default = DialogPanel;
507
+
508
+ Object.defineProperty(exports, '__esModule', { value: true });
509
+
510
+ }));
511
+ //# sourceMappingURL=dialog-panel.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dialog-panel.js","sources":["../node_modules/@magic-spells/focus-trap/dist/focus-trap.esm.js","../src/dialog-panel.js"],"sourcesContent":["/**\n * Retrieves all focusable elements within a given container.\n *\n * @param {HTMLElement} container - The container element to search for focusable elements.\n * @returns {HTMLElement[]} An array of focusable elements found within the container.\n */\nconst getFocusableElements = (container) => {\n\tconst focusableSelectors =\n\t\t'summary, a[href], button:not(:disabled), [tabindex]:not([tabindex^=\"-\"]):not(focus-trap-start):not(focus-trap-end), [draggable], area, input:not([type=hidden]):not(:disabled), select:not(:disabled), textarea:not(:disabled), object, iframe';\n\treturn Array.from(container.querySelectorAll(focusableSelectors));\n};\n\nclass FocusTrap extends HTMLElement {\n\t/** @type {boolean} Indicates whether the styles have been injected into the DOM. */\n\tstatic styleInjected = false;\n\n\tconstructor() {\n\t\tsuper();\n\t\tthis.trapStart = null;\n\t\tthis.trapEnd = null;\n\n\t\t// Inject styles only once, when the first FocusTrap instance is created.\n\t\tif (!FocusTrap.styleInjected) {\n\t\t\tthis.injectStyles();\n\t\t\tFocusTrap.styleInjected = true;\n\t\t}\n\t}\n\n\t/**\n\t * Injects necessary styles for the focus trap into the document's head.\n\t * This ensures that focus-trap-start and focus-trap-end elements are hidden.\n\t */\n\tinjectStyles() {\n\t\tconst style = document.createElement('style');\n\t\tstyle.textContent = `\n focus-trap-start,\n focus-trap-end {\n position: absolute;\n width: 1px;\n height: 1px;\n margin: -1px;\n padding: 0;\n border: 0;\n clip: rect(0, 0, 0, 0);\n overflow: hidden;\n white-space: nowrap;\n }\n `;\n\t\tdocument.head.appendChild(style);\n\t}\n\n\t/**\n\t * Called when the element is connected to the DOM.\n\t * Sets up the focus trap and adds the keydown event listener.\n\t */\n\tconnectedCallback() {\n\t\tthis.setupTrap();\n\t\tthis.addEventListener('keydown', this.handleKeyDown);\n\t}\n\n\t/**\n\t * Called when the element is disconnected from the DOM.\n\t * Removes the keydown event listener.\n\t */\n\tdisconnectedCallback() {\n\t\tthis.removeEventListener('keydown', this.handleKeyDown);\n\t}\n\n\t/**\n\t * Sets up the focus trap by adding trap start and trap end elements.\n\t * Focuses the trap start element to initiate the focus trap.\n\t */\n\tsetupTrap() {\n\t\t// check to see it there are any focusable children\n\t\tconst focusableElements = getFocusableElements(this);\n\t\t// exit if there aren't any\n\t\tif (focusableElements.length === 0) return;\n\n\t\t// create trap start and end elements\n\t\tthis.trapStart = document.createElement('focus-trap-start');\n\t\tthis.trapEnd = document.createElement('focus-trap-end');\n\n\t\t// add to DOM\n\t\tthis.prepend(this.trapStart);\n\t\tthis.append(this.trapEnd);\n\t}\n\n\t/**\n\t * Handles the keydown event. If the Escape key is pressed, the focus trap is exited.\n\t *\n\t * @param {KeyboardEvent} e - The keyboard event object.\n\t */\n\thandleKeyDown = (e) => {\n\t\tif (e.key === 'Escape') {\n\t\t\te.preventDefault();\n\t\t\tthis.exitTrap();\n\t\t}\n\t};\n\n\t/**\n\t * Exits the focus trap by hiding the current container and shifting focus\n\t * back to the trigger element that opened the trap.\n\t */\n\texitTrap() {\n\t\tconst container = this.closest('[aria-hidden=\"false\"]');\n\t\tif (!container) return;\n\n\t\tcontainer.setAttribute('aria-hidden', 'true');\n\n\t\tconst trigger = document.querySelector(\n\t\t\t`[aria-expanded=\"true\"][aria-controls=\"${container.id}\"]`\n\t\t);\n\t\tif (trigger) {\n\t\t\ttrigger.setAttribute('aria-expanded', 'false');\n\t\t\ttrigger.focus();\n\t\t}\n\t}\n}\n\nclass FocusTrapStart extends HTMLElement {\n\t/**\n\t * Called when the element is connected to the DOM.\n\t * Sets the tabindex and adds the focus event listener.\n\t */\n\tconnectedCallback() {\n\t\tthis.setAttribute('tabindex', '0');\n\t\tthis.addEventListener('focus', this.handleFocus);\n\t}\n\n\t/**\n\t * Called when the element is disconnected from the DOM.\n\t * Removes the focus event listener.\n\t */\n\tdisconnectedCallback() {\n\t\tthis.removeEventListener('focus', this.handleFocus);\n\t}\n\n\t/**\n\t * Handles the focus event. If focus moves backwards from the first focusable element,\n\t * it is cycled to the last focusable element, and vice versa.\n\t *\n\t * @param {FocusEvent} e - The focus event object.\n\t */\n\thandleFocus = (e) => {\n\t\tconst trap = this.closest('focus-trap');\n\t\tconst focusableElements = getFocusableElements(trap);\n\n\t\tif (focusableElements.length === 0) return;\n\n\t\tconst firstElement = focusableElements[0];\n\t\tconst lastElement =\n\t\t\tfocusableElements[focusableElements.length - 1];\n\n\t\tif (e.relatedTarget === firstElement) {\n\t\t\tlastElement.focus();\n\t\t} else {\n\t\t\tfirstElement.focus();\n\t\t}\n\t};\n}\n\nclass FocusTrapEnd extends HTMLElement {\n\t/**\n\t * Called when the element is connected to the DOM.\n\t * Sets the tabindex and adds the focus event listener.\n\t */\n\tconnectedCallback() {\n\t\tthis.setAttribute('tabindex', '0');\n\t\tthis.addEventListener('focus', this.handleFocus);\n\t}\n\n\t/**\n\t * Called when the element is disconnected from the DOM.\n\t * Removes the focus event listener.\n\t */\n\tdisconnectedCallback() {\n\t\tthis.removeEventListener('focus', this.handleFocus);\n\t}\n\n\t/**\n\t * Handles the focus event. When the trap end is focused, focus is shifted back to the trap start.\n\t */\n\thandleFocus = () => {\n\t\tconst trap = this.closest('focus-trap');\n\t\tconst trapStart = trap.querySelector('focus-trap-start');\n\t\ttrapStart.focus();\n\t};\n}\n\ncustomElements.define('focus-trap', FocusTrap);\ncustomElements.define('focus-trap-start', FocusTrapStart);\ncustomElements.define('focus-trap-end', FocusTrapEnd);\n//# sourceMappingURL=focus-trap.esm.js.map\n","import './index.scss';\nimport '@magic-spells/focus-trap';\n\n/**\n * Custom element that creates an accessible modal dialog panel with focus management\n * @extends HTMLElement\n */\nclass DialogPanel extends HTMLElement {\n\t#handleTransitionEnd;\n\t#scrollPosition = 0;\n\n\t/**\n\t * Clean up event listeners when component is removed from DOM\n\t */\n\tdisconnectedCallback() {\n\t\tconst _ = this;\n\t\tif (_.contentPanel) {\n\t\t\t_.contentPanel.removeEventListener(\n\t\t\t\t'transitionend',\n\t\t\t\t_.#handleTransitionEnd\n\t\t\t);\n\t\t}\n\n\t\t// Ensure body scroll is restored if component is removed while open\n\t\tdocument.body.classList.remove('overflow-hidden');\n\t\tthis.#restoreScroll();\n\t}\n\n\t/**\n\t * Saves current scroll position and locks body scrolling\n\t * @private\n\t */\n\t#lockScroll() {\n\t\tconst _ = this;\n\t\t// Save current scroll position\n\t\t_.#scrollPosition = window.pageYOffset;\n\n\t\t// Apply fixed position to body\n\t\tdocument.body.classList.add('overflow-hidden');\n\t\tdocument.body.style.top = `-${_.#scrollPosition}px`;\n\t}\n\n\t/**\n\t * Restores scroll position when dialog is closed\n\t * @private\n\t */\n\t#restoreScroll() {\n\t\tconst _ = this;\n\t\t// Remove fixed positioning\n\t\tdocument.body.classList.remove('overflow-hidden');\n\t\tdocument.body.style.removeProperty('top');\n\n\t\t// Restore scroll position\n\t\twindow.scrollTo(0, _.#scrollPosition);\n\t}\n\t/**\n\t * Initializes the dialog panel, sets up focus trap and overlay\n\t */\n\tconstructor() {\n\t\tsuper();\n\t\tconst _ = this;\n\t\t_.id = _.getAttribute('id');\n\t\t_.setAttribute('role', 'dialog');\n\t\t_.setAttribute('aria-modal', 'true');\n\t\t_.setAttribute('aria-hidden', 'true');\n\n\t\t_.contentPanel = _.querySelector('dialog-content');\n\t\t_.focusTrap = document.createElement('focus-trap');\n\t\t_.triggerEl = null;\n\n\t\t// Create a handler for transition end events\n\t\t_.#handleTransitionEnd = (e) => {\n\t\t\tif (\n\t\t\t\te.propertyName === 'opacity' &&\n\t\t\t\t_.getAttribute('aria-hidden') === 'true'\n\t\t\t) {\n\t\t\t\t_.contentPanel.classList.add('hidden');\n\n\t\t\t\t// Dispatch afterHide event - dialog has completed its transition\n\t\t\t\t_.dispatchEvent(\n\t\t\t\t\tnew CustomEvent('afterHide', {\n\t\t\t\t\t\tbubbles: true,\n\t\t\t\t\t\tdetail: { triggerElement: _.triggerEl },\n\t\t\t\t\t})\n\t\t\t\t);\n\t\t\t}\n\t\t};\n\n\t\t// Ensure we have labelledby and describedby references\n\t\tif (!_.getAttribute('aria-labelledby')) {\n\t\t\tconst heading = _.querySelector('h1, h2, h3');\n\t\t\tif (heading && !heading.id) {\n\t\t\t\theading.id = `${_.id}-title`;\n\t\t\t}\n\t\t\tif (heading?.id) {\n\t\t\t\t_.setAttribute('aria-labelledby', heading.id);\n\t\t\t}\n\t\t}\n\n\t\t_.contentPanel.parentNode.insertBefore(\n\t\t\t_.focusTrap,\n\t\t\t_.contentPanel\n\t\t);\n\t\t_.focusTrap.appendChild(_.contentPanel);\n\n\t\t_.focusTrap.setupTrap();\n\n\t\t// Add modal overlay\n\t\t_.prepend(document.createElement('dialog-overlay'));\n\t\t_.#bindUI();\n\t\t_.#bindKeyboard();\n\t}\n\n\t/**\n\t * Binds click events for showing and hiding the dialog\n\t * @private\n\t */\n\t#bindUI() {\n\t\tconst _ = this;\n\n\t\t// Handle trigger buttons\n\t\tdocument.addEventListener('click', (e) => {\n\t\t\tconst trigger = e.target.closest(`[aria-controls=\"${_.id}\"]`);\n\t\t\tif (!trigger) return;\n\n\t\t\tif (trigger.getAttribute('data-prevent-default') === 'true') {\n\t\t\t\te.preventDefault();\n\t\t\t}\n\n\t\t\t_.show(trigger);\n\t\t});\n\n\t\t// Handle close buttons\n\t\t_.addEventListener('click', (e) => {\n\t\t\tif (!e.target.closest('[data-action=\"hide-dialog\"]')) return;\n\t\t\t_.hide();\n\t\t});\n\n\t\t// Add transition end listener\n\t\t_.contentPanel.addEventListener(\n\t\t\t'transitionend',\n\t\t\t_.#handleTransitionEnd\n\t\t);\n\t}\n\n\t/**\n\t * Binds keyboard events for accessibility\n\t * @private\n\t */\n\t#bindKeyboard() {\n\t\tthis.addEventListener('keydown', (e) => {\n\t\t\tif (e.key === 'Escape') {\n\t\t\t\tthis.hide();\n\t\t\t}\n\t\t});\n\t}\n\n\t/**\n\t * Shows the dialog and traps focus within it\n\t * @param {HTMLElement} [triggerEl=null] - The element that triggered the dialog\n\t * @fires DialogPanel#beforeShow - Fired before the dialog starts to show\n\t * @fires DialogPanel#show - Fired when the dialog has been shown\n\t * @returns {boolean} False if the show was prevented by a beforeShow event handler\n\t */\n\tshow(triggerEl = null) {\n\t\tconst _ = this;\n\t\t_.triggerEl = triggerEl || false;\n\n\t\t// Dispatch beforeShow event - allows preventing the dialog from opening\n\t\tconst beforeShowEvent = new CustomEvent('beforeShow', {\n\t\t\tbubbles: true,\n\t\t\tcancelable: true,\n\t\t\tdetail: { triggerElement: _.triggerEl },\n\t\t});\n\n\t\tconst showAllowed = _.dispatchEvent(beforeShowEvent);\n\n\t\t// If event was canceled (preventDefault was called), don't show the dialog\n\t\tif (!showAllowed) return false;\n\n\t\t// Remove the hidden class first to ensure content is rendered\n\t\t_.contentPanel.classList.remove('hidden');\n\n\t\t// Give the browser a moment to process before starting animation\n\t\trequestAnimationFrame(() => {\n\t\t\t// Update ARIA states\n\t\t\t_.setAttribute('aria-hidden', 'false');\n\t\t\tif (_.triggerEl) {\n\t\t\t\t_.triggerEl.setAttribute('aria-expanded', 'true');\n\t\t\t}\n\n\t\t\t// Lock body scrolling and save scroll position\n\t\t\t_.#lockScroll();\n\n\t\t\t// Focus management\n\t\t\tconst firstFocusable = _.querySelector(\n\t\t\t\t'button, [href], input, select, textarea, [tabindex]:not([tabindex=\"-1\"])'\n\t\t\t);\n\t\t\tif (firstFocusable) {\n\t\t\t\trequestAnimationFrame(() => {\n\t\t\t\t\tfirstFocusable.focus();\n\t\t\t\t});\n\t\t\t}\n\n\t\t\t// Dispatch show event - dialog is now visible\n\t\t\t_.dispatchEvent(\n\t\t\t\tnew CustomEvent('show', {\n\t\t\t\t\tbubbles: true,\n\t\t\t\t\tdetail: { triggerElement: _.triggerEl },\n\t\t\t\t})\n\t\t\t);\n\t\t});\n\n\t\treturn true;\n\t}\n\n\t/**\n\t * Hides the dialog and restores focus\n\t * @fires DialogPanel#beforeHide - Fired before the dialog starts to hide\n\t * @fires DialogPanel#hide - Fired when the dialog has started hiding (transition begins)\n\t * @fires DialogPanel#afterHide - Fired when the dialog has completed its hide transition\n\t * @returns {boolean} False if the hide was prevented by a beforeHide event handler\n\t */\n\thide() {\n\t\tconst _ = this;\n\n\t\t// Dispatch beforeHide event - allows preventing the dialog from closing\n\t\tconst beforeHideEvent = new CustomEvent('beforeHide', {\n\t\t\tbubbles: true,\n\t\t\tcancelable: true,\n\t\t\tdetail: { triggerElement: _.triggerEl },\n\t\t});\n\n\t\tconst hideAllowed = _.dispatchEvent(beforeHideEvent);\n\n\t\t// If event was canceled (preventDefault was called), don't hide the dialog\n\t\tif (!hideAllowed) return false;\n\n\t\t// Restore body scroll and scroll position\n\t\t_.#restoreScroll();\n\n\t\t// Update ARIA states\n\t\tif (_.triggerEl) {\n\t\t\t// remove focus from modal panel first\n\t\t\t_.triggerEl.focus();\n\t\t\t// mark trigger as no longer expanded\n\t\t\t_.triggerEl.setAttribute('aria-expanded', 'false');\n\t\t}\n\n\t\t// Set aria-hidden to start transition\n\t\t// The transitionend event handler will add display:none when complete\n\t\t_.setAttribute('aria-hidden', 'true');\n\n\t\t// Dispatch hide event - dialog is now starting to hide\n\t\t_.dispatchEvent(\n\t\t\tnew CustomEvent('hide', {\n\t\t\t\tbubbles: true,\n\t\t\t\tdetail: { triggerElement: _.triggerEl },\n\t\t\t})\n\t\t);\n\n\t\treturn true;\n\t}\n}\n\n/**\n * Custom element that creates a clickable overlay for the dialog\n * @extends HTMLElement\n */\nclass DialogOverlay extends HTMLElement {\n\tconstructor() {\n\t\tsuper();\n\t\tthis.setAttribute('tabindex', '-1'); // Changed to -1 as it shouldn't be focusable\n\t\tthis.setAttribute('aria-hidden', 'true');\n\t\tthis.dialogPanel = this.closest('dialog-panel');\n\t\tthis.#bindUI();\n\t}\n\n\t#bindUI() {\n\t\tthis.addEventListener('click', () => {\n\t\t\tthis.dialogPanel.hide();\n\t\t});\n\t}\n}\n\n/**\n * Custom element that wraps the content of the dialog\n * @extends HTMLElement\n */\nclass DialogContent extends HTMLElement {\n\tconstructor() {\n\t\tsuper();\n\t\tthis.setAttribute('role', 'document'); // Optional: helps with document structure\n\t}\n}\n\nif (!customElements.get('dialog-panel')) {\n\tcustomElements.define('dialog-panel', DialogPanel);\n}\nif (!customElements.get('dialog-overlay')) {\n\tcustomElements.define('dialog-overlay', DialogOverlay);\n}\nif (!customElements.get('dialog-content')) {\n\tcustomElements.define('dialog-content', DialogContent);\n}\n\nexport { DialogPanel, DialogOverlay, DialogContent };\nexport default DialogPanel;\n"],"names":[],"mappings":"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","x_google_ignoreList":[0]}
@@ -1 +1 @@
1
- dialog-panel{position:fixed;z-index:10}dialog-overlay,dialog-panel{height:100vh;left:0;pointer-events:none;top:0;width:100vw}dialog-overlay{backdrop-filter:blur(2px) saturate(120%);background-color:rgba(20,23,26,.4);opacity:0;position:absolute;transition:all .3s ease-out}dialog-content{background:#fff;display:block;opacity:0}dialog-panel[aria-hidden=false]{pointer-events:all}dialog-panel[aria-hidden=false] dialog-overlay{filter:blur(0);opacity:1;pointer-events:all;transform:scale(1)}dialog-panel[aria-hidden=false] dialog-content{filter:blur(0);opacity:1;transform:scale(1);z-index:10}
1
+ :root{--dp-panel-top:0;--dp-panel-left:0;--dp-panel-width:100vw;--dp-panel-height:100vh;--dp-panel-z-index:10;--dp-overlay-z-index:1000;--dp-overlay-background:rgba(20,23,26,.4);--dp-overlay-backdrop-filter:blur(2px) saturate(120%);--dp-overlay-transition:all 400ms ease-out;--dp-content-display:block;--dp-content-background:#fff;--dp-content-z-index:1001;--dp-content-shadow:0 10px 25px rgba(0,0,0,.15);--dp-content-border-radius:8px;--dp-transition-duration:400ms;--dp-transition-timing:ease-out}dialog-panel{display:contents}dialog-panel[aria-hidden=false] dialog-content,dialog-panel[aria-hidden=false] dialog-overlay{filter:blur(0);opacity:1;pointer-events:auto;transform:scale(1)}dialog-overlay{backdrop-filter:var(--dp-overlay-backdrop-filter,blur(2px) saturate(120%));background-color:var(--dp-overlay-background,rgba(20,23,26,.4));height:100vh;left:0;top:0;transition:var(--dp-overlay-transition,all .3s ease-out);width:100vw;z-index:var(--dp-overlay-z-index,1000)}dialog-content,dialog-overlay{opacity:0;pointer-events:none;position:fixed}dialog-content{background:var(--dp-content-background,#fff);border-radius:var(--dp-content-border-radius,8px);box-shadow:var(--dp-content-shadow,0 10px 25px rgba(0,0,0,.15));display:var(--dp-content-display,block);left:50%;max-height:85vh;max-width:90vw;overflow:auto;top:50%;transform:translate(-50%,-50%) scale(.95);transition:opacity var(--dp-transition-duration,.3s) var(--dp-transition-timing,ease-out),transform var(--dp-transition-duration,.3s) var(--dp-transition-timing,ease-out);z-index:var(--dp-content-z-index,1001)}dialog-panel[aria-hidden=false] dialog-content{transform:translate(-50%,-50%) scale(1)}dialog-content.hidden{display:none}
@@ -1 +1 @@
1
- var DialogPanel=function(e){"use strict";const t=e=>Array.from(e.querySelectorAll('summary, a[href], button:not(:disabled), [tabindex]:not([tabindex^="-"]):not(focus-trap-start):not(focus-trap-end), [draggable], area, input:not([type=hidden]):not(:disabled), select:not(:disabled), textarea:not(:disabled), object, iframe'));class FocusTrap extends HTMLElement{static styleInjected=!1;constructor(){super(),this.trapStart=null,this.trapEnd=null,FocusTrap.styleInjected||(this.injectStyles(),FocusTrap.styleInjected=!0)}injectStyles(){const e=document.createElement("style");e.textContent="\n focus-trap-start,\n focus-trap-end {\n position: absolute;\n width: 1px;\n height: 1px;\n margin: -1px;\n padding: 0;\n border: 0;\n clip: rect(0, 0, 0, 0);\n overflow: hidden;\n white-space: nowrap;\n }\n ",document.head.appendChild(e)}connectedCallback(){this.setupTrap(),this.addEventListener("keydown",this.handleKeyDown)}disconnectedCallback(){this.removeEventListener("keydown",this.handleKeyDown)}setupTrap(){0!==t(this).length&&(this.trapStart=document.createElement("focus-trap-start"),this.trapEnd=document.createElement("focus-trap-end"),this.prepend(this.trapStart),this.append(this.trapEnd))}handleKeyDown=e=>{"Escape"===e.key&&(e.preventDefault(),this.exitTrap())};exitTrap(){const e=this.closest('[aria-hidden="false"]');if(!e)return;e.setAttribute("aria-hidden","true");const t=document.querySelector(`[aria-expanded="true"][aria-controls="${e.id}"]`);t&&(t.setAttribute("aria-expanded","false"),t.focus())}}class FocusTrapStart extends HTMLElement{connectedCallback(){this.setAttribute("tabindex","0"),this.addEventListener("focus",this.handleFocus)}disconnectedCallback(){this.removeEventListener("focus",this.handleFocus)}handleFocus=e=>{const n=this.closest("focus-trap"),s=t(n);if(0===s.length)return;const a=s[0],i=s[s.length-1];e.relatedTarget===a?i.focus():a.focus()}}class FocusTrapEnd extends HTMLElement{connectedCallback(){this.setAttribute("tabindex","0"),this.addEventListener("focus",this.handleFocus)}disconnectedCallback(){this.removeEventListener("focus",this.handleFocus)}handleFocus=()=>{this.closest("focus-trap").querySelector("focus-trap-start").focus()}}customElements.define("focus-trap",FocusTrap),customElements.define("focus-trap-start",FocusTrapStart),customElements.define("focus-trap-end",FocusTrapEnd);class DialogPanel extends HTMLElement{constructor(){super();const e=this;if(e.id=e.getAttribute("id"),e.setAttribute("role","dialog"),e.setAttribute("aria-modal","true"),e.setAttribute("aria-hidden","true"),e.contentPanel=e.querySelector("dialog-content"),e.focusTrap=document.createElement("focus-trap"),e.triggerEl=null,!e.getAttribute("aria-labelledby")){const t=e.querySelector("h1, h2, h3");t&&!t.id&&(t.id=`${e.id}-title`),t?.id&&e.setAttribute("aria-labelledby",t.id)}e.contentPanel.parentNode.insertBefore(e.focusTrap,e.contentPanel),e.focusTrap.appendChild(e.contentPanel),e.focusTrap.setupTrap(),e.prepend(document.createElement("dialog-overlay")),e.#e(),e.#t()}#e(){document.addEventListener("click",(e=>{const t=e.target.closest(`[aria-controls="${this.id}"]`);t&&("true"===t.getAttribute("data-prevent-default")&&e.preventDefault(),this.show(t))})),this.addEventListener("click",(e=>{e.target.closest('[data-action="hide-dialog"]')&&this.hide()}))}#t(){this.addEventListener("keydown",(e=>{"Escape"===e.key&&this.hide()}))}show(e=null){this.triggerEl=e||!1,this.setAttribute("aria-hidden","false"),this.triggerEl&&this.triggerEl.setAttribute("aria-expanded","true"),document.body.classList.add("overflow-hidden");const t=this.querySelector('button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])');t&&requestAnimationFrame((()=>{t.focus()}))}hide(){document.body.classList.remove("overflow-hidden"),this.triggerEl?(this.triggerEl.setAttribute("aria-expanded","false"),this.triggerEl.focus()):console.log("we need to blur focus"),setTimeout((()=>{this.setAttribute("aria-hidden","true")}),1)}}class DialogOverlay extends HTMLElement{constructor(){super(),this.setAttribute("tabindex","-1"),this.setAttribute("aria-hidden","true"),this.dialogPanel=this.closest("dialog-panel"),this.#e()}#e(){this.addEventListener("click",(()=>{this.dialogPanel.hide()}))}}class DialogContent extends HTMLElement{constructor(){super(),this.setAttribute("role","document")}}return customElements.define("dialog-panel",DialogPanel),customElements.define("dialog-overlay",DialogOverlay),customElements.define("dialog-content",DialogContent),e.DialogContent=DialogContent,e.DialogOverlay=DialogOverlay,e.DialogPanel=DialogPanel,e.default=DialogPanel,Object.defineProperty(e,"__esModule",{value:!0}),e}({});
1
+ !function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports):"function"==typeof define&&define.amd?define(["exports"],t):t((e="undefined"!=typeof globalThis?globalThis:e||self).DialogPanel={})}(this,(function(e){"use strict";const t=e=>Array.from(e.querySelectorAll('summary, a[href], button:not(:disabled), [tabindex]:not([tabindex^="-"]):not(focus-trap-start):not(focus-trap-end), [draggable], area, input:not([type=hidden]):not(:disabled), select:not(:disabled), textarea:not(:disabled), object, iframe'));class FocusTrap extends HTMLElement{static styleInjected=!1;constructor(){super(),this.trapStart=null,this.trapEnd=null,FocusTrap.styleInjected||(this.injectStyles(),FocusTrap.styleInjected=!0)}injectStyles(){const e=document.createElement("style");e.textContent="\n focus-trap-start,\n focus-trap-end {\n position: absolute;\n width: 1px;\n height: 1px;\n margin: -1px;\n padding: 0;\n border: 0;\n clip: rect(0, 0, 0, 0);\n overflow: hidden;\n white-space: nowrap;\n }\n ",document.head.appendChild(e)}connectedCallback(){this.setupTrap(),this.addEventListener("keydown",this.handleKeyDown)}disconnectedCallback(){this.removeEventListener("keydown",this.handleKeyDown)}setupTrap(){0!==t(this).length&&(this.trapStart=document.createElement("focus-trap-start"),this.trapEnd=document.createElement("focus-trap-end"),this.prepend(this.trapStart),this.append(this.trapEnd))}handleKeyDown=e=>{"Escape"===e.key&&(e.preventDefault(),this.exitTrap())};exitTrap(){const e=this.closest('[aria-hidden="false"]');if(!e)return;e.setAttribute("aria-hidden","true");const t=document.querySelector(`[aria-expanded="true"][aria-controls="${e.id}"]`);t&&(t.setAttribute("aria-expanded","false"),t.focus())}}class FocusTrapStart extends HTMLElement{connectedCallback(){this.setAttribute("tabindex","0"),this.addEventListener("focus",this.handleFocus)}disconnectedCallback(){this.removeEventListener("focus",this.handleFocus)}handleFocus=e=>{const n=this.closest("focus-trap"),s=t(n);if(0===s.length)return;const a=s[0],i=s[s.length-1];e.relatedTarget===a?i.focus():a.focus()}}class FocusTrapEnd extends HTMLElement{connectedCallback(){this.setAttribute("tabindex","0"),this.addEventListener("focus",this.handleFocus)}disconnectedCallback(){this.removeEventListener("focus",this.handleFocus)}handleFocus=()=>{this.closest("focus-trap").querySelector("focus-trap-start").focus()}}customElements.define("focus-trap",FocusTrap),customElements.define("focus-trap-start",FocusTrapStart),customElements.define("focus-trap-end",FocusTrapEnd);class DialogPanel extends HTMLElement{#e;#t=0;disconnectedCallback(){const e=this;e.contentPanel&&e.contentPanel.removeEventListener("transitionend",e.#e),document.body.classList.remove("overflow-hidden"),this.#n()}#s(){this.#t=window.pageYOffset,document.body.classList.add("overflow-hidden"),document.body.style.top=`-${this.#t}px`}#n(){document.body.classList.remove("overflow-hidden"),document.body.style.removeProperty("top"),window.scrollTo(0,this.#t)}constructor(){super();const e=this;if(e.id=e.getAttribute("id"),e.setAttribute("role","dialog"),e.setAttribute("aria-modal","true"),e.setAttribute("aria-hidden","true"),e.contentPanel=e.querySelector("dialog-content"),e.focusTrap=document.createElement("focus-trap"),e.triggerEl=null,e.#e=t=>{"opacity"===t.propertyName&&"true"===e.getAttribute("aria-hidden")&&(e.contentPanel.classList.add("hidden"),e.dispatchEvent(new CustomEvent("afterHide",{bubbles:!0,detail:{triggerElement:e.triggerEl}})))},!e.getAttribute("aria-labelledby")){const t=e.querySelector("h1, h2, h3");t&&!t.id&&(t.id=`${e.id}-title`),t?.id&&e.setAttribute("aria-labelledby",t.id)}e.contentPanel.parentNode.insertBefore(e.focusTrap,e.contentPanel),e.focusTrap.appendChild(e.contentPanel),e.focusTrap.setupTrap(),e.prepend(document.createElement("dialog-overlay")),e.#a(),e.#i()}#a(){const e=this;document.addEventListener("click",(t=>{const n=t.target.closest(`[aria-controls="${e.id}"]`);n&&("true"===n.getAttribute("data-prevent-default")&&t.preventDefault(),e.show(n))})),e.addEventListener("click",(t=>{t.target.closest('[data-action="hide-dialog"]')&&e.hide()})),e.contentPanel.addEventListener("transitionend",e.#e)}#i(){this.addEventListener("keydown",(e=>{"Escape"===e.key&&this.hide()}))}show(e=null){const t=this;t.triggerEl=e||!1;const n=new CustomEvent("beforeShow",{bubbles:!0,cancelable:!0,detail:{triggerElement:t.triggerEl}});return!!t.dispatchEvent(n)&&(t.contentPanel.classList.remove("hidden"),requestAnimationFrame((()=>{t.setAttribute("aria-hidden","false"),t.triggerEl&&t.triggerEl.setAttribute("aria-expanded","true"),t.#s();const e=t.querySelector('button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])');e&&requestAnimationFrame((()=>{e.focus()})),t.dispatchEvent(new CustomEvent("show",{bubbles:!0,detail:{triggerElement:t.triggerEl}}))})),!0)}hide(){const e=this,t=new CustomEvent("beforeHide",{bubbles:!0,cancelable:!0,detail:{triggerElement:e.triggerEl}});return!!e.dispatchEvent(t)&&(e.#n(),e.triggerEl&&(e.triggerEl.focus(),e.triggerEl.setAttribute("aria-expanded","false")),e.setAttribute("aria-hidden","true"),e.dispatchEvent(new CustomEvent("hide",{bubbles:!0,detail:{triggerElement:e.triggerEl}})),!0)}}class DialogOverlay extends HTMLElement{constructor(){super(),this.setAttribute("tabindex","-1"),this.setAttribute("aria-hidden","true"),this.dialogPanel=this.closest("dialog-panel"),this.#a()}#a(){this.addEventListener("click",(()=>{this.dialogPanel.hide()}))}}class DialogContent extends HTMLElement{constructor(){super(),this.setAttribute("role","document")}}customElements.get("dialog-panel")||customElements.define("dialog-panel",DialogPanel),customElements.get("dialog-overlay")||customElements.define("dialog-overlay",DialogOverlay),customElements.get("dialog-content")||customElements.define("dialog-content",DialogContent),e.DialogContent=DialogContent,e.DialogOverlay=DialogOverlay,e.DialogPanel=DialogPanel,e.default=DialogPanel,Object.defineProperty(e,"__esModule",{value:!0})}));
@@ -0,0 +1,2 @@
1
+ @forward "scss/variables";
2
+ @forward "scss/dialog-panel";