@magic-spells/dialog-panel 1.1.0 → 1.2.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
@@ -54,6 +54,53 @@ Or include directly in HTML:
54
54
  </script>
55
55
  ```
56
56
 
57
+ ## Morph transitions
58
+
59
+ `dialog-panel` can use a duck-typed `@magic-spells/morph-engine` instance as
60
+ its transition transport without taking a dependency on the engine. Assign the
61
+ engine to the writable `morphEngine` property and pass the source element to
62
+ `show()`:
63
+
64
+ ```html
65
+ <button id="morph-card">Open details</button>
66
+
67
+ <dialog-panel id="morph-panel" morph-display="flex">
68
+ <dialog>
69
+ <h2>Details</h2>
70
+ <p>The card springs into this real modal dialog.</p>
71
+ <button data-action-hide-dialog>Close</button>
72
+ </dialog>
73
+ </dialog-panel>
74
+
75
+ <script>
76
+ const panel = document.getElementById('morph-panel');
77
+ const card = document.getElementById('morph-card');
78
+
79
+ panel.morphEngine = new MorphEngine.MorphEngine({
80
+ lockScroll: false,
81
+ zIndex: 10000000,
82
+ });
83
+ card.addEventListener('click', () => panel.show(card));
84
+ </script>
85
+ ```
86
+
87
+ The dialog stays closed while the engine renders it in normal flow, then moves
88
+ into the browser top layer with `showModal()` on the spring's settle frame.
89
+ Calling `hide()` during the outbound flight or `show()` during the return flight
90
+ reverses the active spring in place. Calling `show()` without a trigger element
91
+ uses the existing CSS transition path instead.
92
+
93
+ `morph-display` controls the display value used while measuring and revealing a
94
+ closed target (`block` by default). Assigning an engine automatically adds the
95
+ `morph` attribute as a CSS hook; assigning `null` removes it. The default
96
+ stylesheet uses that hook to pin the target geometry and hand control of
97
+ opacity, transforms, and transitions to the engine.
98
+
99
+ Give morph dialogs an explicit width and height so their in-flow and `:modal`
100
+ geometry match. Consumer CSS must not set `opacity`, `transform`, or
101
+ `transition` on the dialog in morph mode because those declarations fight the
102
+ engine's inline animation styles.
103
+
57
104
  ## Positioning
58
105
 
59
106
  By default, the panel is centered and uses a fade/scale animation. Set the
@@ -118,10 +165,11 @@ dialog-panel[state='hidden'] > dialog { /* hidden */ }
118
165
  | `show(triggerEl?)` | Opens the dialog. Pass trigger element for focus return. Returns `false` if cancelled. |
119
166
  | `hide(triggerEl?)` | Closes the dialog. Returns `false` if cancelled. |
120
167
 
121
- ### Properties (read-only)
168
+ ### Properties
122
169
 
123
170
  | Property | Type | Description |
124
171
  |----------|------|-------------|
172
+ | `morphEngine` | `Object \| null` | Optional duck-typed morph transport. Set to `null` to restore CSS-only mode. |
125
173
  | `state` | `string` | Current state: `'hidden'`, `'showing'`, `'shown'`, `'hiding'` |
126
174
  | `dialog` | `HTMLDialogElement` | Reference to inner `<dialog>` |
127
175
  | `isOpen` | `boolean` | `true` if `showing` or `shown` |
@@ -10,6 +10,7 @@
10
10
  * @property {HTMLDialogElement} dialog - Reference to inner <dialog> element
11
11
  * @property {boolean} isOpen - True if state is 'showing' or 'shown'
12
12
  * @property {HTMLElement|null} triggerElement - Element that triggered current action
13
+ * @property {Object|null} morphEngine - Optional duck-typed morph transition engine
13
14
  *
14
15
  * @fires beforeShow - Fired before showing starts (cancelable)
15
16
  * @fires shown - Fired after show animation completes
@@ -22,12 +23,19 @@ class DialogPanel extends HTMLElement {
22
23
  #triggerElement = null;
23
24
  #dialog = null;
24
25
  #result = null;
26
+ #hideTriggerElement = null;
27
+ #morphEngine = null;
28
+ #morphListenersAttached = false;
25
29
 
26
30
  // Event handler references for cleanup
27
31
  #handlers = {
28
32
  click: null,
29
33
  dialogClick: null,
30
34
  cancel: null,
35
+ close: null,
36
+ morphShown: null,
37
+ morphHidden: null,
38
+ morphStop: null,
31
39
  };
32
40
 
33
41
  // Animation cleanup references
@@ -61,6 +69,7 @@ class DialogPanel extends HTMLElement {
61
69
 
62
70
  // Bind event handlers
63
71
  _.#bindEvents();
72
+ _.#wireMorphEngine();
64
73
  }
65
74
 
66
75
  disconnectedCallback() {
@@ -75,6 +84,7 @@ class DialogPanel extends HTMLElement {
75
84
  clearTimeout(_.#pendingTimeout);
76
85
  _.#pendingTimeout = null;
77
86
  }
87
+ _.#unwireMorphEngine();
78
88
 
79
89
  // Clean up event listeners
80
90
  if (_.#handlers.click) {
@@ -90,6 +100,9 @@ class DialogPanel extends HTMLElement {
90
100
  if (_.#handlers.cancel) {
91
101
  _.#dialog.removeEventListener('cancel', _.#handlers.cancel);
92
102
  }
103
+ if (_.#handlers.close) {
104
+ _.#dialog.removeEventListener('close', _.#handlers.close);
105
+ }
93
106
  }
94
107
  }
95
108
 
@@ -133,6 +146,105 @@ class DialogPanel extends HTMLElement {
133
146
  _.hide();
134
147
  };
135
148
  _.#dialog.addEventListener('cancel', _.#handlers.cancel);
149
+
150
+ // Cover browser force-close paths that bypass the cancel event
151
+ _.#handlers.close = () => {
152
+ if (
153
+ _.#morphEngine?.state === 'shown' &&
154
+ _.#state === 'shown' &&
155
+ !_.#dialog.open
156
+ ) {
157
+ _.hide();
158
+ }
159
+ };
160
+ _.#dialog.addEventListener('close', _.#handlers.close);
161
+ }
162
+
163
+ /**
164
+ * Wire morph engine lifecycle listeners
165
+ * @private
166
+ */
167
+ #wireMorphEngine() {
168
+ const _ = this;
169
+
170
+ if (!_.#morphEngine || _.#morphListenersAttached) return;
171
+
172
+ if (!_.#handlers.morphShown) {
173
+ _.#handlers.morphShown = _.#handleMorphShown.bind(_);
174
+ _.#handlers.morphHidden = _.#handleMorphHidden.bind(_);
175
+ _.#handlers.morphStop = _.#handleMorphStop.bind(_);
176
+ }
177
+
178
+ _.#morphEngine.on('shown', _.#handlers.morphShown);
179
+ _.#morphEngine.on('hidden', _.#handlers.morphHidden);
180
+ _.#morphEngine.on('stop', _.#handlers.morphStop);
181
+ _.#morphListenersAttached = true;
182
+ }
183
+
184
+ /**
185
+ * Unwire morph engine lifecycle listeners
186
+ * @private
187
+ */
188
+ #unwireMorphEngine() {
189
+ const _ = this;
190
+
191
+ if (!_.#morphEngine || !_.#morphListenersAttached) return;
192
+
193
+ _.#morphEngine.off('shown', _.#handlers.morphShown);
194
+ _.#morphEngine.off('hidden', _.#handlers.morphHidden);
195
+ _.#morphEngine.off('stop', _.#handlers.morphStop);
196
+ _.#morphListenersAttached = false;
197
+ }
198
+
199
+ /**
200
+ * Promote the settled morph target into the dialog top layer
201
+ * @private
202
+ */
203
+ #handleMorphShown() {
204
+ const _ = this;
205
+
206
+ if (!_.#dialog.open) _.#dialog.showModal();
207
+ _.#setState('shown');
208
+ _.#emit('shown');
209
+ }
210
+
211
+ /**
212
+ * Finalize a settled morph hide
213
+ * @private
214
+ */
215
+ #handleMorphHidden() {
216
+ this.#finalizeMorphHide();
217
+ }
218
+
219
+ /**
220
+ * Finalize an interrupted morph as hidden
221
+ * @private
222
+ */
223
+ #handleMorphStop() {
224
+ this.#finalizeMorphHide();
225
+ }
226
+
227
+ /**
228
+ * Restore the component's hidden state after a morph ends
229
+ * @private
230
+ */
231
+ #finalizeMorphHide() {
232
+ const _ = this;
233
+
234
+ if (_.#dialog.open) _.#dialog.close();
235
+ _.#setState('hidden');
236
+ _.#emit('hidden', {
237
+ result: _.#result,
238
+ triggerElement: _.#hideTriggerElement,
239
+ });
240
+
241
+ // Return focus to trigger element
242
+ if (_.#triggerElement) _.#triggerElement.focus();
243
+
244
+ // Clean up
245
+ _.#triggerElement = null;
246
+ _.#hideTriggerElement = null;
247
+ _.#result = null;
136
248
  }
137
249
 
138
250
  /**
@@ -146,17 +258,36 @@ class DialogPanel extends HTMLElement {
146
258
  // Check if already showing/shown
147
259
  if (_.#state === 'showing' || _.#state === 'shown') return true;
148
260
 
149
- // If currently hiding, ignore (let hide complete first)
150
- if (_.#state === 'hiding') return false;
261
+ const reversingMorph =
262
+ _.#state === 'hiding' && _.#morphEngine?.state === 'hiding';
263
+
264
+ // CSS transitions cannot reverse while hiding
265
+ if (_.#state === 'hiding' && !reversingMorph) return false;
151
266
 
152
267
  // Store trigger element for focus return later
153
- _.#triggerElement = triggerEl || null;
268
+ if (!reversingMorph) _.#triggerElement = triggerEl || null;
154
269
 
155
270
  // Fire beforeShow (cancelable)
156
271
  if (!_.#emit('beforeShow', { cancelable: true })) return false;
157
272
 
158
- // Set state to 'showing' and open native dialog
273
+ if (reversingMorph) {
274
+ _.#hideTriggerElement = null;
275
+ _.#result = null;
276
+ }
277
+
278
+ // Set state to 'showing'
159
279
  _.#setState('showing');
280
+
281
+ if (_.#morphEngine && (triggerEl || reversingMorph)) {
282
+ _.#morphEngine.show({
283
+ from: _.#triggerElement,
284
+ to: _.#dialog,
285
+ display: _.getAttribute('morph-display') || 'block',
286
+ });
287
+ return true;
288
+ }
289
+
290
+ // Open native dialog for the CSS transition path
160
291
  _.#dialog.showModal();
161
292
 
162
293
  // Double RAF ensures browser has painted the 'showing' state
@@ -187,8 +318,11 @@ class DialogPanel extends HTMLElement {
187
318
  // Check if already hiding/hidden
188
319
  if (_.#state === 'hiding' || _.#state === 'hidden') return true;
189
320
 
190
- // If currently showing, ignore (let show complete first)
191
- if (_.#state === 'showing') return false;
321
+ const reversingMorph =
322
+ _.#state === 'showing' && _.#morphEngine?.state === 'showing';
323
+
324
+ // CSS transitions cannot reverse while showing
325
+ if (_.#state === 'showing' && !reversingMorph) return false;
192
326
 
193
327
  // Capture result from trigger element
194
328
  _.#result = triggerEl?.dataset?.result ?? null;
@@ -204,6 +338,14 @@ class DialogPanel extends HTMLElement {
204
338
  return false;
205
339
  }
206
340
 
341
+ if (reversingMorph || _.#morphEngine?.state === 'shown') {
342
+ _.#hideTriggerElement = triggerEl;
343
+ if (_.#dialog.open) _.#dialog.close();
344
+ _.#morphEngine.hide();
345
+ _.#setState('hiding');
346
+ return true;
347
+ }
348
+
207
349
  // Set state to 'hiding' - this triggers CSS exit animation
208
350
  _.#setState('hiding');
209
351
 
@@ -235,15 +377,16 @@ class DialogPanel extends HTMLElement {
235
377
  #waitForTransition(callback) {
236
378
  const _ = this;
237
379
  let called = false;
380
+ let timerId = null;
238
381
 
239
382
  const done = () => {
240
383
  if (called) return;
241
384
  called = true;
242
385
  _.#dialog.removeEventListener('transitionend', onTransitionEnd);
243
- if (_.#pendingTimeout) {
244
- clearTimeout(_.#pendingTimeout);
245
- _.#pendingTimeout = null;
246
- }
386
+ // clear only our own timer — clearing the shared field would let an
387
+ // earlier, still-pending wait cancel a later wait's fallback
388
+ clearTimeout(timerId);
389
+ if (_.#pendingTimeout === timerId) _.#pendingTimeout = null;
247
390
  callback();
248
391
  };
249
392
 
@@ -253,10 +396,8 @@ class DialogPanel extends HTMLElement {
253
396
 
254
397
  _.#dialog.addEventListener('transitionend', onTransitionEnd);
255
398
 
256
- _.#pendingTimeout = setTimeout(
257
- done,
258
- DialogPanel.TRANSITION_FALLBACK_TIMEOUT
259
- );
399
+ timerId = setTimeout(done, DialogPanel.TRANSITION_FALLBACK_TIMEOUT);
400
+ _.#pendingTimeout = timerId;
260
401
  }
261
402
 
262
403
  /**
@@ -295,6 +436,34 @@ class DialogPanel extends HTMLElement {
295
436
  return _.dispatchEvent(event);
296
437
  }
297
438
 
439
+ /**
440
+ * Optional morph transition transport
441
+ * @returns {Object|null} The attached morph engine
442
+ */
443
+ get morphEngine() {
444
+ return this.#morphEngine;
445
+ }
446
+
447
+ /**
448
+ * Attach or remove a duck-typed morph transition engine
449
+ * @param {Object|null} engine - Engine with show, hide, state, on, and off
450
+ */
451
+ set morphEngine(engine) {
452
+ const _ = this;
453
+
454
+ if (_.#morphEngine === engine) return;
455
+
456
+ _.#unwireMorphEngine();
457
+ _.#morphEngine = engine || null;
458
+
459
+ if (_.#morphEngine) {
460
+ _.setAttribute('morph', '');
461
+ _.#wireMorphEngine();
462
+ } else {
463
+ _.removeAttribute('morph');
464
+ }
465
+ }
466
+
298
467
  // Read-only properties
299
468
  get state() {
300
469
  return this.#state;
@@ -1 +1 @@
1
- {"version":3,"file":"dialog-panel.cjs.js","sources":["../src/dialog-panel.js"],"sourcesContent":["import './dialog-panel.css';\n\n/**\n * DialogPanel - A lightweight web component wrapper for native <dialog> elements\n * with state-driven animations.\n *\n * @extends HTMLElement\n *\n * @property {string} state - Current state: 'hidden' | 'showing' | 'shown' | 'hiding'\n * @property {HTMLDialogElement} dialog - Reference to inner <dialog> element\n * @property {boolean} isOpen - True if state is 'showing' or 'shown'\n * @property {HTMLElement|null} triggerElement - Element that triggered current action\n *\n * @fires beforeShow - Fired before showing starts (cancelable)\n * @fires shown - Fired after show animation completes\n * @fires beforeHide - Fired before hiding starts (cancelable)\n * @fires hidden - Fired after hide animation completes\n */\nclass DialogPanel extends HTMLElement {\n\t// Private fields\n\t#state = 'hidden';\n\t#triggerElement = null;\n\t#dialog = null;\n\t#result = null;\n\n\t// Event handler references for cleanup\n\t#handlers = {\n\t\tclick: null,\n\t\tdialogClick: null,\n\t\tcancel: null,\n\t};\n\n\t// Animation cleanup references\n\t#pendingRAF = null;\n\t#pendingTimeout = null;\n\n\t// Fallback timeout for transitionend (in ms)\n\tstatic TRANSITION_FALLBACK_TIMEOUT = 700;\n\n\tconnectedCallback() {\n\t\tconst _ = this;\n\n\t\t// Find inner dialog element\n\t\t_.#dialog = _.querySelector('dialog');\n\n\t\tif (!_.#dialog) {\n\t\t\tconsole.warn(\n\t\t\t\t'DialogPanel: No <dialog> element found inside <dialog-panel>'\n\t\t\t);\n\t\t\treturn;\n\t\t}\n\n\t\t// Auto-create dialog-backdrop if not present\n\t\tif (!_.querySelector('dialog-backdrop')) {\n\t\t\tconst backdrop = document.createElement('dialog-backdrop');\n\t\t\t_.insertBefore(backdrop, _.firstChild);\n\t\t}\n\n\t\t// Set initial state attribute\n\t\t_.#setState('hidden');\n\n\t\t// Bind event handlers\n\t\t_.#bindEvents();\n\t}\n\n\tdisconnectedCallback() {\n\t\tconst _ = this;\n\n\t\t// Cancel pending animations\n\t\tif (_.#pendingRAF) {\n\t\t\tcancelAnimationFrame(_.#pendingRAF);\n\t\t\t_.#pendingRAF = null;\n\t\t}\n\t\tif (_.#pendingTimeout) {\n\t\t\tclearTimeout(_.#pendingTimeout);\n\t\t\t_.#pendingTimeout = null;\n\t\t}\n\n\t\t// Clean up event listeners\n\t\tif (_.#handlers.click) {\n\t\t\t_.removeEventListener('click', _.#handlers.click);\n\t\t}\n\t\tif (_.#dialog) {\n\t\t\tif (_.#handlers.dialogClick) {\n\t\t\t\t_.#dialog.removeEventListener(\n\t\t\t\t\t'click',\n\t\t\t\t\t_.#handlers.dialogClick\n\t\t\t\t);\n\t\t\t}\n\t\t\tif (_.#handlers.cancel) {\n\t\t\t\t_.#dialog.removeEventListener('cancel', _.#handlers.cancel);\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Bind event listeners for close buttons, backdrop, and escape key\n\t * @private\n\t */\n\t#bindEvents() {\n\t\tconst _ = this;\n\n\t\t// Handle close buttons with data-action-hide-dialog\n\t\t_.#handlers.click = (e) => {\n\t\t\tconst trigger = e.target.closest('[data-action-hide-dialog]');\n\t\t\tif (trigger) {\n\t\t\t\te.stopPropagation();\n\t\t\t\t_.hide(trigger);\n\t\t\t}\n\t\t};\n\t\t_.addEventListener('click', _.#handlers.click);\n\n\t\t// Handle backdrop click - detect clicks outside dialog bounds\n\t\t// This works because clicks on ::backdrop still fire on the dialog element\n\t\t_.#handlers.dialogClick = (e) => {\n\t\t\tconst rect = _.#dialog.getBoundingClientRect();\n\t\t\tconst clickedOutside =\n\t\t\t\te.clientX < rect.left ||\n\t\t\t\te.clientX > rect.right ||\n\t\t\t\te.clientY < rect.top ||\n\t\t\t\te.clientY > rect.bottom;\n\t\t\tif (clickedOutside) {\n\t\t\t\te.stopPropagation();\n\t\t\t\t_.hide();\n\t\t\t}\n\t\t};\n\t\t_.#dialog.addEventListener('click', _.#handlers.dialogClick);\n\n\t\t// Handle escape key - intercept native cancel and animate close\n\t\t_.#handlers.cancel = (e) => {\n\t\t\te.preventDefault();\n\t\t\te.stopPropagation();\n\t\t\t_.hide();\n\t\t};\n\t\t_.#dialog.addEventListener('cancel', _.#handlers.cancel);\n\t}\n\n\t/**\n\t * Show the dialog with animation\n\t * @param {HTMLElement} [triggerEl=null] - The element that triggered the show\n\t * @returns {boolean} False if show was prevented via beforeShow event\n\t */\n\tshow(triggerEl = null) {\n\t\tconst _ = this;\n\n\t\t// Check if already showing/shown\n\t\tif (_.#state === 'showing' || _.#state === 'shown') return true;\n\n\t\t// If currently hiding, ignore (let hide complete first)\n\t\tif (_.#state === 'hiding') return false;\n\n\t\t// Store trigger element for focus return later\n\t\t_.#triggerElement = triggerEl || null;\n\n\t\t// Fire beforeShow (cancelable)\n\t\tif (!_.#emit('beforeShow', { cancelable: true })) return false;\n\n\t\t// Set state to 'showing' and open native dialog\n\t\t_.#setState('showing');\n\t\t_.#dialog.showModal();\n\n\t\t// Double RAF ensures browser has painted the 'showing' state\n\t\t// before we transition to 'shown'\n\t\t_.#pendingRAF = requestAnimationFrame(() => {\n\t\t\t_.#pendingRAF = requestAnimationFrame(() => {\n\t\t\t\t_.#pendingRAF = null;\n\t\t\t\t_.#setState('shown');\n\n\t\t\t\t// Wait for transition to complete before firing 'shown' event\n\t\t\t\t_.#waitForTransition(() => {\n\t\t\t\t\t_.#emit('shown');\n\t\t\t\t});\n\t\t\t});\n\t\t});\n\n\t\treturn true;\n\t}\n\n\t/**\n\t * Hide the dialog with animation\n\t * @param {HTMLElement} [triggerEl=null] - The element that triggered the hide\n\t * @returns {boolean} False if hide was prevented via beforeHide event\n\t */\n\thide(triggerEl = null) {\n\t\tconst _ = this;\n\n\t\t// Check if already hiding/hidden\n\t\tif (_.#state === 'hiding' || _.#state === 'hidden') return true;\n\n\t\t// If currently showing, ignore (let show complete first)\n\t\tif (_.#state === 'showing') return false;\n\n\t\t// Capture result from trigger element\n\t\t_.#result = triggerEl?.dataset?.result ?? null;\n\n\t\t// Fire beforeHide (cancelable)\n\t\tif (\n\t\t\t!_.#emit('beforeHide', {\n\t\t\t\tcancelable: true,\n\t\t\t\tresult: _.#result,\n\t\t\t\ttriggerElement: triggerEl,\n\t\t\t})\n\t\t) {\n\t\t\treturn false;\n\t\t}\n\n\t\t// Set state to 'hiding' - this triggers CSS exit animation\n\t\t_.#setState('hiding');\n\n\t\t// Wait for transition to complete\n\t\t_.#waitForTransition(() => {\n\t\t\t_.#dialog.close();\n\t\t\t_.#setState('hidden');\n\t\t\t_.#emit('hidden', {\n\t\t\t\tresult: _.#result,\n\t\t\t\ttriggerElement: triggerEl,\n\t\t\t});\n\n\t\t\t// Return focus to trigger element\n\t\t\tif (_.#triggerElement) _.#triggerElement.focus();\n\n\t\t\t// Clean up\n\t\t\t_.#triggerElement = null;\n\t\t\t_.#result = null;\n\t\t});\n\n\t\treturn true;\n\t}\n\n\t/**\n\t * Wait for CSS transition to complete with fallback timeout\n\t * @param {Function} callback - Called when transition completes\n\t * @private\n\t */\n\t#waitForTransition(callback) {\n\t\tconst _ = this;\n\t\tlet called = false;\n\n\t\tconst done = () => {\n\t\t\tif (called) return;\n\t\t\tcalled = true;\n\t\t\t_.#dialog.removeEventListener('transitionend', onTransitionEnd);\n\t\t\tif (_.#pendingTimeout) {\n\t\t\t\tclearTimeout(_.#pendingTimeout);\n\t\t\t\t_.#pendingTimeout = null;\n\t\t\t}\n\t\t\tcallback();\n\t\t};\n\n\t\tconst onTransitionEnd = (e) => {\n\t\t\tif (e.target === _.#dialog) done();\n\t\t};\n\n\t\t_.#dialog.addEventListener('transitionend', onTransitionEnd);\n\n\t\t_.#pendingTimeout = setTimeout(\n\t\t\tdone,\n\t\t\tDialogPanel.TRANSITION_FALLBACK_TIMEOUT\n\t\t);\n\t}\n\n\t/**\n\t * Set the component state\n\t * @param {string} newState - The new state\n\t * @private\n\t */\n\t#setState(newState) {\n\t\tthis.#state = newState;\n\t\tthis.setAttribute('state', newState);\n\t}\n\n\t/**\n\t * Emit a custom event\n\t * @param {string} name - Event name\n\t * @param {Object} options - Event options\n\t * @returns {boolean} False if event was cancelled\n\t * @private\n\t */\n\t#emit(name, options = {}) {\n\t\tconst _ = this;\n\t\tconst { cancelable = false, ...detail } = options;\n\n\t\tconst event = new CustomEvent(name, {\n\t\t\tbubbles: true,\n\t\t\tcomposed: true,\n\t\t\tcancelable,\n\t\t\tdetail: {\n\t\t\t\ttriggerElement: _.#triggerElement,\n\t\t\t\tresult: _.#result,\n\t\t\t\tstate: _.#state,\n\t\t\t\t...detail,\n\t\t\t},\n\t\t});\n\n\t\treturn _.dispatchEvent(event);\n\t}\n\n\t// Read-only properties\n\tget state() {\n\t\treturn this.#state;\n\t}\n\tget dialog() {\n\t\treturn this.#dialog;\n\t}\n\tget isOpen() {\n\t\treturn this.#state === 'showing' || this.#state === 'shown';\n\t}\n\tget triggerElement() {\n\t\treturn this.#triggerElement;\n\t}\n}\n\n/**\n * DialogBackdrop - A custom backdrop element that animates with the dialog-panel state.\n * Use this instead of native ::backdrop for consistent cross-browser animations.\n *\n * @extends HTMLElement\n */\nclass DialogBackdrop extends HTMLElement {\n\t#panel = null;\n\t#handlers = {\n\t\tclick: null,\n\t};\n\n\tconnectedCallback() {\n\t\tconst _ = this;\n\n\t\t// Find parent dialog-panel\n\t\t_.#panel = _.closest('dialog-panel');\n\n\t\tif (!_.#panel) {\n\t\t\tconsole.warn(\n\t\t\t\t'DialogBackdrop: Must be inside a <dialog-panel> element'\n\t\t\t);\n\t\t\treturn;\n\t\t}\n\n\t\t// Handle click to close\n\t\t_.#handlers.click = () => {\n\t\t\t_.#panel.hide();\n\t\t};\n\t\t_.addEventListener('click', _.#handlers.click);\n\t}\n\n\tdisconnectedCallback() {\n\t\tconst _ = this;\n\t\tif (_.#handlers.click) {\n\t\t\t_.removeEventListener('click', _.#handlers.click);\n\t\t}\n\t}\n}\n\n// Register the custom elements\n// Note: dialog-backdrop must be defined BEFORE dialog-panel,\n// because dialog-panel's connectedCallback may create dialog-backdrop elements\nif (!customElements.get('dialog-backdrop')) {\n\tcustomElements.define('dialog-backdrop', DialogBackdrop);\n}\nif (!customElements.get('dialog-panel')) {\n\tcustomElements.define('dialog-panel', DialogPanel);\n}\n\nexport { DialogPanel, DialogBackdrop };\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"dialog-panel.cjs.js","sources":["../src/dialog-panel.js"],"sourcesContent":["import './dialog-panel.css';\n\n/**\n * DialogPanel - A lightweight web component wrapper for native <dialog> elements\n * with state-driven animations.\n *\n * @extends HTMLElement\n *\n * @property {string} state - Current state: 'hidden' | 'showing' | 'shown' | 'hiding'\n * @property {HTMLDialogElement} dialog - Reference to inner <dialog> element\n * @property {boolean} isOpen - True if state is 'showing' or 'shown'\n * @property {HTMLElement|null} triggerElement - Element that triggered current action\n * @property {Object|null} morphEngine - Optional duck-typed morph transition engine\n *\n * @fires beforeShow - Fired before showing starts (cancelable)\n * @fires shown - Fired after show animation completes\n * @fires beforeHide - Fired before hiding starts (cancelable)\n * @fires hidden - Fired after hide animation completes\n */\nclass DialogPanel extends HTMLElement {\n\t// Private fields\n\t#state = 'hidden';\n\t#triggerElement = null;\n\t#dialog = null;\n\t#result = null;\n\t#hideTriggerElement = null;\n\t#morphEngine = null;\n\t#morphListenersAttached = false;\n\n\t// Event handler references for cleanup\n\t#handlers = {\n\t\tclick: null,\n\t\tdialogClick: null,\n\t\tcancel: null,\n\t\tclose: null,\n\t\tmorphShown: null,\n\t\tmorphHidden: null,\n\t\tmorphStop: null,\n\t};\n\n\t// Animation cleanup references\n\t#pendingRAF = null;\n\t#pendingTimeout = null;\n\n\t// Fallback timeout for transitionend (in ms)\n\tstatic TRANSITION_FALLBACK_TIMEOUT = 700;\n\n\tconnectedCallback() {\n\t\tconst _ = this;\n\n\t\t// Find inner dialog element\n\t\t_.#dialog = _.querySelector('dialog');\n\n\t\tif (!_.#dialog) {\n\t\t\tconsole.warn(\n\t\t\t\t'DialogPanel: No <dialog> element found inside <dialog-panel>'\n\t\t\t);\n\t\t\treturn;\n\t\t}\n\n\t\t// Auto-create dialog-backdrop if not present\n\t\tif (!_.querySelector('dialog-backdrop')) {\n\t\t\tconst backdrop = document.createElement('dialog-backdrop');\n\t\t\t_.insertBefore(backdrop, _.firstChild);\n\t\t}\n\n\t\t// Set initial state attribute\n\t\t_.#setState('hidden');\n\n\t\t// Bind event handlers\n\t\t_.#bindEvents();\n\t\t_.#wireMorphEngine();\n\t}\n\n\tdisconnectedCallback() {\n\t\tconst _ = this;\n\n\t\t// Cancel pending animations\n\t\tif (_.#pendingRAF) {\n\t\t\tcancelAnimationFrame(_.#pendingRAF);\n\t\t\t_.#pendingRAF = null;\n\t\t}\n\t\tif (_.#pendingTimeout) {\n\t\t\tclearTimeout(_.#pendingTimeout);\n\t\t\t_.#pendingTimeout = null;\n\t\t}\n\t\t_.#unwireMorphEngine();\n\n\t\t// Clean up event listeners\n\t\tif (_.#handlers.click) {\n\t\t\t_.removeEventListener('click', _.#handlers.click);\n\t\t}\n\t\tif (_.#dialog) {\n\t\t\tif (_.#handlers.dialogClick) {\n\t\t\t\t_.#dialog.removeEventListener(\n\t\t\t\t\t'click',\n\t\t\t\t\t_.#handlers.dialogClick\n\t\t\t\t);\n\t\t\t}\n\t\t\tif (_.#handlers.cancel) {\n\t\t\t\t_.#dialog.removeEventListener('cancel', _.#handlers.cancel);\n\t\t\t}\n\t\t\tif (_.#handlers.close) {\n\t\t\t\t_.#dialog.removeEventListener('close', _.#handlers.close);\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Bind event listeners for close buttons, backdrop, and escape key\n\t * @private\n\t */\n\t#bindEvents() {\n\t\tconst _ = this;\n\n\t\t// Handle close buttons with data-action-hide-dialog\n\t\t_.#handlers.click = (e) => {\n\t\t\tconst trigger = e.target.closest('[data-action-hide-dialog]');\n\t\t\tif (trigger) {\n\t\t\t\te.stopPropagation();\n\t\t\t\t_.hide(trigger);\n\t\t\t}\n\t\t};\n\t\t_.addEventListener('click', _.#handlers.click);\n\n\t\t// Handle backdrop click - detect clicks outside dialog bounds\n\t\t// This works because clicks on ::backdrop still fire on the dialog element\n\t\t_.#handlers.dialogClick = (e) => {\n\t\t\tconst rect = _.#dialog.getBoundingClientRect();\n\t\t\tconst clickedOutside =\n\t\t\t\te.clientX < rect.left ||\n\t\t\t\te.clientX > rect.right ||\n\t\t\t\te.clientY < rect.top ||\n\t\t\t\te.clientY > rect.bottom;\n\t\t\tif (clickedOutside) {\n\t\t\t\te.stopPropagation();\n\t\t\t\t_.hide();\n\t\t\t}\n\t\t};\n\t\t_.#dialog.addEventListener('click', _.#handlers.dialogClick);\n\n\t\t// Handle escape key - intercept native cancel and animate close\n\t\t_.#handlers.cancel = (e) => {\n\t\t\te.preventDefault();\n\t\t\te.stopPropagation();\n\t\t\t_.hide();\n\t\t};\n\t\t_.#dialog.addEventListener('cancel', _.#handlers.cancel);\n\n\t\t// Cover browser force-close paths that bypass the cancel event\n\t\t_.#handlers.close = () => {\n\t\t\tif (\n\t\t\t\t_.#morphEngine?.state === 'shown' &&\n\t\t\t\t_.#state === 'shown' &&\n\t\t\t\t!_.#dialog.open\n\t\t\t) {\n\t\t\t\t_.hide();\n\t\t\t}\n\t\t};\n\t\t_.#dialog.addEventListener('close', _.#handlers.close);\n\t}\n\n\t/**\n\t * Wire morph engine lifecycle listeners\n\t * @private\n\t */\n\t#wireMorphEngine() {\n\t\tconst _ = this;\n\n\t\tif (!_.#morphEngine || _.#morphListenersAttached) return;\n\n\t\tif (!_.#handlers.morphShown) {\n\t\t\t_.#handlers.morphShown = _.#handleMorphShown.bind(_);\n\t\t\t_.#handlers.morphHidden = _.#handleMorphHidden.bind(_);\n\t\t\t_.#handlers.morphStop = _.#handleMorphStop.bind(_);\n\t\t}\n\n\t\t_.#morphEngine.on('shown', _.#handlers.morphShown);\n\t\t_.#morphEngine.on('hidden', _.#handlers.morphHidden);\n\t\t_.#morphEngine.on('stop', _.#handlers.morphStop);\n\t\t_.#morphListenersAttached = true;\n\t}\n\n\t/**\n\t * Unwire morph engine lifecycle listeners\n\t * @private\n\t */\n\t#unwireMorphEngine() {\n\t\tconst _ = this;\n\n\t\tif (!_.#morphEngine || !_.#morphListenersAttached) return;\n\n\t\t_.#morphEngine.off('shown', _.#handlers.morphShown);\n\t\t_.#morphEngine.off('hidden', _.#handlers.morphHidden);\n\t\t_.#morphEngine.off('stop', _.#handlers.morphStop);\n\t\t_.#morphListenersAttached = false;\n\t}\n\n\t/**\n\t * Promote the settled morph target into the dialog top layer\n\t * @private\n\t */\n\t#handleMorphShown() {\n\t\tconst _ = this;\n\n\t\tif (!_.#dialog.open) _.#dialog.showModal();\n\t\t_.#setState('shown');\n\t\t_.#emit('shown');\n\t}\n\n\t/**\n\t * Finalize a settled morph hide\n\t * @private\n\t */\n\t#handleMorphHidden() {\n\t\tthis.#finalizeMorphHide();\n\t}\n\n\t/**\n\t * Finalize an interrupted morph as hidden\n\t * @private\n\t */\n\t#handleMorphStop() {\n\t\tthis.#finalizeMorphHide();\n\t}\n\n\t/**\n\t * Restore the component's hidden state after a morph ends\n\t * @private\n\t */\n\t#finalizeMorphHide() {\n\t\tconst _ = this;\n\n\t\tif (_.#dialog.open) _.#dialog.close();\n\t\t_.#setState('hidden');\n\t\t_.#emit('hidden', {\n\t\t\tresult: _.#result,\n\t\t\ttriggerElement: _.#hideTriggerElement,\n\t\t});\n\n\t\t// Return focus to trigger element\n\t\tif (_.#triggerElement) _.#triggerElement.focus();\n\n\t\t// Clean up\n\t\t_.#triggerElement = null;\n\t\t_.#hideTriggerElement = null;\n\t\t_.#result = null;\n\t}\n\n\t/**\n\t * Show the dialog with animation\n\t * @param {HTMLElement} [triggerEl=null] - The element that triggered the show\n\t * @returns {boolean} False if show was prevented via beforeShow event\n\t */\n\tshow(triggerEl = null) {\n\t\tconst _ = this;\n\n\t\t// Check if already showing/shown\n\t\tif (_.#state === 'showing' || _.#state === 'shown') return true;\n\n\t\tconst reversingMorph =\n\t\t\t_.#state === 'hiding' && _.#morphEngine?.state === 'hiding';\n\n\t\t// CSS transitions cannot reverse while hiding\n\t\tif (_.#state === 'hiding' && !reversingMorph) return false;\n\n\t\t// Store trigger element for focus return later\n\t\tif (!reversingMorph) _.#triggerElement = triggerEl || null;\n\n\t\t// Fire beforeShow (cancelable)\n\t\tif (!_.#emit('beforeShow', { cancelable: true })) return false;\n\n\t\tif (reversingMorph) {\n\t\t\t_.#hideTriggerElement = null;\n\t\t\t_.#result = null;\n\t\t}\n\n\t\t// Set state to 'showing'\n\t\t_.#setState('showing');\n\n\t\tif (_.#morphEngine && (triggerEl || reversingMorph)) {\n\t\t\t_.#morphEngine.show({\n\t\t\t\tfrom: _.#triggerElement,\n\t\t\t\tto: _.#dialog,\n\t\t\t\tdisplay: _.getAttribute('morph-display') || 'block',\n\t\t\t});\n\t\t\treturn true;\n\t\t}\n\n\t\t// Open native dialog for the CSS transition path\n\t\t_.#dialog.showModal();\n\n\t\t// Double RAF ensures browser has painted the 'showing' state\n\t\t// before we transition to 'shown'\n\t\t_.#pendingRAF = requestAnimationFrame(() => {\n\t\t\t_.#pendingRAF = requestAnimationFrame(() => {\n\t\t\t\t_.#pendingRAF = null;\n\t\t\t\t_.#setState('shown');\n\n\t\t\t\t// Wait for transition to complete before firing 'shown' event\n\t\t\t\t_.#waitForTransition(() => {\n\t\t\t\t\t_.#emit('shown');\n\t\t\t\t});\n\t\t\t});\n\t\t});\n\n\t\treturn true;\n\t}\n\n\t/**\n\t * Hide the dialog with animation\n\t * @param {HTMLElement} [triggerEl=null] - The element that triggered the hide\n\t * @returns {boolean} False if hide was prevented via beforeHide event\n\t */\n\thide(triggerEl = null) {\n\t\tconst _ = this;\n\n\t\t// Check if already hiding/hidden\n\t\tif (_.#state === 'hiding' || _.#state === 'hidden') return true;\n\n\t\tconst reversingMorph =\n\t\t\t_.#state === 'showing' && _.#morphEngine?.state === 'showing';\n\n\t\t// CSS transitions cannot reverse while showing\n\t\tif (_.#state === 'showing' && !reversingMorph) return false;\n\n\t\t// Capture result from trigger element\n\t\t_.#result = triggerEl?.dataset?.result ?? null;\n\n\t\t// Fire beforeHide (cancelable)\n\t\tif (\n\t\t\t!_.#emit('beforeHide', {\n\t\t\t\tcancelable: true,\n\t\t\t\tresult: _.#result,\n\t\t\t\ttriggerElement: triggerEl,\n\t\t\t})\n\t\t) {\n\t\t\treturn false;\n\t\t}\n\n\t\tif (reversingMorph || _.#morphEngine?.state === 'shown') {\n\t\t\t_.#hideTriggerElement = triggerEl;\n\t\t\tif (_.#dialog.open) _.#dialog.close();\n\t\t\t_.#morphEngine.hide();\n\t\t\t_.#setState('hiding');\n\t\t\treturn true;\n\t\t}\n\n\t\t// Set state to 'hiding' - this triggers CSS exit animation\n\t\t_.#setState('hiding');\n\n\t\t// Wait for transition to complete\n\t\t_.#waitForTransition(() => {\n\t\t\t_.#dialog.close();\n\t\t\t_.#setState('hidden');\n\t\t\t_.#emit('hidden', {\n\t\t\t\tresult: _.#result,\n\t\t\t\ttriggerElement: triggerEl,\n\t\t\t});\n\n\t\t\t// Return focus to trigger element\n\t\t\tif (_.#triggerElement) _.#triggerElement.focus();\n\n\t\t\t// Clean up\n\t\t\t_.#triggerElement = null;\n\t\t\t_.#result = null;\n\t\t});\n\n\t\treturn true;\n\t}\n\n\t/**\n\t * Wait for CSS transition to complete with fallback timeout\n\t * @param {Function} callback - Called when transition completes\n\t * @private\n\t */\n\t#waitForTransition(callback) {\n\t\tconst _ = this;\n\t\tlet called = false;\n\t\tlet timerId = null;\n\n\t\tconst done = () => {\n\t\t\tif (called) return;\n\t\t\tcalled = true;\n\t\t\t_.#dialog.removeEventListener('transitionend', onTransitionEnd);\n\t\t\t// clear only our own timer — clearing the shared field would let an\n\t\t\t// earlier, still-pending wait cancel a later wait's fallback\n\t\t\tclearTimeout(timerId);\n\t\t\tif (_.#pendingTimeout === timerId) _.#pendingTimeout = null;\n\t\t\tcallback();\n\t\t};\n\n\t\tconst onTransitionEnd = (e) => {\n\t\t\tif (e.target === _.#dialog) done();\n\t\t};\n\n\t\t_.#dialog.addEventListener('transitionend', onTransitionEnd);\n\n\t\ttimerId = setTimeout(done, DialogPanel.TRANSITION_FALLBACK_TIMEOUT);\n\t\t_.#pendingTimeout = timerId;\n\t}\n\n\t/**\n\t * Set the component state\n\t * @param {string} newState - The new state\n\t * @private\n\t */\n\t#setState(newState) {\n\t\tthis.#state = newState;\n\t\tthis.setAttribute('state', newState);\n\t}\n\n\t/**\n\t * Emit a custom event\n\t * @param {string} name - Event name\n\t * @param {Object} options - Event options\n\t * @returns {boolean} False if event was cancelled\n\t * @private\n\t */\n\t#emit(name, options = {}) {\n\t\tconst _ = this;\n\t\tconst { cancelable = false, ...detail } = options;\n\n\t\tconst event = new CustomEvent(name, {\n\t\t\tbubbles: true,\n\t\t\tcomposed: true,\n\t\t\tcancelable,\n\t\t\tdetail: {\n\t\t\t\ttriggerElement: _.#triggerElement,\n\t\t\t\tresult: _.#result,\n\t\t\t\tstate: _.#state,\n\t\t\t\t...detail,\n\t\t\t},\n\t\t});\n\n\t\treturn _.dispatchEvent(event);\n\t}\n\n\t/**\n\t * Optional morph transition transport\n\t * @returns {Object|null} The attached morph engine\n\t */\n\tget morphEngine() {\n\t\treturn this.#morphEngine;\n\t}\n\n\t/**\n\t * Attach or remove a duck-typed morph transition engine\n\t * @param {Object|null} engine - Engine with show, hide, state, on, and off\n\t */\n\tset morphEngine(engine) {\n\t\tconst _ = this;\n\n\t\tif (_.#morphEngine === engine) return;\n\n\t\t_.#unwireMorphEngine();\n\t\t_.#morphEngine = engine || null;\n\n\t\tif (_.#morphEngine) {\n\t\t\t_.setAttribute('morph', '');\n\t\t\t_.#wireMorphEngine();\n\t\t} else {\n\t\t\t_.removeAttribute('morph');\n\t\t}\n\t}\n\n\t// Read-only properties\n\tget state() {\n\t\treturn this.#state;\n\t}\n\tget dialog() {\n\t\treturn this.#dialog;\n\t}\n\tget isOpen() {\n\t\treturn this.#state === 'showing' || this.#state === 'shown';\n\t}\n\tget triggerElement() {\n\t\treturn this.#triggerElement;\n\t}\n}\n\n/**\n * DialogBackdrop - A custom backdrop element that animates with the dialog-panel state.\n * Use this instead of native ::backdrop for consistent cross-browser animations.\n *\n * @extends HTMLElement\n */\nclass DialogBackdrop extends HTMLElement {\n\t#panel = null;\n\t#handlers = {\n\t\tclick: null,\n\t};\n\n\tconnectedCallback() {\n\t\tconst _ = this;\n\n\t\t// Find parent dialog-panel\n\t\t_.#panel = _.closest('dialog-panel');\n\n\t\tif (!_.#panel) {\n\t\t\tconsole.warn(\n\t\t\t\t'DialogBackdrop: Must be inside a <dialog-panel> element'\n\t\t\t);\n\t\t\treturn;\n\t\t}\n\n\t\t// Handle click to close\n\t\t_.#handlers.click = () => {\n\t\t\t_.#panel.hide();\n\t\t};\n\t\t_.addEventListener('click', _.#handlers.click);\n\t}\n\n\tdisconnectedCallback() {\n\t\tconst _ = this;\n\t\tif (_.#handlers.click) {\n\t\t\t_.removeEventListener('click', _.#handlers.click);\n\t\t}\n\t}\n}\n\n// Register the custom elements\n// Note: dialog-backdrop must be defined BEFORE dialog-panel,\n// because dialog-panel's connectedCallback may create dialog-backdrop elements\nif (!customElements.get('dialog-backdrop')) {\n\tcustomElements.define('dialog-backdrop', DialogBackdrop);\n}\nif (!customElements.get('dialog-panel')) {\n\tcustomElements.define('dialog-panel', DialogPanel);\n}\n\nexport { DialogPanel, DialogBackdrop };\n"],"names":[],"mappings":"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"}
@@ -116,84 +116,115 @@ dialog-panel[state='hiding'] > dialog-backdrop {
116
116
 
117
117
  /* ============================================================
118
118
  Position variants — drawer-style slide-in animations.
119
- Default (no position attr, or position="center") uses the
120
- centered fade/scale animation defined above.
119
+ Self-contained: declares its own `position: fixed` and
120
+ explicit inset values so it doesn't rely on the UA's
121
+ `dialog:modal` styling or on consumer body overflow rules.
122
+ Default (no position attr) uses the centered fade/scale
123
+ animation defined above.
121
124
  ============================================================ */
122
125
 
126
+ /* Shared base for all four drawer positions */
127
+ dialog-panel[position='top'] > dialog,
128
+ dialog-panel[position='right'] > dialog,
129
+ dialog-panel[position='bottom'] > dialog,
130
+ dialog-panel[position='left'] > dialog {
131
+ position: fixed;
132
+ margin: 0;
133
+ max-width: 100%;
134
+ opacity: 1;
135
+ }
136
+
123
137
  /* ---- Top drawer ---- */
124
138
  dialog-panel[position='top'] > dialog {
125
- margin: 0 auto auto auto;
139
+ top: 0;
140
+ right: 0;
141
+ bottom: auto;
142
+ left: 0;
126
143
  width: 100%;
127
- max-width: 100%;
128
144
  max-height: 85vh;
129
- }
130
-
131
- dialog-panel[position='top'][state='showing'] > dialog,
132
- dialog-panel[position='top'][state='hiding'] > dialog {
133
- opacity: 1;
134
145
  transform: translateY(-100%);
135
146
  }
136
147
 
137
148
  dialog-panel[position='top'][state='shown'] > dialog {
138
- opacity: 1;
139
149
  transform: translateY(0);
140
150
  }
141
151
 
142
152
  /* ---- Bottom drawer ---- */
143
153
  dialog-panel[position='bottom'] > dialog {
144
- margin: auto auto 0 auto;
154
+ top: auto;
155
+ right: 0;
156
+ bottom: 0;
157
+ left: 0;
145
158
  width: 100%;
146
- max-width: 100%;
147
159
  max-height: 85vh;
148
- }
149
-
150
- dialog-panel[position='bottom'][state='showing'] > dialog,
151
- dialog-panel[position='bottom'][state='hiding'] > dialog {
152
- opacity: 1;
153
160
  transform: translateY(100%);
154
161
  }
155
162
 
156
163
  dialog-panel[position='bottom'][state='shown'] > dialog {
157
- opacity: 1;
158
164
  transform: translateY(0);
159
165
  }
160
166
 
161
167
  /* ---- Left drawer ---- */
162
168
  dialog-panel[position='left'] > dialog {
163
- margin: auto auto auto 0;
169
+ top: 0;
170
+ right: auto;
171
+ bottom: 0;
172
+ left: 0;
173
+ width: min(24rem, 90vw);
164
174
  height: 100dvh;
165
175
  max-height: 100dvh;
166
- width: min(24rem, 90vw);
167
- max-width: 100%;
168
- }
169
-
170
- dialog-panel[position='left'][state='showing'] > dialog,
171
- dialog-panel[position='left'][state='hiding'] > dialog {
172
- opacity: 1;
173
176
  transform: translateX(-100%);
174
177
  }
175
178
 
176
179
  dialog-panel[position='left'][state='shown'] > dialog {
177
- opacity: 1;
178
180
  transform: translateX(0);
179
181
  }
180
182
 
181
183
  /* ---- Right drawer ---- */
182
184
  dialog-panel[position='right'] > dialog {
183
- margin: auto 0 auto auto;
185
+ top: 0;
186
+ right: 0;
187
+ bottom: 0;
188
+ left: auto;
189
+ width: min(24rem, 90vw);
184
190
  height: 100dvh;
185
191
  max-height: 100dvh;
186
- width: min(24rem, 90vw);
187
- max-width: 100%;
192
+ transform: translateX(100%);
193
+ }
194
+
195
+ dialog-panel[position='right'][state='shown'] > dialog {
196
+ transform: translateX(0);
197
+ }
198
+
199
+ /* ============================================================
200
+ Page scroll lock — prevents the underlying page from
201
+ scrolling while any dialog-panel is open or animating.
202
+ Keyed on the package's own [state='*'] attributes so it
203
+ activates from the first frame of the opening animation
204
+ and stays through the closing animation, regardless of
205
+ when the native <dialog>'s [open] attribute is toggled.
206
+ ============================================================ */
207
+ body:has(dialog-panel[state='showing']),
208
+ body:has(dialog-panel[state='shown']),
209
+ body:has(dialog-panel[state='hiding']) {
210
+ overflow: hidden;
188
211
  }
189
212
 
190
- dialog-panel[position='right'][state='showing'] > dialog,
191
- dialog-panel[position='right'][state='hiding'] > dialog {
213
+ /* Morph transport — the engine owns opacity, transforms, and transitions */
214
+ dialog-panel[morph] > dialog,
215
+ dialog-panel[morph][state] > dialog {
216
+ position: fixed;
217
+ inset: 0;
218
+ margin: auto;
219
+ max-width: none;
220
+ max-height: none;
192
221
  opacity: 1;
193
- transform: translateX(100%);
222
+ transform: none;
223
+ transition: none;
194
224
  }
195
225
 
196
- dialog-panel[position='right'][state='shown'] > dialog {
226
+ /* Bring in the scrim during the outbound morph flight */
227
+ dialog-panel[morph][state='showing'] > dialog-backdrop {
197
228
  opacity: 1;
198
- transform: translateX(0);
229
+ pointer-events: auto;
199
230
  }