@rcarls/rc-dialog 0.3.2 → 0.4.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
@@ -23,7 +23,9 @@ import { RCDialog } from '@rcarls/rc-dialog'; // named class export
23
23
 
24
24
  ## Basic usage
25
25
 
26
- Place a `<dialog>` element directly inside `<rc-dialog>`. The inner `<dialog>` must have `aria-labelledby` or `aria-label` to satisfy the [WAI-ARIA Dialog pattern](https://www.w3.org/WAI/ARIA/apg/patterns/dialog-modal/).
26
+ Place a `<dialog>` element directly inside `<rc-dialog>`. The inner `<dialog>` must have
27
+ `aria-labelledby` or `aria-label` to satisfy the
28
+ [WAI-ARIA Dialog pattern](https://www.w3.org/WAI/ARIA/apg/patterns/dialog-modal/).
27
29
 
28
30
  ```html
29
31
  <rc-dialog id="my-dialog">
@@ -45,15 +47,17 @@ Place a `<dialog>` element directly inside `<rc-dialog>`. The inner `<dialog>` m
45
47
 
46
48
  | Property | Attribute | Type | Default | Description |
47
49
  |---|---|---|---|---|
48
- | `open` | `open` | `boolean` | — | Controlled open state. Setting to `true`/`false` opens/closes the dialog silently (no `rc-dialog-toggle` event). Reads the inner `<dialog>.open` value. |
50
+ | `open` | `open` | `boolean` | None | Controlled open state. Setting to `true`/`false` opens/closes the dialog silently (no `rc-dialog-toggle` event). Reads the inner `<dialog>.open` value. |
49
51
  | `defaultOpen` | `default-open` | `boolean` | `false` | Uncontrolled initial open state. The component takes ownership after initialization. |
50
- | `modal` | — | `boolean` | `true` | Whether controlled `open` / `defaultOpen` opens as modal (`showModal`) or non-modal (`show`). No effect on direct `showModal()` / `show()` calls. JS property only — no attribute. |
52
+ | `modal` | None | `boolean` | `true` | Whether controlled `open` / `defaultOpen` opens as modal (`showModal`) or non-modal (`show`). No effect on direct `showModal()` / `show()` calls. JS property only; no attribute. |
51
53
  | `movable` | `movable` | `boolean` | `false` | Enable drag-to-move. Named `movable` (not `draggable`) to avoid colliding with the HTML `draggable` attribute. |
52
- | `moveHandle` | `move-handle` | `string` | `''` | CSS selector for the drag handle within the inner `<dialog>` (e.g. `'.titlebar'`). Defaults to the whole dialog. |
54
+ | `moveHandle` | `move-handle` | `string` | `''` | CSS selector for the drag handle within the inner `<dialog>` (for example, `'.titlebar'`). Defaults to the whole dialog. |
53
55
  | `moveBounds` | `move-bounds` | `'viewport' \| 'parent'` | `'viewport'` | Constrains drag within the viewport or the nearest positioned ancestor. |
54
56
  | `moveStep` | `move-step` | `number` | `4` | Keyboard arrow-key step in px when moving. Shift multiplies by 10×. |
55
57
  | `resize` | `resize` | `'none' \| 'both' \| 'horizontal' \| 'vertical'` | `'none'` | Enables edge/corner resizing, mirroring CSS `resize` semantics. |
56
- | `resizeThreshold` | `resize-threshold` | `number` | `8` | Edge hit-test band in px (straddles the border — half inside, half outside). |
58
+ | `resizeOrigin` | `resize-origin` | `'' \| 'top' \| 'right' \| 'bottom' \| 'left' \| 'top-left' \| 'top-right' \| 'bottom-left' \| 'bottom-right'` | `''` | Constrains fallback edge detection or supplies the default origin for explicit handles. Empty keeps free edge detection. |
59
+ | `resizeHandle` | `resize-handle` | `string` | `''` | CSS selector for explicit resize handles within the inner `<dialog>`. Matching handles receive pointer and keyboard resize behavior. |
60
+ | `resizeThreshold` | `resize-threshold` | `number` | `8` | Edge hit-test band in px (straddles the border, half inside and half outside). |
57
61
  | `resizeStep` | `resize-step` | `number` | `4` | Keyboard arrow-key step in px when resizing. Shift multiplies by 10×. |
58
62
  | `closedBy` | `closed-by` | `'any' \| 'closerequest' \| 'none' \| ''` | `''` | Proxied to the inner `<dialog closedby="...">` attribute (Chrome 134+, Safari 18.4+, Firefox 139+). `'any'` = Escape or backdrop click; `'closerequest'` = Escape only; `'none'` = programmatic only. |
59
63
  | `lightDismiss` | `light-dismiss` | `boolean` | `false` | JS fallback for backdrop-click dismissal. Detects clicks whose target is the `<dialog>` element itself and calls `requestClose()`. Works in all browsers alongside or instead of `closed-by`. |
@@ -81,14 +85,21 @@ returnValue: string // The return value set when the dialog last closed.
81
85
 
82
86
  | Event | Cancelable | Detail | Description |
83
87
  |---|---|---|---|
84
- | `rc-dialog-open` | No | — | Fired when the dialog opens via `showModal()` or `show()`. |
88
+ | `rc-dialog-open` | No | None | Fired when the dialog opens via `showModal()` or `show()`. |
85
89
  | `rc-dialog-toggle` | No | `{ open: boolean, returnValue: string }` | Fired when user or native interaction changes the open state. Not fired on silent host writes (`open` property). |
86
90
  | `rc-dialog-request-close` | **Yes** | `{ returnValue: string }` | Fired before close (Escape, backdrop click, or `requestClose()`). Call `preventDefault()` to block. |
87
- | `rc-dialog-cancel` | No | — | Fired after `rc-dialog-request-close` when the close was not prevented. Backward-compatible alias. |
91
+ | `rc-dialog-cancel` | No | None | Fired after `rc-dialog-request-close` when the close was not prevented. Backward-compatible alias. |
88
92
  | `rc-dialog-close` | No | `{ returnValue: string }` | Fired after the dialog has closed. |
89
93
 
90
94
  ---
91
95
 
96
+ ### Theming
97
+
98
+ Set `--rc-dialog-scrim` on `<rc-dialog>` or a theme scope to customize the modal
99
+ backdrop color. Theme packages consume this token in their `::backdrop` styles.
100
+
101
+ ---
102
+
92
103
  ## Examples
93
104
 
94
105
  ### Movable dialog with a drag handle
@@ -105,7 +116,8 @@ returnValue: string // The return value set when the dialog last closed.
105
116
  </rc-dialog>
106
117
  ```
107
118
 
108
- Drag the `.titlebar` to reposition. Focus the titlebar and use **Arrow keys** to move it (Shift = 10× step).
119
+ Drag the `.titlebar` to reposition. Focus the titlebar and use **Arrow keys** to move it
120
+ (Shift = 10× step).
109
121
 
110
122
  ### Movable + resizable
111
123
 
@@ -117,7 +129,30 @@ Drag the `.titlebar` to reposition. Focus the titlebar and use **Arrow keys** to
117
129
  </rc-dialog>
118
130
  ```
119
131
 
120
- All 8 resize handles are active (n, s, e, w, ne, nw, se, sw). Opposite-edge handles anchor the far side and move `left`/`top`, mirroring OS-window resize semantics. A small keyboard-accessible resize button is injected at the bottom-right corner.
132
+ All eight resize handles are active (top, right, bottom, left, and the four corners).
133
+ Opposite-edge handles anchor the far side and move `left` or `top`, mirroring OS-window resize
134
+ semantics. A small keyboard-accessible resize button is injected at the bottom-right corner.
135
+
136
+ ### Explicit resize handle
137
+
138
+ ```html
139
+ <rc-dialog id="sheet-like" resize="vertical" resize-origin="top" resize-handle=".resize-handle">
140
+ <dialog aria-labelledby="sheet-title">
141
+ <button
142
+ type="button"
143
+ class="resize-handle"
144
+ data-rc-dialog-resize-axis="y"
145
+ data-rc-dialog-resize-origin="top"
146
+ aria-label="Resize"
147
+ ></button>
148
+ <h2 id="sheet-title">Filters</h2>
149
+ </dialog>
150
+ </rc-dialog>
151
+ ```
152
+
153
+ Use `data-rc-dialog-resize-axis="x|y|both"` and
154
+ `data-rc-dialog-resize-origin="top|right|bottom|left|top-left|..."`
155
+ on individual handles to override the host resize direction or origin.
121
156
 
122
157
  ### Minimal / no-header dialog
123
158
 
@@ -138,7 +173,8 @@ No titlebar or footer structure is required. Any layout is valid.
138
173
 
139
174
  ### Alert / confirm dialog
140
175
 
141
- Use `role="alertdialog"` with `aria-describedby` pointing to the message text. Assistive technology treats this with higher urgency.
176
+ Use `role="alertdialog"` with `aria-describedby` pointing to the message text. Assistive
177
+ technology treats this with higher urgency.
142
178
 
143
179
  ```html
144
180
  <rc-dialog id="confirm">
@@ -157,7 +193,8 @@ Use `role="alertdialog"` with `aria-describedby` pointing to the message text. A
157
193
 
158
194
  ### Native form integration
159
195
 
160
- `<form method="dialog">` submits to the dialog: the submit button's `value` becomes `returnValue` and the dialog closes — no JavaScript needed.
196
+ `<form method="dialog">` submits to the dialog: the submit button's `value` becomes
197
+ `returnValue`, and the dialog closes without JavaScript.
161
198
 
162
199
  ```html
163
200
  <rc-dialog id="dlg">
@@ -189,7 +226,7 @@ Use `role="alertdialog"` with `aria-describedby` pointing to the message text. A
189
226
  <button onclick="document.querySelector('#dlg').requestClose('cancel')">✕</button>
190
227
  </div>
191
228
  <textarea id="note" rows="5"></textarea>
192
- <p id="warning" hidden role="alert">Unsaved changes — save or discard first.</p>
229
+ <p id="warning" hidden role="alert">Unsaved changes; save or discard first.</p>
193
230
  <div class="footer">
194
231
  <button onclick="note.value=''; dlg.close('discard')">Discard</button>
195
232
  <button onclick="dlg.close('save')">Save</button>
@@ -219,7 +256,9 @@ Use `role="alertdialog"` with `aria-describedby` pointing to the message text. A
219
256
  </rc-dialog>
220
257
  ```
221
258
 
222
- `closed-by="any"` delegates to the browser's native light-dismiss on supporting browsers. `light-dismiss` adds a JS click-on-backdrop fallback that works everywhere and routes through `requestClose()` (so close guards still apply).
259
+ `closed-by="any"` delegates to the browser's native light-dismiss on supporting browsers.
260
+ `light-dismiss` adds a JS click-on-backdrop fallback that works everywhere and routes through
261
+ `requestClose()`, so close guards still apply.
223
262
 
224
263
  ---
225
264
 
@@ -227,20 +266,26 @@ Use `role="alertdialog"` with `aria-describedby` pointing to the message text. A
227
266
 
228
267
  `<rc-dialog>` delegates entirely to the native `<dialog>` element:
229
268
 
230
- - **Focus trapping** — built into `showModal()` (Tab/Shift+Tab stays inside the dialog).
231
- - **Focus restoration** — `rc-dialog` captures the focused element before opening and restores focus to it on close. If the opener was removed from the DOM while the dialog was open, focus falls back to `document.body`.
232
- - **Escape to close** — native behaviour; routes through `rc-dialog-request-close` so guards still apply.
233
- - **`aria-modal`** — `showModal()` implies `aria-modal="true"` without an explicit attribute.
269
+ - **Focus trapping:** Built into `showModal()` (Tab/Shift+Tab stays inside the dialog).
270
+ - **Focus restoration:** `rc-dialog` captures the focused element before opening and restores
271
+ focus to it on close. If the opener was removed from the DOM while the dialog was open, focus
272
+ falls back to `document.body`.
273
+ - **Escape to close:** Native behavior routes through `rc-dialog-request-close` so guards still
274
+ apply.
275
+ - **`aria-modal`:** `showModal()` implies `aria-modal="true"` without an explicit attribute.
234
276
 
235
- **Required:** The inner `<dialog>` must have `aria-labelledby` or `aria-label`. In development mode the component logs a console warning if either is absent.
277
+ **Required:** The inner `<dialog>` must have `aria-labelledby` or `aria-label`. In development
278
+ mode the component logs a console warning if either is absent.
236
279
 
237
- **Alert dialogs:** When `role="alertdialog"` is set, add `aria-describedby` pointing to the message text. A dev-mode warning fires if it is missing.
280
+ **Alert dialogs:** When `role="alertdialog"` is set, add `aria-describedby` pointing to the
281
+ message text. A dev-mode warning fires if it is missing.
238
282
 
239
283
  ---
240
284
 
241
285
  ## CSS layout for scrollable dialogs
242
286
 
243
- When the dialog needs scrollable body content (especially when resizable), use flex layout so the body grows and the header/footer stay fixed:
287
+ When the dialog needs scrollable body content (especially when resizable), use flex layout so
288
+ the body grows and the header/footer stay fixed:
244
289
 
245
290
  ```css
246
291
  dialog[open] {
@@ -261,7 +306,9 @@ dialog[open] {
261
306
  }
262
307
  ```
263
308
 
264
- > **Note:** `display: flex` must be scoped to `dialog[open]`, not `dialog`. Author styles take precedence over the UA `dialog:not([open]) { display: none }` rule — scoping to `[open]` prevents all dialogs from being visible on page load.
309
+ > **Note:** `display: flex` must be scoped to `dialog[open]`, not `dialog`. Author styles take
310
+ > precedence over the UA `dialog:not([open]) { display: none }` rule. Scoping to `[open]`
311
+ > prevents all dialogs from being visible on page load.
265
312
 
266
313
  ---
267
314
 
@@ -48,6 +48,13 @@
48
48
  "kind": "class",
49
49
  "description": "Draggable, resizable wrapper for a native <dialog>, following the WAI-ARIA Dialog Modal\npattern.",
50
50
  "name": "RCDialog",
51
+ "cssProperties": [
52
+ {
53
+ "description": "Modal backdrop color.",
54
+ "name": "--rc-dialog-scrim",
55
+ "default": "color-mix(in srgb, CanvasText 32%, transparent)"
56
+ }
57
+ ],
51
58
  "slots": [
52
59
  {
53
60
  "description": "Place a `<dialog>` element with your content here.",
@@ -107,6 +114,26 @@
107
114
  "attribute": "resize",
108
115
  "reflects": true
109
116
  },
117
+ {
118
+ "kind": "field",
119
+ "name": "resizeOrigin",
120
+ "type": {
121
+ "text": "ResizeOrigin"
122
+ },
123
+ "default": "''",
124
+ "description": "Origin for resize edge hit-testing or explicit handles.\n\nEmpty preserves the historical free edge-detection behavior.",
125
+ "attribute": "resize-origin"
126
+ },
127
+ {
128
+ "kind": "field",
129
+ "name": "resizeHandle",
130
+ "type": {
131
+ "text": "string"
132
+ },
133
+ "default": "''",
134
+ "description": "CSS selector, scoped to the inner `<dialog>`, for one or more explicit\nresize handles.\n\nHandles may override host behavior with:\n- `data-rc-dialog-resize-axis=\"x|y|both\"`\n- `data-rc-dialog-resize-origin=\"top|right|bottom|left|top-left|...\"`",
135
+ "attribute": "resize-handle"
136
+ },
110
137
  {
111
138
  "kind": "field",
112
139
  "name": "resizeThreshold",
@@ -188,7 +215,7 @@
188
215
  {
189
216
  "kind": "field",
190
217
  "name": "_dialogController",
191
- "privacy": "private",
218
+ "privacy": "protected",
192
219
  "readonly": true,
193
220
  "default": "new NativeChildController<HTMLDialogElement>(this, { selector: ':scope > dialog', observe: true, onChange: ($dialog) => this._setupDialog($dialog), onMissing: () => { if (import.meta.env.DEV) { warnMissingDirectChild(this, { selector: ':scope > dialog', message: '[rc-dialog] No direct child <dialog> found. Place a native <dialog> inside <rc-dialog>.', }); } }, })"
194
221
  },
@@ -198,7 +225,7 @@
198
225
  "type": {
199
226
  "text": "WeakRef<HTMLDialogElement> | null"
200
227
  },
201
- "privacy": "private",
228
+ "privacy": "protected",
202
229
  "default": "null"
203
230
  },
204
231
  {
@@ -207,7 +234,7 @@
207
234
  "type": {
208
235
  "text": "boolean"
209
236
  },
210
- "privacy": "private",
237
+ "privacy": "protected",
211
238
  "default": "false"
212
239
  },
213
240
  {
@@ -349,6 +376,117 @@
349
376
  "privacy": "protected",
350
377
  "description": "Detects backdrop clicks."
351
378
  },
379
+ {
380
+ "kind": "method",
381
+ "name": "_onResizeStart",
382
+ "privacy": "protected",
383
+ "return": {
384
+ "type": {
385
+ "text": "void"
386
+ }
387
+ },
388
+ "parameters": [
389
+ {
390
+ "name": "_detail",
391
+ "type": {
392
+ "text": "ResizeLifecycleDetail"
393
+ }
394
+ }
395
+ ],
396
+ "description": "Hook for subclasses to respond when a resize gesture begins."
397
+ },
398
+ {
399
+ "kind": "method",
400
+ "name": "_onResize",
401
+ "privacy": "protected",
402
+ "return": {
403
+ "type": {
404
+ "text": "void"
405
+ }
406
+ },
407
+ "parameters": [
408
+ {
409
+ "name": "_detail",
410
+ "type": {
411
+ "text": "ResizeLifecycleDetail"
412
+ }
413
+ }
414
+ ],
415
+ "description": "Hook for subclasses to respond to each resize update during an active gesture."
416
+ },
417
+ {
418
+ "kind": "method",
419
+ "name": "_onResizeEnd",
420
+ "privacy": "protected",
421
+ "return": {
422
+ "type": {
423
+ "text": "void"
424
+ }
425
+ },
426
+ "parameters": [
427
+ {
428
+ "name": "_detail",
429
+ "type": {
430
+ "text": "ResizeLifecycleDetail"
431
+ }
432
+ }
433
+ ],
434
+ "description": "Hook for subclasses to respond after a resize gesture has settled."
435
+ },
436
+ {
437
+ "kind": "method",
438
+ "name": "_resizeHandles",
439
+ "privacy": "protected",
440
+ "return": {
441
+ "type": {
442
+ "text": "Element[]"
443
+ }
444
+ },
445
+ "parameters": [
446
+ {
447
+ "name": "$dialog",
448
+ "type": {
449
+ "text": "HTMLDialogElement"
450
+ }
451
+ }
452
+ ]
453
+ },
454
+ {
455
+ "kind": "method",
456
+ "name": "_resizeDirectionForHandle",
457
+ "privacy": "protected",
458
+ "return": {
459
+ "type": {
460
+ "text": "ResizeDirection"
461
+ }
462
+ },
463
+ "parameters": [
464
+ {
465
+ "name": "$handle",
466
+ "type": {
467
+ "text": "Element"
468
+ }
469
+ }
470
+ ]
471
+ },
472
+ {
473
+ "kind": "method",
474
+ "name": "_resizeOriginForHandle",
475
+ "privacy": "protected",
476
+ "return": {
477
+ "type": {
478
+ "text": "ResizeOrigin"
479
+ }
480
+ },
481
+ "parameters": [
482
+ {
483
+ "name": "$handle",
484
+ "type": {
485
+ "text": "Element"
486
+ }
487
+ }
488
+ ]
489
+ },
352
490
  {
353
491
  "kind": "method",
354
492
  "name": "_applyOpen",
@@ -364,19 +502,19 @@
364
502
  "type": {
365
503
  "text": "boolean"
366
504
  },
367
- "description": "Whether to open (`true`) or close (`false`)."
505
+ "description": "whether to open (`true`) or close (`false`)"
368
506
  },
369
507
  {
370
508
  "name": "silent",
371
509
  "type": {
372
510
  "text": "boolean"
373
511
  },
374
- "description": "When `true`, suppresses the outgoing `rc-dialog-toggle` event."
512
+ "description": "when `true`, suppresses the outgoing `rc-dialog-toggle` event"
375
513
  },
376
514
  {
377
515
  "name": "modal",
378
516
  "default": "true",
379
- "description": "Whether to call `showModal()` (`true`) or `show()` (`false`)."
517
+ "description": "whether to call `showModal()` (`true`) or `show()` (`false`)"
380
518
  }
381
519
  ],
382
520
  "description": "Opens or closes the inner `<dialog>` and returns `true` if state actually changed."
@@ -431,101 +569,119 @@
431
569
  ],
432
570
  "attributes": [
433
571
  {
572
+ "description": "Whether the inner `<dialog>` is currently open. Host writes update silently.",
573
+ "name": "open",
574
+ "type": {
575
+ "text": "boolean"
576
+ },
577
+ "fieldName": "open"
578
+ },
579
+ {
580
+ "description": "Initial uncontrolled open state.",
581
+ "name": "default-open",
582
+ "type": {
583
+ "text": "boolean"
584
+ },
585
+ "fieldName": "defaultOpen"
586
+ },
587
+ {
588
+ "description": "Allow the dialog to be moved by dragging.\n\nUse `move-handle` to restrict dragging to a specific child\nelement (e.g. a titlebar).",
434
589
  "name": "movable",
435
590
  "type": {
436
591
  "text": "boolean"
437
592
  },
438
593
  "default": "false",
439
- "description": "Allow the dialog to be moved by dragging.\n\nUse `move-handle` to restrict dragging to a specific child\nelement (e.g. a titlebar).",
440
594
  "fieldName": "movable"
441
595
  },
442
596
  {
597
+ "description": "CSS selector (within the inner `<dialog>`) for the drag handle element.",
443
598
  "name": "move-handle",
444
599
  "type": {
445
600
  "text": "string"
446
601
  },
447
602
  "default": "''",
448
- "description": "CSS selector (within the inner `<dialog>`) for the drag handle element.",
449
603
  "fieldName": "moveHandle"
450
604
  },
451
605
  {
606
+ "description": "Bounds constraint for movement.",
452
607
  "name": "move-bounds",
453
608
  "type": {
454
609
  "text": "'viewport' | 'parent'"
455
610
  },
456
611
  "default": "'viewport'",
457
- "description": "Bounds constraint for movement.",
458
612
  "fieldName": "moveBounds"
459
613
  },
460
614
  {
615
+ "description": "Keyboard arrow-key step in px for moving.",
461
616
  "name": "move-step",
462
617
  "type": {
463
618
  "text": "number"
464
619
  },
465
620
  "default": "4",
466
- "description": "Keyboard arrow-key step in px for moving.",
467
621
  "fieldName": "moveStep"
468
622
  },
469
623
  {
624
+ "description": "Enable resizing, mirroring the CSS `resize` property values.",
470
625
  "name": "resize",
471
626
  "type": {
472
627
  "text": "'none' | 'both' | 'horizontal' | 'vertical'"
473
628
  },
474
629
  "default": "'none'",
475
- "description": "Enable resizing, mirroring the CSS `resize` property values.",
476
630
  "fieldName": "resize"
477
631
  },
478
632
  {
633
+ "description": "Origin for resize edge hit-testing or explicit handles.\n\nEmpty preserves the historical free edge-detection behavior.",
634
+ "name": "resize-origin",
635
+ "type": {
636
+ "text": "ResizeOrigin"
637
+ },
638
+ "default": "''",
639
+ "fieldName": "resizeOrigin"
640
+ },
641
+ {
642
+ "description": "CSS selector, scoped to the inner `<dialog>`, for one or more explicit\nresize handles.\n\nHandles may override host behavior with:\n- `data-rc-dialog-resize-axis=\"x|y|both\"`\n- `data-rc-dialog-resize-origin=\"top|right|bottom|left|top-left|...\"`",
643
+ "name": "resize-handle",
644
+ "type": {
645
+ "text": "string"
646
+ },
647
+ "default": "''",
648
+ "fieldName": "resizeHandle"
649
+ },
650
+ {
651
+ "description": "Edge hit-test thickness in px for resize detection.",
479
652
  "name": "resize-threshold",
480
653
  "type": {
481
654
  "text": "number"
482
655
  },
483
656
  "default": "8",
484
- "description": "Edge hit-test thickness in px for resize detection.",
485
657
  "fieldName": "resizeThreshold"
486
658
  },
487
659
  {
660
+ "description": "Keyboard arrow-key step in px for resizing.",
488
661
  "name": "resize-step",
489
662
  "type": {
490
663
  "text": "number"
491
664
  },
492
665
  "default": "4",
493
- "description": "Keyboard arrow-key step in px for resizing.",
494
666
  "fieldName": "resizeStep"
495
667
  },
496
668
  {
669
+ "description": "Proxied to the inner `<dialog closedby=\"...\">` attribute.\n\nProgressive enhancement, no-op in older browsers.\n\n- `'any'` — Escape OR backdrop click closes the dialog.\n- `'closerequest'` — Escape only (browser default for modal dialogs).\n- `'none'` — Only programmatic `close()` / `requestClose()`.\n- `''` — Attribute absent; use `light-dismiss` for JS fallback.",
497
670
  "name": "closed-by",
498
671
  "type": {
499
672
  "text": "'any' | 'closerequest' | 'none' | ''"
500
673
  },
501
674
  "default": "''",
502
- "description": "Proxied to the inner `<dialog closedby=\"...\">` attribute.\n\nProgressive enhancement, no-op in older browsers.\n\n- `'any'` — Escape OR backdrop click closes the dialog.\n- `'closerequest'` — Escape only (browser default for modal dialogs).\n- `'none'` — Only programmatic `close()` / `requestClose()`.\n- `''` — Attribute absent; use `light-dismiss` for JS fallback.",
503
675
  "fieldName": "closedBy"
504
676
  },
505
677
  {
678
+ "description": "When true and the dialog is modal, a click on the backdrop area calls\n`requestClose()`.",
506
679
  "name": "light-dismiss",
507
680
  "type": {
508
681
  "text": "boolean"
509
682
  },
510
683
  "default": "false",
511
- "description": "When true and the dialog is modal, a click on the backdrop area calls\n`requestClose()`.",
512
684
  "fieldName": "lightDismiss"
513
- },
514
- {
515
- "name": "open",
516
- "type": {
517
- "text": "boolean"
518
- },
519
- "description": "Whether the inner `<dialog>` is currently open. Host writes update silently.",
520
- "fieldName": "open"
521
- },
522
- {
523
- "name": "default-open",
524
- "type": {
525
- "text": "boolean"
526
- },
527
- "description": "Initial uncontrolled open state.",
528
- "fieldName": "defaultOpen"
529
685
  }
530
686
  ],
531
687
  "superclass": {
@@ -1,14 +1,14 @@
1
- import { LitElement as a, nothing as d } from "lit";
2
- import { property as i } from "lit/decorators.js";
3
- import { NativeChildController as u, DragController as c, ResizeController as f } from "@rcarls/rc-common";
4
- var _ = Object.defineProperty, m = Object.getOwnPropertyDescriptor, o = (n, e, t, l) => {
5
- for (var s = l > 1 ? void 0 : l ? m(e, t) : e, p = n.length - 1, h; p >= 0; p--)
6
- (h = n[p]) && (s = (l ? h(e, t, s) : h(s)) || s);
7
- return l && s && _(e, t, s), s;
1
+ import { LitElement as p, nothing as u } from "lit";
2
+ import { property as r } from "lit/decorators.js";
3
+ import { NativeChildController as c, DragController as _, ResizeController as d } from "@rcarls/rc-common";
4
+ var f = Object.defineProperty, g = Object.getOwnPropertyDescriptor, o = (l, e, t, i) => {
5
+ for (var s = i > 1 ? void 0 : i ? g(e, t) : e, a = l.length - 1, h; a >= 0; a--)
6
+ (h = l[a]) && (s = (i ? h(e, t, s) : h(s)) || s);
7
+ return i && s && f(e, t, s), s;
8
8
  };
9
- class r extends a {
9
+ class n extends p {
10
10
  constructor() {
11
- super(...arguments), this.movable = !1, this.moveHandle = "", this.moveBounds = "viewport", this.moveStep = 4, this.resize = "none", this.resizeThreshold = 8, this.resizeStep = 4, this.closedBy = "", this.lightDismiss = !1, this.modal = !0, this._controlledOpen = void 0, this._defaultOpen = !1, this._dialogController = new u(this, {
11
+ super(...arguments), this.movable = !1, this.moveHandle = "", this.moveBounds = "viewport", this.moveStep = 4, this.resize = "none", this.resizeOrigin = "", this.resizeHandle = "", this.resizeThreshold = 8, this.resizeStep = 4, this.closedBy = "", this.lightDismiss = !1, this.modal = !0, this._controlledOpen = void 0, this._defaultOpen = !1, this._dialogController = new c(this, {
12
12
  selector: ":scope > dialog",
13
13
  observe: !0,
14
14
  onChange: (e) => this._setupDialog(e),
@@ -83,12 +83,12 @@ class r extends a {
83
83
  if ("requestClose" in t && typeof t.requestClose == "function")
84
84
  t.requestClose(e);
85
85
  else {
86
- const l = new Event("cancel", { cancelable: !0, bubbles: !1 });
87
- !t.dispatchEvent(l) || t.close(e);
86
+ const i = new Event("cancel", { cancelable: !0, bubbles: !1 });
87
+ !t.dispatchEvent(i) || t.close(e);
88
88
  }
89
89
  }
90
90
  render() {
91
- return d;
91
+ return u;
92
92
  }
93
93
  firstUpdated() {
94
94
  this._dialogController.sync();
@@ -102,20 +102,43 @@ class r extends a {
102
102
  if (this._$wired?.deref() !== e) {
103
103
  if (this._teardownDialog(), this._$wired = new WeakRef(e), e.addEventListener("close", this._onClose), e.addEventListener("cancel", this._onCancel), this.lightDismiss && "closedBy" in HTMLDialogElement.prototype ? e.setAttribute("closedby", "any") : this.lightDismiss ? e.addEventListener("click", this._onBackdropClick) : this.closedBy && e.setAttribute("closedby", this.closedBy), this.movable || this.moveHandle) {
104
104
  const t = this.moveHandle ? e.querySelector(this.moveHandle) ?? e : e;
105
- new c(this, {
105
+ new _(this, {
106
106
  target: e,
107
107
  handle: t,
108
108
  bounds: this.moveBounds,
109
109
  step: this.moveStep
110
110
  });
111
111
  }
112
- this.resize !== "none" && new f(this, {
113
- target: e,
114
- direction: this.resize,
115
- threshold: this.resizeThreshold,
116
- step: this.resizeStep,
117
- bounds: this.moveBounds
118
- }), this._controlledOpen !== void 0 ? this._applyOpen(this._controlledOpen, !0, this.modal) : this.defaultOpen && this._applyOpen(!0, !0, this.modal);
112
+ if (this.resize !== "none") {
113
+ const t = this._resizeHandles(e);
114
+ if (t.length > 0)
115
+ for (const i of t)
116
+ new d(this, {
117
+ target: e,
118
+ direction: this._resizeDirectionForHandle(i),
119
+ handle: i,
120
+ origin: this._resizeOriginForHandle(i),
121
+ threshold: this.resizeThreshold,
122
+ step: this.resizeStep,
123
+ bounds: this.moveBounds,
124
+ onResizeStart: (s) => this._onResizeStart(s),
125
+ onResize: (s) => this._onResize(s),
126
+ onResizeEnd: (s) => this._onResizeEnd(s)
127
+ });
128
+ else
129
+ new d(this, {
130
+ target: e,
131
+ direction: this.resize,
132
+ origin: this.resizeOrigin,
133
+ threshold: this.resizeThreshold,
134
+ step: this.resizeStep,
135
+ bounds: this.moveBounds,
136
+ onResizeStart: (i) => this._onResizeStart(i),
137
+ onResize: (i) => this._onResize(i),
138
+ onResizeEnd: (i) => this._onResizeEnd(i)
139
+ });
140
+ }
141
+ this._controlledOpen !== void 0 ? this._applyOpen(this._controlledOpen, !0, this.modal) : this.defaultOpen && this._applyOpen(!0, !0, this.modal);
119
142
  }
120
143
  }
121
144
  updated(e) {
@@ -130,16 +153,49 @@ class r extends a {
130
153
  const e = this._$wired?.deref();
131
154
  e && (e.removeEventListener("close", this._onClose), e.removeEventListener("cancel", this._onCancel), e.removeEventListener("click", this._onBackdropClick), this._$wired = null, this._$opener = null);
132
155
  }
156
+ /** Hook for subclasses to respond when a resize gesture begins. */
157
+ _onResizeStart(e) {
158
+ }
159
+ /** Hook for subclasses to respond to each resize update during an active gesture. */
160
+ _onResize(e) {
161
+ }
162
+ /** Hook for subclasses to respond after a resize gesture has settled. */
163
+ _onResizeEnd(e) {
164
+ }
165
+ _resizeHandles(e) {
166
+ if (!this.resizeHandle)
167
+ return [];
168
+ try {
169
+ return [...e.querySelectorAll(this.resizeHandle)];
170
+ } catch {
171
+ return [];
172
+ }
173
+ }
174
+ _resizeDirectionForHandle(e) {
175
+ switch (e.getAttribute("data-rc-dialog-resize-axis")) {
176
+ case "x":
177
+ return "horizontal";
178
+ case "y":
179
+ return "vertical";
180
+ case "both":
181
+ return "both";
182
+ default:
183
+ return this.resize;
184
+ }
185
+ }
186
+ _resizeOriginForHandle(e) {
187
+ return e.getAttribute("data-rc-dialog-resize-origin") ?? this.resizeOrigin;
188
+ }
133
189
  /**
134
190
  * Opens or closes the inner `<dialog>` and returns `true` if state actually changed.
135
191
  *
136
- * @param open - Whether to open (`true`) or close (`false`).
137
- * @param silent - When `true`, suppresses the outgoing `rc-dialog-toggle` event.
138
- * @param modal - Whether to call `showModal()` (`true`) or `show()` (`false`).
192
+ * @param open - whether to open (`true`) or close (`false`)
193
+ * @param silent - when `true`, suppresses the outgoing `rc-dialog-toggle` event
194
+ * @param modal - whether to call `showModal()` (`true`) or `show()` (`false`)
139
195
  */
140
- _applyOpen(e, t, l = !0) {
196
+ _applyOpen(e, t, i = !0) {
141
197
  const s = this._$dialog;
142
- return s ? e ? s.open ? !1 : (this._$opener = document.activeElement, l ? s.showModal() : s.show(), this.requestUpdate("open"), !0) : s.open ? (this._suppressNextCloseToggle = t, s.close(), this.requestUpdate("open"), !0) : !1 : !1;
198
+ return s ? e ? s.open ? !1 : (this._$opener = document.activeElement, i ? s.showModal() : s.show(), this.requestUpdate("open"), !0) : s.open ? (this._suppressNextCloseToggle = t, s.close(), this.requestUpdate("open"), !0) : !1 : !1;
143
199
  }
144
200
  /** Dispatches `rc-dialog-toggle` with the current open state and return value. */
145
201
  _dispatchToggle(e) {
@@ -153,39 +209,45 @@ class r extends a {
153
209
  }
154
210
  }
155
211
  o([
156
- i({ type: Boolean, reflect: !0 })
157
- ], r.prototype, "movable", 2);
212
+ r({ type: Boolean, reflect: !0 })
213
+ ], n.prototype, "movable", 2);
214
+ o([
215
+ r({ type: String, attribute: "move-handle" })
216
+ ], n.prototype, "moveHandle", 2);
217
+ o([
218
+ r({ type: String, attribute: "move-bounds" })
219
+ ], n.prototype, "moveBounds", 2);
158
220
  o([
159
- i({ type: String, attribute: "move-handle" })
160
- ], r.prototype, "moveHandle", 2);
221
+ r({ type: Number, attribute: "move-step" })
222
+ ], n.prototype, "moveStep", 2);
161
223
  o([
162
- i({ type: String, attribute: "move-bounds" })
163
- ], r.prototype, "moveBounds", 2);
224
+ r({ type: String, reflect: !0 })
225
+ ], n.prototype, "resize", 2);
164
226
  o([
165
- i({ type: Number, attribute: "move-step" })
166
- ], r.prototype, "moveStep", 2);
227
+ r({ type: String, attribute: "resize-origin" })
228
+ ], n.prototype, "resizeOrigin", 2);
167
229
  o([
168
- i({ type: String, reflect: !0 })
169
- ], r.prototype, "resize", 2);
230
+ r({ type: String, attribute: "resize-handle" })
231
+ ], n.prototype, "resizeHandle", 2);
170
232
  o([
171
- i({ type: Number, attribute: "resize-threshold" })
172
- ], r.prototype, "resizeThreshold", 2);
233
+ r({ type: Number, attribute: "resize-threshold" })
234
+ ], n.prototype, "resizeThreshold", 2);
173
235
  o([
174
- i({ type: Number, attribute: "resize-step" })
175
- ], r.prototype, "resizeStep", 2);
236
+ r({ type: Number, attribute: "resize-step" })
237
+ ], n.prototype, "resizeStep", 2);
176
238
  o([
177
- i({ type: String, attribute: "closed-by", reflect: !0 })
178
- ], r.prototype, "closedBy", 2);
239
+ r({ type: String, attribute: "closed-by", reflect: !0 })
240
+ ], n.prototype, "closedBy", 2);
179
241
  o([
180
- i({ type: Boolean, attribute: "light-dismiss" })
181
- ], r.prototype, "lightDismiss", 2);
242
+ r({ type: Boolean, attribute: "light-dismiss" })
243
+ ], n.prototype, "lightDismiss", 2);
182
244
  o([
183
- i({ type: Boolean, attribute: "open", reflect: !0 })
184
- ], r.prototype, "open", 1);
245
+ r({ type: Boolean, attribute: "open", reflect: !0 })
246
+ ], n.prototype, "open", 1);
185
247
  o([
186
- i({ type: Boolean, attribute: "default-open" })
187
- ], r.prototype, "defaultOpen", 1);
248
+ r({ type: Boolean, attribute: "default-open" })
249
+ ], n.prototype, "defaultOpen", 1);
188
250
  export {
189
- r as R
251
+ n as R
190
252
  };
191
- //# sourceMappingURL=rc-dialog-Dpj3ERfv.js.map
253
+ //# sourceMappingURL=rc-dialog-D9jUBKJn.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rc-dialog-D9jUBKJn.js","sources":["../src/rc-dialog.ts"],"sourcesContent":["import { LitElement, nothing, type PropertyValues } from 'lit';\nimport { property } from 'lit/decorators.js';\n\nimport {\n DragController,\n NativeChildController,\n ResizeController,\n type ResizeDirection,\n type ResizeLifecycleDetail,\n type ResizeOrigin,\n warnMissingDirectChild,\n} from '@rcarls/rc-common';\n\n/** Detail shape for `rc-dialog-close` and `rc-dialog-request-close`. */\nexport interface RCDialogCloseEvent {\n returnValue: string;\n}\n\n/** Detail shape for `rc-dialog-toggle`. */\nexport interface RCDialogToggleEvent {\n open: boolean;\n returnValue: string;\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'rc-dialog': RCDialog;\n }\n\n interface HTMLElementEventMap {\n 'rc-dialog-open': CustomEvent<Record<string, never>>;\n 'rc-dialog-close': CustomEvent<RCDialogCloseEvent>;\n 'rc-dialog-request-close': CustomEvent<RCDialogCloseEvent>;\n 'rc-dialog-cancel': CustomEvent<Record<string, never>>;\n 'rc-dialog-toggle': CustomEvent<RCDialogToggleEvent>;\n }\n}\n\n/**\n * Draggable, resizable wrapper for a native <dialog>, following the WAI-ARIA Dialog Modal\n * pattern.\n *\n * @see {@link https://richardcarls.github.io/rc-webcomponents/components/rc-dialog rc-dialog docs}\n * @see {@link https://www.w3.org/WAI/ARIA/apg/patterns/dialog-modal/ WAI-ARIA Dialog Modal pattern}\n *\n * @slot - Place a `<dialog>` element with your content here.\n *\n * @fires rc-dialog-open - Fired when the dialog opens via `showModal()` or `show()`.\n * @fires rc-dialog-toggle - Fired when user/native interaction changes open state.\n * @fires rc-dialog-request-close - Fired before the dialog closes (cancellable).\n * @fires rc-dialog-cancel - Mirrors the inner `<dialog>` cancel event when the\n * close was not prevented. Backward-compatible alias for `rc-dialog-request-close`.\n * @fires rc-dialog-close - Mirrors the inner `<dialog>` close event.\n * `detail: { returnValue: string }`\n *\n * @attr open - Controlled open state. Reads the inner `<dialog>.open` value.\n * @attr default-open - Initial uncontrolled open state.\n * @attr movable - Allow the dialog to be moved by dragging.\n * @attr move-handle - CSS selector (within the inner `<dialog>`) for the drag handle element.\n * @attr move-bounds - Bounds constraint for movement: `viewport` or `parent`.\n * @attr move-step - Keyboard arrow-key step in px for moving.\n * @attr resize - Enable resizing, mirroring the CSS `resize` property values.\n * @attr resize-origin - Origin for resize edge hit-testing or explicit handles.\n * @attr resize-handle - CSS selector, scoped to the inner `<dialog>`, for one or more explicit\n * resize handles.\n * @attr resize-threshold - Edge hit-test thickness in px for resize detection.\n * @attr resize-step - Keyboard arrow-key step in px for resizing.\n * @attr closed-by - Proxied to the inner `<dialog closedby=\"...\">` attribute.\n * @attr light-dismiss - When present and the dialog is modal, a click on the backdrop area calls\n * `requestClose()`.\n *\n * @cssprop [--rc-dialog-scrim=color-mix(in srgb, CanvasText 32%, transparent)] - Modal backdrop color.\n *\n */\nexport class RCDialog extends LitElement {\n override createRenderRoot() {\n return this;\n }\n\n /**\n * Allow the dialog to be moved by dragging.\n *\n * Use `move-handle` to restrict dragging to a specific child\n * element (e.g. a titlebar).\n */\n @property({ type: Boolean, reflect: true })\n movable = false;\n\n /** CSS selector (within the inner `<dialog>`) for the drag handle element. */\n @property({ type: String, attribute: 'move-handle' })\n moveHandle = '';\n\n /** Bounds constraint for movement. */\n @property({ type: String, attribute: 'move-bounds' })\n moveBounds: 'viewport' | 'parent' = 'viewport';\n\n /** Keyboard arrow-key step in px for moving. */\n @property({ type: Number, attribute: 'move-step' })\n moveStep = 4;\n\n /** Enable resizing, mirroring the CSS `resize` property values. */\n @property({ type: String, reflect: true })\n resize: 'none' | 'both' | 'horizontal' | 'vertical' = 'none';\n\n /**\n * Origin for resize edge hit-testing or explicit handles.\n *\n * Empty preserves the historical free edge-detection behavior.\n */\n @property({ type: String, attribute: 'resize-origin' })\n resizeOrigin: ResizeOrigin = '';\n\n /**\n * CSS selector, scoped to the inner `<dialog>`, for one or more explicit\n * resize handles.\n *\n * Handles may override host behavior with:\n * - `data-rc-dialog-resize-axis=\"x|y|both\"`\n * - `data-rc-dialog-resize-origin=\"top|right|bottom|left|top-left|...\"`\n */\n @property({ type: String, attribute: 'resize-handle' })\n resizeHandle = '';\n\n /** Edge hit-test thickness in px for resize detection. */\n @property({ type: Number, attribute: 'resize-threshold' })\n resizeThreshold = 8;\n\n /** Keyboard arrow-key step in px for resizing. */\n @property({ type: Number, attribute: 'resize-step' })\n resizeStep = 4;\n\n /**\n * Proxied to the inner `<dialog closedby=\"...\">` attribute.\n *\n * Progressive enhancement, no-op in older browsers.\n *\n * - `'any'` — Escape OR backdrop click closes the dialog.\n * - `'closerequest'` — Escape only (browser default for modal dialogs).\n * - `'none'` — Only programmatic `close()` / `requestClose()`.\n * - `''` — Attribute absent; use `light-dismiss` for JS fallback.\n */\n @property({ type: String, attribute: 'closed-by', reflect: true })\n closedBy: 'any' | 'closerequest' | 'none' | '' = '';\n\n /**\n * When true and the dialog is modal, a click on the backdrop area calls\n * `requestClose()`.\n */\n @property({ type: Boolean, attribute: 'light-dismiss' })\n lightDismiss = false;\n\n /**\n * Whether to open as modal with controlled open. Default: `true`.\n */\n modal = true;\n\n /** The inner `<dialog>` element, resolved from the direct light-DOM child. */\n protected get _$dialog(): HTMLDialogElement | null {\n return this._dialogController.child;\n }\n\n private _controlledOpen: boolean | undefined = undefined;\n private _defaultOpen = false;\n protected readonly _dialogController = new NativeChildController<HTMLDialogElement>(this, {\n selector: ':scope > dialog',\n observe: true,\n onChange: ($dialog) => this._setupDialog($dialog),\n onMissing: () => {\n if (import.meta.env.DEV) {\n warnMissingDirectChild(this, {\n selector: ':scope > dialog',\n message:\n '[rc-dialog] No direct child <dialog> found. Place a native <dialog> inside <rc-dialog>.',\n });\n }\n },\n });\n\n // Tracks which <dialog> has its listeners wired; used by _teardownDialog to\n // remove listeners even after the element is removed from the DOM.\n protected _$wired: WeakRef<HTMLDialogElement> | null = null;\n protected _suppressNextCloseToggle = false;\n\n /** The element that had focus when the dialog was opened; restored on close. */\n protected _$opener: Element | null = null;\n\n /** Whether the inner `<dialog>` is currently open. Host writes update silently. */\n @property({ type: Boolean, attribute: 'open', reflect: true })\n get open(): boolean {\n return this._$dialog?.open ?? false;\n }\n\n set open(value: boolean | undefined) {\n const oldValue = this._controlledOpen;\n\n this._controlledOpen = value;\n\n if (value !== undefined) {\n this._applyOpen(value, true, this.modal);\n }\n\n this.requestUpdate('open', oldValue);\n }\n\n /** Initial uncontrolled open state. */\n @property({ type: Boolean, attribute: 'default-open' })\n get defaultOpen(): boolean {\n return this._defaultOpen;\n }\n\n set defaultOpen(value: boolean) {\n const oldValue = this._defaultOpen;\n\n this._defaultOpen = value;\n\n if (this._controlledOpen === undefined && value && this.isConnected) {\n this._applyOpen(true, true, this.modal);\n }\n\n this.requestUpdate('defaultOpen', oldValue);\n }\n\n /** The return value set when the dialog was closed. */\n get returnValue(): string {\n return this._$dialog?.returnValue ?? '';\n }\n\n /** Opens the inner `<dialog>` as a modal and fires `rc-dialog-open`. */\n showModal(): void {\n if (this._applyOpen(true, false, true)) {\n this.dispatchEvent(new CustomEvent('rc-dialog-open', { bubbles: true, composed: true }));\n this._dispatchToggle(true);\n }\n }\n\n /**\n * Opens the inner `<dialog>` (non-modal) and fires `rc-dialog-open`.\n */\n show(): void {\n if (this._applyOpen(true, false, false)) {\n this.dispatchEvent(new CustomEvent('rc-dialog-open', { bubbles: true, composed: true }));\n this._dispatchToggle(true);\n }\n }\n\n /** Closes the inner `<dialog>`, optionally setting a return value. */\n close(returnValue?: string): void {\n this._$dialog?.close(returnValue);\n }\n\n /**\n * Requests the inner `<dialog>` to close, firing a cancelable `cancel` event\n * first.\n */\n requestClose(returnValue?: string): void {\n const $dialog = this._$dialog;\n\n if (!$dialog) {\n return;\n }\n\n if ('requestClose' in $dialog && typeof $dialog.requestClose === 'function') {\n $dialog.requestClose(returnValue);\n } else {\n // Synthesize a cancelable cancel event; _onCancel fires rc-dialog-request-close.\n // If not prevented, _onCancel does not call $dlg.close() — we do it here.\n const ev = new Event('cancel', { cancelable: true, bubbles: false });\n const prevented = !$dialog.dispatchEvent(ev);\n\n if (!prevented) {\n $dialog.close(returnValue);\n }\n }\n }\n\n override render() {\n return nothing;\n }\n\n override firstUpdated() {\n this._dialogController.sync();\n }\n\n /** Wires event listeners, drag/resize controllers, and initial open state for the inner `<dialog>`. */\n protected _setupDialog($dialog: HTMLDialogElement | null = this._$dialog) {\n if (!$dialog) {\n this._teardownDialog();\n\n return;\n }\n\n if (this._$wired?.deref() === $dialog) {\n return;\n }\n\n this._teardownDialog();\n this._$wired = new WeakRef($dialog);\n\n if (import.meta.env.DEV) {\n const hasLabel =\n $dialog.hasAttribute('aria-labelledby') || $dialog.hasAttribute('aria-label');\n\n if (!hasLabel) {\n console.warn(\n '[rc-dialog] The inner <dialog> is missing aria-labelledby or ' +\n 'aria-label. Add one to satisfy the ARIA dialog pattern.',\n $dialog,\n );\n }\n\n if (\n $dialog.getAttribute('role') === 'alertdialog' &&\n !$dialog.hasAttribute('aria-describedby')\n ) {\n console.warn(\n '[rc-dialog] <dialog role=\"alertdialog\"> should have aria-describedby ' +\n 'pointing to the alert message text.',\n $dialog,\n );\n }\n\n if (!$dialog.querySelector('button:not([disabled])')) {\n console.warn(\n '[rc-dialog] No enabled <button> found inside <dialog>. APG recommends ' +\n 'including a visible close button in the tab sequence.',\n $dialog,\n );\n }\n }\n\n $dialog.addEventListener('close', this._onClose);\n $dialog.addEventListener('cancel', this._onCancel);\n\n if (this.lightDismiss && 'closedBy' in HTMLDialogElement.prototype) {\n $dialog.setAttribute('closedby', 'any');\n } else if (this.lightDismiss) {\n $dialog.addEventListener('click', this._onBackdropClick);\n } else {\n if (this.closedBy) {\n $dialog.setAttribute('closedby', this.closedBy);\n }\n }\n\n if (this.movable || this.moveHandle) {\n const $handle = this.moveHandle\n ? ($dialog.querySelector<Element>(this.moveHandle) ?? $dialog)\n : $dialog;\n\n new DragController(this, {\n target: $dialog,\n handle: $handle,\n bounds: this.moveBounds,\n step: this.moveStep,\n });\n }\n\n if (this.resize !== 'none') {\n const $handles = this._resizeHandles($dialog);\n\n if ($handles.length > 0) {\n for (const $handle of $handles) {\n // TODO: add a separate resize-bounds attribute; moveBounds is a proxy for now.\n new ResizeController(this, {\n target: $dialog,\n direction: this._resizeDirectionForHandle($handle),\n handle: $handle,\n origin: this._resizeOriginForHandle($handle),\n threshold: this.resizeThreshold,\n step: this.resizeStep,\n bounds: this.moveBounds,\n onResizeStart: (detail) => this._onResizeStart(detail),\n onResize: (detail) => this._onResize(detail),\n onResizeEnd: (detail) => this._onResizeEnd(detail),\n });\n }\n } else {\n // TODO: add a separate resize-bounds attribute; moveBounds is a proxy for now.\n new ResizeController(this, {\n target: $dialog,\n direction: this.resize,\n origin: this.resizeOrigin,\n threshold: this.resizeThreshold,\n step: this.resizeStep,\n bounds: this.moveBounds,\n onResizeStart: (detail) => this._onResizeStart(detail),\n onResize: (detail) => this._onResize(detail),\n onResizeEnd: (detail) => this._onResizeEnd(detail),\n });\n }\n }\n\n if (this._controlledOpen !== undefined) {\n this._applyOpen(this._controlledOpen, true, this.modal);\n } else if (this.defaultOpen) {\n this._applyOpen(true, true, this.modal);\n }\n }\n\n override updated(changed: PropertyValues) {\n const $dialog = this._$dialog;\n\n if (!$dialog) {\n return;\n }\n\n if (changed.has('closedBy')) {\n if (this.closedBy) {\n $dialog.setAttribute('closedby', this.closedBy);\n } else {\n $dialog.removeAttribute('closedby');\n }\n }\n\n if (changed.has('lightDismiss')) {\n if (this.lightDismiss && 'closedBy' in HTMLDialogElement.prototype) {\n // Native support available — delegate to closedby=\"any\" instead of JS handler.\n $dialog.setAttribute('closedby', 'any');\n $dialog.removeEventListener('click', this._onBackdropClick);\n } else if (this.lightDismiss) {\n $dialog.addEventListener('click', this._onBackdropClick);\n } else {\n $dialog.removeEventListener('click', this._onBackdropClick);\n\n if (this.closedBy) {\n $dialog.setAttribute('closedby', this.closedBy);\n } else {\n $dialog.removeAttribute('closedby');\n }\n }\n }\n }\n\n override disconnectedCallback() {\n this._teardownDialog();\n\n super.disconnectedCallback();\n }\n\n /** Removes all event listeners attached to the inner `<dialog>` and clears cached state. */\n protected _teardownDialog(): void {\n const $dialog = this._$wired?.deref();\n\n if (!$dialog) {\n return;\n }\n\n $dialog.removeEventListener('close', this._onClose);\n $dialog.removeEventListener('cancel', this._onCancel);\n $dialog.removeEventListener('click', this._onBackdropClick);\n\n this._$wired = null;\n this._$opener = null;\n }\n\n protected _onClose = () => {\n // Restore focus to the element that triggered the open, per APG focus management.\n if (this._$opener instanceof HTMLElement) {\n if (this._$opener.isConnected) {\n this._$opener.focus();\n } else {\n // Opener was removed from the DOM while the dialog was open; fall back\n // to body so focus is not left stranded.\n document.body.focus();\n }\n }\n\n this._$opener = null;\n\n this.dispatchEvent(\n new CustomEvent('rc-dialog-close', {\n bubbles: true,\n composed: true,\n detail: { returnValue: this.returnValue },\n }),\n );\n\n if (!this._suppressNextCloseToggle) {\n this._dispatchToggle(false);\n }\n\n this._suppressNextCloseToggle = false;\n this.requestUpdate('open');\n };\n\n /**\n * Intercepts the native `cancel` event.\n */\n protected _onCancel = (e: Event) => {\n const requestCloseEvent = new CustomEvent('rc-dialog-request-close', {\n bubbles: true,\n composed: true,\n cancelable: true,\n detail: { returnValue: this.returnValue },\n });\n const prevented = !this.dispatchEvent(requestCloseEvent);\n\n if (prevented) {\n e.preventDefault();\n } else {\n this.dispatchEvent(new CustomEvent('rc-dialog-cancel', { bubbles: true, composed: true }));\n }\n };\n\n /**\n * Detects backdrop clicks.\n */\n protected _onBackdropClick = (e: MouseEvent) => {\n if (e.target === this._$dialog) {\n this.requestClose();\n }\n };\n\n /** Hook for subclasses to respond when a resize gesture begins. */\n protected _onResizeStart(_detail: ResizeLifecycleDetail): void {}\n\n /** Hook for subclasses to respond to each resize update during an active gesture. */\n protected _onResize(_detail: ResizeLifecycleDetail): void {}\n\n /** Hook for subclasses to respond after a resize gesture has settled. */\n protected _onResizeEnd(_detail: ResizeLifecycleDetail): void {}\n\n protected _resizeHandles($dialog: HTMLDialogElement): Element[] {\n if (!this.resizeHandle) {\n return [];\n }\n\n try {\n return [...$dialog.querySelectorAll(this.resizeHandle)];\n } catch {\n if (import.meta.env.DEV) {\n console.warn('[rc-dialog] Invalid resize-handle selector.', this.resizeHandle);\n }\n\n return [];\n }\n }\n\n protected _resizeDirectionForHandle($handle: Element): ResizeDirection {\n const axis = $handle.getAttribute('data-rc-dialog-resize-axis');\n\n switch (axis) {\n case 'x':\n return 'horizontal';\n case 'y':\n return 'vertical';\n case 'both':\n return 'both';\n default:\n return this.resize;\n }\n }\n\n protected _resizeOriginForHandle($handle: Element): ResizeOrigin {\n return (\n ($handle.getAttribute('data-rc-dialog-resize-origin') as ResizeOrigin | null) ??\n this.resizeOrigin\n );\n }\n\n /**\n * Opens or closes the inner `<dialog>` and returns `true` if state actually changed.\n *\n * @param open - whether to open (`true`) or close (`false`)\n * @param silent - when `true`, suppresses the outgoing `rc-dialog-toggle` event\n * @param modal - whether to call `showModal()` (`true`) or `show()` (`false`)\n */\n protected _applyOpen(open: boolean, silent: boolean, modal = true): boolean {\n const $dialog = this._$dialog;\n\n if (!$dialog) {\n return false;\n }\n\n if (open) {\n if ($dialog.open) {\n return false;\n }\n\n // Capture focus owner before the dialog steals it, so we can restore on close.\n this._$opener = document.activeElement;\n modal ? $dialog.showModal() : $dialog.show();\n this.requestUpdate('open');\n\n return true;\n }\n\n if (!$dialog.open) {\n return false;\n }\n\n this._suppressNextCloseToggle = silent;\n $dialog.close();\n this.requestUpdate('open');\n\n return true;\n }\n\n /** Dispatches `rc-dialog-toggle` with the current open state and return value. */\n protected _dispatchToggle(open: boolean): void {\n this.dispatchEvent(\n new CustomEvent('rc-dialog-toggle', {\n bubbles: true,\n composed: true,\n detail: { open, returnValue: this.returnValue },\n }),\n );\n }\n}\n\nexport default RCDialog;\n"],"names":["RCDialog","LitElement","NativeChildController","$dialog","requestCloseEvent","value","oldValue","returnValue","ev","nothing","$handle","DragController","$handles","ResizeController","detail","changed","_detail","open","silent","modal","__decorateClass","property"],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import { R as e } from "./rc-dialog-Dpj3ERfv.js";
1
+ import { R as e } from "./rc-dialog-D9jUBKJn.js";
2
2
  customElements.get("rc-dialog") || customElements.define("rc-dialog", e);
3
3
  export {
4
4
  e as RCDialog
package/dist/rc-dialog.js CHANGED
@@ -1,4 +1,4 @@
1
- import { R as r } from "./rc-dialog-Dpj3ERfv.js";
1
+ import { R as r } from "./rc-dialog-D9jUBKJn.js";
2
2
  export {
3
3
  r as RCDialog
4
4
  };
@@ -1,4 +1,5 @@
1
1
  import { LitElement, PropertyValues } from 'lit';
2
+ import { NativeChildController, ResizeDirection, ResizeLifecycleDetail, ResizeOrigin } from '@rcarls/rc-common';
2
3
  /** Detail shape for `rc-dialog-close` and `rc-dialog-request-close`. */
3
4
  export interface RCDialogCloseEvent {
4
5
  returnValue: string;
@@ -37,6 +38,24 @@ declare global {
37
38
  * @fires rc-dialog-close - Mirrors the inner `<dialog>` close event.
38
39
  * `detail: { returnValue: string }`
39
40
  *
41
+ * @attr open - Controlled open state. Reads the inner `<dialog>.open` value.
42
+ * @attr default-open - Initial uncontrolled open state.
43
+ * @attr movable - Allow the dialog to be moved by dragging.
44
+ * @attr move-handle - CSS selector (within the inner `<dialog>`) for the drag handle element.
45
+ * @attr move-bounds - Bounds constraint for movement: `viewport` or `parent`.
46
+ * @attr move-step - Keyboard arrow-key step in px for moving.
47
+ * @attr resize - Enable resizing, mirroring the CSS `resize` property values.
48
+ * @attr resize-origin - Origin for resize edge hit-testing or explicit handles.
49
+ * @attr resize-handle - CSS selector, scoped to the inner `<dialog>`, for one or more explicit
50
+ * resize handles.
51
+ * @attr resize-threshold - Edge hit-test thickness in px for resize detection.
52
+ * @attr resize-step - Keyboard arrow-key step in px for resizing.
53
+ * @attr closed-by - Proxied to the inner `<dialog closedby="...">` attribute.
54
+ * @attr light-dismiss - When present and the dialog is modal, a click on the backdrop area calls
55
+ * `requestClose()`.
56
+ *
57
+ * @cssprop [--rc-dialog-scrim=color-mix(in srgb, CanvasText 32%, transparent)] - Modal backdrop color.
58
+ *
40
59
  */
41
60
  export declare class RCDialog extends LitElement {
42
61
  createRenderRoot(): this;
@@ -55,6 +74,21 @@ export declare class RCDialog extends LitElement {
55
74
  moveStep: number;
56
75
  /** Enable resizing, mirroring the CSS `resize` property values. */
57
76
  resize: 'none' | 'both' | 'horizontal' | 'vertical';
77
+ /**
78
+ * Origin for resize edge hit-testing or explicit handles.
79
+ *
80
+ * Empty preserves the historical free edge-detection behavior.
81
+ */
82
+ resizeOrigin: ResizeOrigin;
83
+ /**
84
+ * CSS selector, scoped to the inner `<dialog>`, for one or more explicit
85
+ * resize handles.
86
+ *
87
+ * Handles may override host behavior with:
88
+ * - `data-rc-dialog-resize-axis="x|y|both"`
89
+ * - `data-rc-dialog-resize-origin="top|right|bottom|left|top-left|..."`
90
+ */
91
+ resizeHandle: string;
58
92
  /** Edge hit-test thickness in px for resize detection. */
59
93
  resizeThreshold: number;
60
94
  /** Keyboard arrow-key step in px for resizing. */
@@ -83,9 +117,9 @@ export declare class RCDialog extends LitElement {
83
117
  protected get _$dialog(): HTMLDialogElement | null;
84
118
  private _controlledOpen;
85
119
  private _defaultOpen;
86
- private readonly _dialogController;
87
- private _$wired;
88
- private _suppressNextCloseToggle;
120
+ protected readonly _dialogController: NativeChildController<HTMLDialogElement>;
121
+ protected _$wired: WeakRef<HTMLDialogElement> | null;
122
+ protected _suppressNextCloseToggle: boolean;
89
123
  /** The element that had focus when the dialog was opened; restored on close. */
90
124
  protected _$opener: Element | null;
91
125
  /** Whether the inner `<dialog>` is currently open. Host writes update silently. */
@@ -126,12 +160,21 @@ export declare class RCDialog extends LitElement {
126
160
  * Detects backdrop clicks.
127
161
  */
128
162
  protected _onBackdropClick: (e: MouseEvent) => void;
163
+ /** Hook for subclasses to respond when a resize gesture begins. */
164
+ protected _onResizeStart(_detail: ResizeLifecycleDetail): void;
165
+ /** Hook for subclasses to respond to each resize update during an active gesture. */
166
+ protected _onResize(_detail: ResizeLifecycleDetail): void;
167
+ /** Hook for subclasses to respond after a resize gesture has settled. */
168
+ protected _onResizeEnd(_detail: ResizeLifecycleDetail): void;
169
+ protected _resizeHandles($dialog: HTMLDialogElement): Element[];
170
+ protected _resizeDirectionForHandle($handle: Element): ResizeDirection;
171
+ protected _resizeOriginForHandle($handle: Element): ResizeOrigin;
129
172
  /**
130
173
  * Opens or closes the inner `<dialog>` and returns `true` if state actually changed.
131
174
  *
132
- * @param open - Whether to open (`true`) or close (`false`).
133
- * @param silent - When `true`, suppresses the outgoing `rc-dialog-toggle` event.
134
- * @param modal - Whether to call `showModal()` (`true`) or `show()` (`false`).
175
+ * @param open - whether to open (`true`) or close (`false`)
176
+ * @param silent - when `true`, suppresses the outgoing `rc-dialog-toggle` event
177
+ * @param modal - whether to call `showModal()` (`true`) or `show()` (`false`)
135
178
  */
136
179
  protected _applyOpen(open: boolean, silent: boolean, modal?: boolean): boolean;
137
180
  /** Dispatches `rc-dialog-toggle` with the current open state and return value. */
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "publishConfig": {
4
4
  "access": "public"
5
5
  },
6
- "version": "0.3.2",
6
+ "version": "0.4.0",
7
7
  "description": "Draggable, resizable wrapper for a native <dialog>.",
8
8
  "repository": {
9
9
  "type": "git",
@@ -1 +0,0 @@
1
- {"version":3,"file":"rc-dialog-Dpj3ERfv.js","sources":["../src/rc-dialog.ts"],"sourcesContent":["import { LitElement, nothing, type PropertyValues } from 'lit';\nimport { property } from 'lit/decorators.js';\nimport {\n DragController,\n NativeChildController,\n ResizeController,\n warnMissingDirectChild,\n} from '@rcarls/rc-common';\n\n/** Detail shape for `rc-dialog-close` and `rc-dialog-request-close`. */\nexport interface RCDialogCloseEvent {\n returnValue: string;\n}\n\n/** Detail shape for `rc-dialog-toggle`. */\nexport interface RCDialogToggleEvent {\n open: boolean;\n returnValue: string;\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'rc-dialog': RCDialog;\n }\n\n interface HTMLElementEventMap {\n 'rc-dialog-open': CustomEvent<Record<string, never>>;\n 'rc-dialog-close': CustomEvent<RCDialogCloseEvent>;\n 'rc-dialog-request-close': CustomEvent<RCDialogCloseEvent>;\n 'rc-dialog-cancel': CustomEvent<Record<string, never>>;\n 'rc-dialog-toggle': CustomEvent<RCDialogToggleEvent>;\n }\n}\n\n/**\n * Draggable, resizable wrapper for a native <dialog>, following the WAI-ARIA Dialog Modal\n * pattern.\n *\n * @see {@link https://richardcarls.github.io/rc-webcomponents/components/rc-dialog rc-dialog docs}\n * @see {@link https://www.w3.org/WAI/ARIA/apg/patterns/dialog-modal/ WAI-ARIA Dialog Modal pattern}\n *\n * @slot - Place a `<dialog>` element with your content here.\n *\n * @fires rc-dialog-open - Fired when the dialog opens via `showModal()` or `show()`.\n * @fires rc-dialog-toggle - Fired when user/native interaction changes open state.\n * @fires rc-dialog-request-close - Fired before the dialog closes (cancellable).\n * @fires rc-dialog-cancel - Mirrors the inner `<dialog>` cancel event when the\n * close was not prevented. Backward-compatible alias for `rc-dialog-request-close`.\n * @fires rc-dialog-close - Mirrors the inner `<dialog>` close event.\n * `detail: { returnValue: string }`\n *\n */\nexport class RCDialog extends LitElement {\n override createRenderRoot() {\n return this;\n }\n\n /**\n * Allow the dialog to be moved by dragging.\n *\n * Use `move-handle` to restrict dragging to a specific child\n * element (e.g. a titlebar).\n */\n @property({ type: Boolean, reflect: true })\n movable = false;\n\n /** CSS selector (within the inner `<dialog>`) for the drag handle element. */\n @property({ type: String, attribute: 'move-handle' })\n moveHandle = '';\n\n /** Bounds constraint for movement. */\n @property({ type: String, attribute: 'move-bounds' })\n moveBounds: 'viewport' | 'parent' = 'viewport';\n\n /** Keyboard arrow-key step in px for moving. */\n @property({ type: Number, attribute: 'move-step' })\n moveStep = 4;\n\n /** Enable resizing, mirroring the CSS `resize` property values. */\n @property({ type: String, reflect: true })\n resize: 'none' | 'both' | 'horizontal' | 'vertical' = 'none';\n\n /** Edge hit-test thickness in px for resize detection. */\n @property({ type: Number, attribute: 'resize-threshold' })\n resizeThreshold = 8;\n\n /** Keyboard arrow-key step in px for resizing. */\n @property({ type: Number, attribute: 'resize-step' })\n resizeStep = 4;\n\n /**\n * Proxied to the inner `<dialog closedby=\"...\">` attribute.\n *\n * Progressive enhancement, no-op in older browsers.\n *\n * - `'any'` — Escape OR backdrop click closes the dialog.\n * - `'closerequest'` — Escape only (browser default for modal dialogs).\n * - `'none'` — Only programmatic `close()` / `requestClose()`.\n * - `''` — Attribute absent; use `light-dismiss` for JS fallback.\n */\n @property({ type: String, attribute: 'closed-by', reflect: true })\n closedBy: 'any' | 'closerequest' | 'none' | '' = '';\n\n /**\n * When true and the dialog is modal, a click on the backdrop area calls\n * `requestClose()`.\n */\n @property({ type: Boolean, attribute: 'light-dismiss' })\n lightDismiss = false;\n\n /**\n * Whether to open as modal with controlled open. Default: `true`.\n */\n modal = true;\n\n /** The inner `<dialog>` element, resolved from the direct light-DOM child. */\n protected get _$dialog(): HTMLDialogElement | null {\n return this._dialogController.child;\n }\n\n private _controlledOpen: boolean | undefined = undefined;\n private _defaultOpen = false;\n private readonly _dialogController = new NativeChildController<HTMLDialogElement>(this, {\n selector: ':scope > dialog',\n observe: true,\n onChange: ($dialog) => this._setupDialog($dialog),\n onMissing: () => {\n if (import.meta.env.DEV) {\n warnMissingDirectChild(this, {\n selector: ':scope > dialog',\n message:\n '[rc-dialog] No direct child <dialog> found. Place a native <dialog> inside <rc-dialog>.',\n });\n }\n },\n });\n // Tracks which <dialog> has its listeners wired; used by _teardownDialog to\n // remove listeners even after the element is removed from the DOM.\n private _$wired: WeakRef<HTMLDialogElement> | null = null;\n private _suppressNextCloseToggle = false;\n\n /** The element that had focus when the dialog was opened; restored on close. */\n protected _$opener: Element | null = null;\n\n /** Whether the inner `<dialog>` is currently open. Host writes update silently. */\n @property({ type: Boolean, attribute: 'open', reflect: true })\n get open(): boolean {\n return this._$dialog?.open ?? false;\n }\n\n set open(value: boolean | undefined) {\n const oldValue = this._controlledOpen;\n\n this._controlledOpen = value;\n\n if (value !== undefined) {\n this._applyOpen(value, true, this.modal);\n }\n\n this.requestUpdate('open', oldValue);\n }\n\n /** Initial uncontrolled open state. */\n @property({ type: Boolean, attribute: 'default-open' })\n get defaultOpen(): boolean {\n return this._defaultOpen;\n }\n\n set defaultOpen(value: boolean) {\n const oldValue = this._defaultOpen;\n\n this._defaultOpen = value;\n\n if (this._controlledOpen === undefined && value && this.isConnected) {\n this._applyOpen(true, true, this.modal);\n }\n\n this.requestUpdate('defaultOpen', oldValue);\n }\n\n /** The return value set when the dialog was closed. */\n get returnValue(): string {\n return this._$dialog?.returnValue ?? '';\n }\n\n /** Opens the inner `<dialog>` as a modal and fires `rc-dialog-open`. */\n showModal(): void {\n if (this._applyOpen(true, false, true)) {\n this.dispatchEvent(new CustomEvent('rc-dialog-open', { bubbles: true, composed: true }));\n this._dispatchToggle(true);\n }\n }\n\n /**\n * Opens the inner `<dialog>` (non-modal) and fires `rc-dialog-open`.\n */\n show(): void {\n if (this._applyOpen(true, false, false)) {\n this.dispatchEvent(new CustomEvent('rc-dialog-open', { bubbles: true, composed: true }));\n this._dispatchToggle(true);\n }\n }\n\n /** Closes the inner `<dialog>`, optionally setting a return value. */\n close(returnValue?: string): void {\n this._$dialog?.close(returnValue);\n }\n\n /**\n * Requests the inner `<dialog>` to close, firing a cancelable `cancel` event\n * first.\n */\n requestClose(returnValue?: string): void {\n const $dialog = this._$dialog;\n\n if (!$dialog) {\n return;\n }\n\n if ('requestClose' in $dialog && typeof $dialog.requestClose === 'function') {\n $dialog.requestClose(returnValue);\n } else {\n // Synthesize a cancelable cancel event; _onCancel fires rc-dialog-request-close.\n // If not prevented, _onCancel does not call $dlg.close() — we do it here.\n const ev = new Event('cancel', { cancelable: true, bubbles: false });\n const prevented = !$dialog.dispatchEvent(ev);\n\n if (!prevented) {\n $dialog.close(returnValue);\n }\n }\n }\n\n override render() {\n return nothing;\n }\n\n override firstUpdated() {\n this._dialogController.sync();\n }\n\n /** Wires event listeners, drag/resize controllers, and initial open state for the inner `<dialog>`. */\n protected _setupDialog($dialog: HTMLDialogElement | null = this._$dialog) {\n if (!$dialog) {\n this._teardownDialog();\n return;\n }\n\n if (this._$wired?.deref() === $dialog) {\n return;\n }\n\n this._teardownDialog();\n this._$wired = new WeakRef($dialog);\n\n if (import.meta.env.DEV) {\n const hasLabel =\n $dialog.hasAttribute('aria-labelledby') || $dialog.hasAttribute('aria-label');\n\n if (!hasLabel) {\n console.warn(\n '[rc-dialog] The inner <dialog> is missing aria-labelledby or ' +\n 'aria-label. Add one to satisfy the ARIA dialog pattern.',\n $dialog,\n );\n }\n\n if (\n $dialog.getAttribute('role') === 'alertdialog' &&\n !$dialog.hasAttribute('aria-describedby')\n ) {\n console.warn(\n '[rc-dialog] <dialog role=\"alertdialog\"> should have aria-describedby ' +\n 'pointing to the alert message text.',\n $dialog,\n );\n }\n\n if (!$dialog.querySelector('button:not([disabled])')) {\n console.warn(\n '[rc-dialog] No enabled <button> found inside <dialog>. APG recommends ' +\n 'including a visible close button in the tab sequence.',\n $dialog,\n );\n }\n }\n\n $dialog.addEventListener('close', this._onClose);\n $dialog.addEventListener('cancel', this._onCancel);\n\n if (this.lightDismiss && 'closedBy' in HTMLDialogElement.prototype) {\n $dialog.setAttribute('closedby', 'any');\n } else if (this.lightDismiss) {\n $dialog.addEventListener('click', this._onBackdropClick);\n } else {\n if (this.closedBy) {\n $dialog.setAttribute('closedby', this.closedBy);\n }\n }\n\n if (this.movable || this.moveHandle) {\n const $handle = this.moveHandle\n ? ($dialog.querySelector<Element>(this.moveHandle) ?? $dialog)\n : $dialog;\n\n new DragController(this, {\n target: $dialog,\n handle: $handle,\n bounds: this.moveBounds,\n step: this.moveStep,\n });\n }\n\n if (this.resize !== 'none') {\n // TODO: add a separate resize-bounds attribute; moveBounds is a proxy for now.\n new ResizeController(this, {\n target: $dialog,\n direction: this.resize,\n threshold: this.resizeThreshold,\n step: this.resizeStep,\n bounds: this.moveBounds,\n });\n }\n\n if (this._controlledOpen !== undefined) {\n this._applyOpen(this._controlledOpen, true, this.modal);\n } else if (this.defaultOpen) {\n this._applyOpen(true, true, this.modal);\n }\n }\n\n override updated(changed: PropertyValues) {\n const $dialog = this._$dialog;\n\n if (!$dialog) {\n return;\n }\n\n if (changed.has('closedBy')) {\n if (this.closedBy) {\n $dialog.setAttribute('closedby', this.closedBy);\n } else {\n $dialog.removeAttribute('closedby');\n }\n }\n\n if (changed.has('lightDismiss')) {\n if (this.lightDismiss && 'closedBy' in HTMLDialogElement.prototype) {\n // Native support available — delegate to closedby=\"any\" instead of JS handler.\n $dialog.setAttribute('closedby', 'any');\n $dialog.removeEventListener('click', this._onBackdropClick);\n } else if (this.lightDismiss) {\n $dialog.addEventListener('click', this._onBackdropClick);\n } else {\n $dialog.removeEventListener('click', this._onBackdropClick);\n\n if (this.closedBy) {\n $dialog.setAttribute('closedby', this.closedBy);\n } else {\n $dialog.removeAttribute('closedby');\n }\n }\n }\n }\n\n override disconnectedCallback() {\n this._teardownDialog();\n\n super.disconnectedCallback();\n }\n\n /** Removes all event listeners attached to the inner `<dialog>` and clears cached state. */\n protected _teardownDialog(): void {\n const $dialog = this._$wired?.deref();\n\n if (!$dialog) {\n return;\n }\n\n $dialog.removeEventListener('close', this._onClose);\n $dialog.removeEventListener('cancel', this._onCancel);\n $dialog.removeEventListener('click', this._onBackdropClick);\n\n this._$wired = null;\n this._$opener = null;\n }\n\n protected _onClose = () => {\n // Restore focus to the element that triggered the open, per APG focus management.\n if (this._$opener instanceof HTMLElement) {\n if (this._$opener.isConnected) {\n this._$opener.focus();\n } else {\n // Opener was removed from the DOM while the dialog was open; fall back\n // to body so focus is not left stranded.\n document.body.focus();\n }\n }\n\n this._$opener = null;\n\n this.dispatchEvent(\n new CustomEvent('rc-dialog-close', {\n bubbles: true,\n composed: true,\n detail: { returnValue: this.returnValue },\n }),\n );\n\n if (!this._suppressNextCloseToggle) {\n this._dispatchToggle(false);\n }\n\n this._suppressNextCloseToggle = false;\n this.requestUpdate('open');\n };\n\n /**\n * Intercepts the native `cancel` event.\n */\n protected _onCancel = (e: Event) => {\n const requestCloseEvent = new CustomEvent('rc-dialog-request-close', {\n bubbles: true,\n composed: true,\n cancelable: true,\n detail: { returnValue: this.returnValue },\n });\n const prevented = !this.dispatchEvent(requestCloseEvent);\n\n if (prevented) {\n e.preventDefault();\n } else {\n this.dispatchEvent(new CustomEvent('rc-dialog-cancel', { bubbles: true, composed: true }));\n }\n };\n\n /**\n * Detects backdrop clicks.\n */\n protected _onBackdropClick = (e: MouseEvent) => {\n if (e.target === this._$dialog) {\n this.requestClose();\n }\n };\n\n /**\n * Opens or closes the inner `<dialog>` and returns `true` if state actually changed.\n *\n * @param open - Whether to open (`true`) or close (`false`).\n * @param silent - When `true`, suppresses the outgoing `rc-dialog-toggle` event.\n * @param modal - Whether to call `showModal()` (`true`) or `show()` (`false`).\n */\n protected _applyOpen(open: boolean, silent: boolean, modal = true): boolean {\n const $dialog = this._$dialog;\n\n if (!$dialog) {\n return false;\n }\n\n if (open) {\n if ($dialog.open) {\n return false;\n }\n\n // Capture focus owner before the dialog steals it, so we can restore on close.\n this._$opener = document.activeElement;\n modal ? $dialog.showModal() : $dialog.show();\n this.requestUpdate('open');\n\n return true;\n }\n\n if (!$dialog.open) {\n return false;\n }\n\n this._suppressNextCloseToggle = silent;\n $dialog.close();\n this.requestUpdate('open');\n\n return true;\n }\n\n /** Dispatches `rc-dialog-toggle` with the current open state and return value. */\n protected _dispatchToggle(open: boolean): void {\n this.dispatchEvent(\n new CustomEvent('rc-dialog-toggle', {\n bubbles: true,\n composed: true,\n detail: { open, returnValue: this.returnValue },\n }),\n );\n }\n}\n\nexport default RCDialog;\n"],"names":["RCDialog","LitElement","NativeChildController","$dialog","requestCloseEvent","value","oldValue","returnValue","ev","nothing","$handle","DragController","ResizeController","changed","open","silent","modal","__decorateClass","property"],"mappings":"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"}