@rcarls/rc-dialog 0.2.0 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,8 +1,8 @@
1
1
  # `@rcarls/rc-dialog`
2
2
 
3
- A WAI-ARIA compliant web component that enhances a consumer-provided `<dialog>` element with drag, resize, cancelable close events, and light-dismiss. Built with [Lit 3](https://lit.dev).
3
+ Draggable, resizable wrapper for a native `<dialog>`, following the [WAI-ARIA Dialog Modal pattern](https://www.w3.org/WAI/ARIA/apg/patterns/dialog-modal/).
4
4
 
5
- The component is a **headless wrapper** — it injects no HTML of its own. Your `<dialog>` stays in the document's light DOM with full CSS and assistive-technology access.
5
+ Docs: [https://richardcarls.github.io/rc-webcomponents/components/rc-dialog](https://richardcarls.github.io/rc-webcomponents/components/rc-dialog).
6
6
 
7
7
  ---
8
8
 
@@ -45,6 +45,9 @@ Place a `<dialog>` element directly inside `<rc-dialog>`. The inner `<dialog>` m
45
45
 
46
46
  | Property | Attribute | Type | Default | Description |
47
47
  |---|---|---|---|---|
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. |
49
+ | `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. |
48
51
  | `movable` | `movable` | `boolean` | `false` | Enable drag-to-move. Named `movable` (not `draggable`) to avoid colliding with the HTML `draggable` attribute. |
49
52
  | `moveHandle` | `move-handle` | `string` | `''` | CSS selector for the drag handle within the inner `<dialog>` (e.g. `'.titlebar'`). Defaults to the whole dialog. |
50
53
  | `moveBounds` | `move-bounds` | `'viewport' \| 'parent'` | `'viewport'` | Constrains drag within the viewport or the nearest positioned ancestor. |
@@ -78,6 +81,8 @@ returnValue: string // The return value set when the dialog last closed.
78
81
 
79
82
  | Event | Cancelable | Detail | Description |
80
83
  |---|---|---|---|
84
+ | `rc-dialog-open` | No | — | Fired when the dialog opens via `showModal()` or `show()`. |
85
+ | `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). |
81
86
  | `rc-dialog-request-close` | **Yes** | `{ returnValue: string }` | Fired before close (Escape, backdrop click, or `requestClose()`). Call `preventDefault()` to block. |
82
87
  | `rc-dialog-cancel` | No | — | Fired after `rc-dialog-request-close` when the close was not prevented. Backward-compatible alias. |
83
88
  | `rc-dialog-close` | No | `{ returnValue: string }` | Fired after the dialog has closed. |
@@ -223,7 +228,7 @@ Use `role="alertdialog"` with `aria-describedby` pointing to the message text. A
223
228
  `<rc-dialog>` delegates entirely to the native `<dialog>` element:
224
229
 
225
230
  - **Focus trapping** — built into `showModal()` (Tab/Shift+Tab stays inside the dialog).
226
- - **Focus restoration** — the browser returns focus to the triggering element on close.
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`.
227
232
  - **Escape to close** — native behaviour; routes through `rc-dialog-request-close` so guards still apply.
228
233
  - **`aria-modal`** — `showModal()` implies `aria-modal="true"` without an explicit attribute.
229
234
 
@@ -46,7 +46,7 @@
46
46
  "declarations": [
47
47
  {
48
48
  "kind": "class",
49
- "description": "Enhances a consumer-provided `<dialog>` child with drag, resize, and\naccessible event forwarding. Renders nothing itself — the `<dialog>` element\nremains in the document's light DOM for full CSS and AT access.",
49
+ "description": "Draggable, resizable wrapper for a native <dialog>, following the WAI-ARIA Dialog Modal\npattern.",
50
50
  "name": "RCDialog",
51
51
  "slots": [
52
52
  {
@@ -62,7 +62,7 @@
62
62
  "text": "boolean"
63
63
  },
64
64
  "default": "false",
65
- "description": "Allow the dialog to be moved by dragging. Use `move-handle` to restrict\ndragging to a specific child element (e.g. a titlebar).\nNamed `movable` — not `draggable` — to avoid colliding with the\nbuilt-in HTML Drag and Drop `draggable` global attribute.",
65
+ "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).",
66
66
  "attribute": "movable",
67
67
  "reflects": true
68
68
  },
@@ -134,7 +134,7 @@
134
134
  "text": "'any' | 'closerequest' | 'none' | ''"
135
135
  },
136
136
  "default": "''",
137
- "description": "Proxied to the inner `<dialog closedby=\"...\">` attribute (Chrome 134+,\nSafari 18.4+, Firefox 139+). 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.",
137
+ "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.",
138
138
  "attribute": "closed-by",
139
139
  "reflects": true
140
140
  },
@@ -145,9 +145,28 @@
145
145
  "text": "boolean"
146
146
  },
147
147
  "default": "false",
148
- "description": "JS fallback for backdrop-click dismissal. When true, a click on the\n`<dialog>` element itself (i.e. the backdrop area, not a child element)\ncalls `requestClose()`. Complements native `closed-by=\"any\"` for browsers\nthat do not yet support the `closedby` attribute.",
148
+ "description": "When true and the dialog is modal, a click on the backdrop area calls\n`requestClose()`.",
149
149
  "attribute": "light-dismiss"
150
150
  },
151
+ {
152
+ "kind": "field",
153
+ "name": "modal",
154
+ "type": {
155
+ "text": "boolean"
156
+ },
157
+ "default": "true",
158
+ "description": "Whether to open as modal with controlled open. Default: `true`."
159
+ },
160
+ {
161
+ "kind": "field",
162
+ "name": "_$dialog",
163
+ "type": {
164
+ "text": "HTMLDialogElement | null"
165
+ },
166
+ "privacy": "protected",
167
+ "description": "The inner `<dialog>` element, resolved from the direct light-DOM child.",
168
+ "readonly": true
169
+ },
151
170
  {
152
171
  "kind": "field",
153
172
  "name": "_controlledOpen",
@@ -168,18 +187,16 @@
168
187
  },
169
188
  {
170
189
  "kind": "field",
171
- "name": "_dialogRef",
172
- "type": {
173
- "text": "WeakRef<HTMLDialogElement> | null"
174
- },
190
+ "name": "_dialogController",
175
191
  "privacy": "private",
176
- "default": "null"
192
+ "readonly": true,
193
+ "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>.', }); } }, })"
177
194
  },
178
195
  {
179
196
  "kind": "field",
180
- "name": "_observer",
197
+ "name": "_$wired",
181
198
  "type": {
182
- "text": "MutationObserver | null"
199
+ "text": "WeakRef<HTMLDialogElement> | null"
183
200
  },
184
201
  "privacy": "private",
185
202
  "default": "null"
@@ -195,11 +212,11 @@
195
212
  },
196
213
  {
197
214
  "kind": "field",
198
- "name": "_openerEl",
215
+ "name": "_$opener",
199
216
  "type": {
200
217
  "text": "Element | null"
201
218
  },
202
- "privacy": "private",
219
+ "privacy": "protected",
203
220
  "default": "null",
204
221
  "description": "The element that had focus when the dialog was opened; restored on close."
205
222
  },
@@ -249,7 +266,7 @@
249
266
  "text": "void"
250
267
  }
251
268
  },
252
- "description": "Opens the inner `<dialog>` as a non-modal and fires `rc-dialog-open`."
269
+ "description": "Opens the inner `<dialog>` (non-modal) and fires `rc-dialog-open`."
253
270
  },
254
271
  {
255
272
  "kind": "method",
@@ -287,54 +304,55 @@
287
304
  }
288
305
  }
289
306
  ],
290
- "description": "Requests the inner `<dialog>` to close, firing a cancelable `cancel` event\nfirst. If the consumer prevents `rc-dialog-request-close`, the close is\nblocked. Falls back to a synthesized cancel → close sequence in browsers\nthat do not yet support the native `requestClose()` method."
291
- },
292
- {
293
- "kind": "method",
294
- "name": "_dlg",
295
- "privacy": "private",
296
- "return": {
297
- "type": {
298
- "text": "HTMLDialogElement | null"
299
- }
300
- }
307
+ "description": "Requests the inner `<dialog>` to close, firing a cancelable `cancel` event\nfirst."
301
308
  },
302
309
  {
303
310
  "kind": "method",
304
311
  "name": "_setupDialog",
305
- "privacy": "private"
312
+ "privacy": "protected",
313
+ "parameters": [
314
+ {
315
+ "name": "$dialog",
316
+ "default": "this._$dialog",
317
+ "type": {
318
+ "text": "HTMLDialogElement | null"
319
+ }
320
+ }
321
+ ],
322
+ "description": "Wires event listeners, drag/resize controllers, and initial open state for the inner `<dialog>`."
306
323
  },
307
324
  {
308
325
  "kind": "method",
309
326
  "name": "_teardownDialog",
310
- "privacy": "private",
327
+ "privacy": "protected",
311
328
  "return": {
312
329
  "type": {
313
330
  "text": "void"
314
331
  }
315
- }
332
+ },
333
+ "description": "Removes all event listeners attached to the inner `<dialog>` and clears cached state."
316
334
  },
317
335
  {
318
336
  "kind": "field",
319
337
  "name": "_onClose",
320
- "privacy": "private"
338
+ "privacy": "protected"
321
339
  },
322
340
  {
323
341
  "kind": "field",
324
342
  "name": "_onCancel",
325
- "privacy": "private",
326
- "description": "Intercepts the native `cancel` event (Escape key or `requestClose()`).\nFires the cancelable `rc-dialog-request-close` event first. If prevented,\nthe native cancel is suppressed and the dialog stays open. If not prevented,\nthe backward-compatible `rc-dialog-cancel` is also fired and the browser\nproceeds to close the dialog naturally (no explicit `dlg.close()` call here,\nso the `requestClose()` fallback can close after `dispatchEvent` returns)."
343
+ "privacy": "protected",
344
+ "description": "Intercepts the native `cancel` event."
327
345
  },
328
346
  {
329
347
  "kind": "field",
330
348
  "name": "_onBackdropClick",
331
- "privacy": "private",
332
- "description": "Detects backdrop clicks: a click whose `target` is the `<dialog>` element\nitself (not a descendant) means the user clicked outside the dialog's\ncontent box on the backdrop area."
349
+ "privacy": "protected",
350
+ "description": "Detects backdrop clicks."
333
351
  },
334
352
  {
335
353
  "kind": "method",
336
354
  "name": "_applyOpen",
337
- "privacy": "private",
355
+ "privacy": "protected",
338
356
  "return": {
339
357
  "type": {
340
358
  "text": "boolean"
@@ -345,24 +363,28 @@
345
363
  "name": "open",
346
364
  "type": {
347
365
  "text": "boolean"
348
- }
366
+ },
367
+ "description": "Whether to open (`true`) or close (`false`)."
349
368
  },
350
369
  {
351
370
  "name": "silent",
352
371
  "type": {
353
372
  "text": "boolean"
354
- }
373
+ },
374
+ "description": "When `true`, suppresses the outgoing `rc-dialog-toggle` event."
355
375
  },
356
376
  {
357
377
  "name": "modal",
358
- "default": "true"
378
+ "default": "true",
379
+ "description": "Whether to call `showModal()` (`true`) or `show()` (`false`)."
359
380
  }
360
- ]
381
+ ],
382
+ "description": "Opens or closes the inner `<dialog>` and returns `true` if state actually changed."
361
383
  },
362
384
  {
363
385
  "kind": "method",
364
386
  "name": "_dispatchToggle",
365
- "privacy": "private",
387
+ "privacy": "protected",
366
388
  "return": {
367
389
  "type": {
368
390
  "text": "void"
@@ -375,7 +397,8 @@
375
397
  "text": "boolean"
376
398
  }
377
399
  }
378
- ]
400
+ ],
401
+ "description": "Dispatches `rc-dialog-toggle` with the current open state and return value."
379
402
  }
380
403
  ],
381
404
  "events": [
@@ -394,7 +417,7 @@
394
417
  "description": "Fired when user/native interaction changes open state."
395
418
  },
396
419
  {
397
- "description": "Fired before the dialog closes (Escape key, backdrop click when `light-dismiss` is set, or a call to `requestClose()`). **Cancelable** — call `preventDefault()` to block the close (e.g. unsaved- changes guard). `detail: { returnValue: string }`",
420
+ "description": "Fired before the dialog closes (cancellable).",
398
421
  "name": "rc-dialog-request-close"
399
422
  },
400
423
  {
@@ -413,7 +436,7 @@
413
436
  "text": "boolean"
414
437
  },
415
438
  "default": "false",
416
- "description": "Allow the dialog to be moved by dragging. Use `move-handle` to restrict\ndragging to a specific child element (e.g. a titlebar).\nNamed `movable` — not `draggable` — to avoid colliding with the\nbuilt-in HTML Drag and Drop `draggable` global attribute.",
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).",
417
440
  "fieldName": "movable"
418
441
  },
419
442
  {
@@ -476,7 +499,7 @@
476
499
  "text": "'any' | 'closerequest' | 'none' | ''"
477
500
  },
478
501
  "default": "''",
479
- "description": "Proxied to the inner `<dialog closedby=\"...\">` attribute (Chrome 134+,\nSafari 18.4+, Firefox 139+). 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.",
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.",
480
503
  "fieldName": "closedBy"
481
504
  },
482
505
  {
@@ -485,7 +508,7 @@
485
508
  "text": "boolean"
486
509
  },
487
510
  "default": "false",
488
- "description": "JS fallback for backdrop-click dismissal. When true, a click on the\n`<dialog>` element itself (i.e. the backdrop area, not a child element)\ncalls `requestClose()`. Complements native `closed-by=\"any\"` for browsers\nthat do not yet support the `closedby` attribute.",
511
+ "description": "When true and the dialog is modal, a click on the backdrop area calls\n`requestClose()`.",
489
512
  "fieldName": "lightDismiss"
490
513
  },
491
514
  {
@@ -1,15 +1,21 @@
1
1
  import { LitElement as a, nothing as d } from "lit";
2
2
  import { property as i } from "lit/decorators.js";
3
- import { DragController as u, ResizeController as c } from "@rcarls/rc-common";
4
- var f = Object.defineProperty, _ = Object.getOwnPropertyDescriptor, o = (n, e, t, l) => {
5
- for (var s = l > 1 ? void 0 : l ? _(e, t) : e, p = n.length - 1, h; p >= 0; p--)
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
6
  (h = n[p]) && (s = (l ? h(e, t, s) : h(s)) || s);
7
- return l && s && f(e, t, s), s;
7
+ return l && s && _(e, t, s), s;
8
8
  };
9
9
  class r extends a {
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._controlledOpen = void 0, this._defaultOpen = !1, this._dialogRef = null, this._observer = null, this._suppressNextCloseToggle = !1, this._openerEl = null, this._onClose = () => {
12
- this._openerEl instanceof HTMLElement && this._openerEl.isConnected && this._openerEl.focus(), this._openerEl = null, this.dispatchEvent(
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, {
12
+ selector: ":scope > dialog",
13
+ observe: !0,
14
+ onChange: (e) => this._setupDialog(e),
15
+ onMissing: () => {
16
+ }
17
+ }), this._$wired = null, this._suppressNextCloseToggle = !1, this._$opener = null, this._onClose = () => {
18
+ this._$opener instanceof HTMLElement && (this._$opener.isConnected ? this._$opener.focus() : document.body.focus()), this._$opener = null, this.dispatchEvent(
13
19
  new CustomEvent("rc-dialog-close", {
14
20
  bubbles: !0,
15
21
  composed: !0,
@@ -23,54 +29,56 @@ class r extends a {
23
29
  cancelable: !0,
24
30
  detail: { returnValue: this.returnValue }
25
31
  });
26
- !this.dispatchEvent(t) ? e.preventDefault() : this.dispatchEvent(
27
- new CustomEvent("rc-dialog-cancel", { bubbles: !0, composed: !0 })
28
- );
32
+ !this.dispatchEvent(t) ? e.preventDefault() : this.dispatchEvent(new CustomEvent("rc-dialog-cancel", { bubbles: !0, composed: !0 }));
29
33
  }, this._onBackdropClick = (e) => {
30
- e.target === this._dlg() && this.requestClose();
34
+ e.target === this._$dialog && this.requestClose();
31
35
  };
32
36
  }
33
37
  createRenderRoot() {
34
38
  return this;
35
39
  }
40
+ /** The inner `<dialog>` element, resolved from the direct light-DOM child. */
41
+ get _$dialog() {
42
+ return this._dialogController.child;
43
+ }
36
44
  get open() {
37
- return this._dlg()?.open ?? !1;
45
+ return this._$dialog?.open ?? !1;
38
46
  }
39
47
  set open(e) {
40
48
  const t = this._controlledOpen;
41
- this._controlledOpen = e, e !== void 0 && this._applyOpen(e, !0), this.requestUpdate("open", t);
49
+ this._controlledOpen = e, e !== void 0 && this._applyOpen(e, !0, this.modal), this.requestUpdate("open", t);
42
50
  }
43
51
  get defaultOpen() {
44
52
  return this._defaultOpen;
45
53
  }
46
54
  set defaultOpen(e) {
47
55
  const t = this._defaultOpen;
48
- this._defaultOpen = e, this._controlledOpen === void 0 && e && this._applyOpen(!0, !0), this.requestUpdate("defaultOpen", t);
56
+ this._defaultOpen = e, this._controlledOpen === void 0 && e && this.isConnected && this._applyOpen(!0, !0, this.modal), this.requestUpdate("defaultOpen", t);
49
57
  }
50
58
  /** The return value set when the dialog was closed. */
51
59
  get returnValue() {
52
- return this._dlg()?.returnValue ?? "";
60
+ return this._$dialog?.returnValue ?? "";
53
61
  }
54
62
  /** Opens the inner `<dialog>` as a modal and fires `rc-dialog-open`. */
55
63
  showModal() {
56
64
  this._applyOpen(!0, !1, !0) && (this.dispatchEvent(new CustomEvent("rc-dialog-open", { bubbles: !0, composed: !0 })), this._dispatchToggle(!0));
57
65
  }
58
- /** Opens the inner `<dialog>` as a non-modal and fires `rc-dialog-open`. */
66
+ /**
67
+ * Opens the inner `<dialog>` (non-modal) and fires `rc-dialog-open`.
68
+ */
59
69
  show() {
60
70
  this._applyOpen(!0, !1, !1) && (this.dispatchEvent(new CustomEvent("rc-dialog-open", { bubbles: !0, composed: !0 })), this._dispatchToggle(!0));
61
71
  }
62
72
  /** Closes the inner `<dialog>`, optionally setting a return value. */
63
73
  close(e) {
64
- this._dlg()?.close(e);
74
+ this._$dialog?.close(e);
65
75
  }
66
76
  /**
67
77
  * Requests the inner `<dialog>` to close, firing a cancelable `cancel` event
68
- * first. If the consumer prevents `rc-dialog-request-close`, the close is
69
- * blocked. Falls back to a synthesized cancel → close sequence in browsers
70
- * that do not yet support the native `requestClose()` method.
78
+ * first.
71
79
  */
72
80
  requestClose(e) {
73
- const t = this._dlg();
81
+ const t = this._$dialog;
74
82
  if (t)
75
83
  if ("requestClose" in t && typeof t.requestClose == "function")
76
84
  t.requestClose(e);
@@ -79,55 +87,61 @@ class r extends a {
79
87
  !t.dispatchEvent(l) || t.close(e);
80
88
  }
81
89
  }
82
- // ---- Internals ----------------------------------------------------------
83
- _dlg() {
84
- return this._dialogRef?.deref() ?? this.querySelector(":scope > dialog");
85
- }
86
90
  render() {
87
91
  return d;
88
92
  }
89
- connectedCallback() {
90
- super.connectedCallback(), this._observer = new MutationObserver(() => this._setupDialog()), this._observer.observe(this, { childList: !0 });
91
- }
92
93
  firstUpdated() {
93
- this._setupDialog();
94
+ this._dialogController.sync();
94
95
  }
95
- _setupDialog() {
96
- const e = this._dlg();
97
- if (e && this._dialogRef?.deref() !== e) {
98
- if (this._teardownDialog(), this._dialogRef = 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) {
96
+ /** Wires event listeners, drag/resize controllers, and initial open state for the inner `<dialog>`. */
97
+ _setupDialog(e = this._$dialog) {
98
+ if (!e) {
99
+ this._teardownDialog();
100
+ return;
101
+ }
102
+ if (this._$wired?.deref() !== e) {
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) {
99
104
  const t = this.moveHandle ? e.querySelector(this.moveHandle) ?? e : e;
100
- new u(this, {
105
+ new c(this, {
101
106
  target: e,
102
107
  handle: t,
103
108
  bounds: this.moveBounds,
104
109
  step: this.moveStep
105
110
  });
106
111
  }
107
- this.resize !== "none" && new c(this, {
112
+ this.resize !== "none" && new f(this, {
108
113
  target: e,
109
114
  direction: this.resize,
110
115
  threshold: this.resizeThreshold,
111
116
  step: this.resizeStep,
112
117
  bounds: this.moveBounds
113
- }), this._controlledOpen !== void 0 ? this._applyOpen(this._controlledOpen, !0) : this.defaultOpen && this._applyOpen(!0, !0);
118
+ }), this._controlledOpen !== void 0 ? this._applyOpen(this._controlledOpen, !0, this.modal) : this.defaultOpen && this._applyOpen(!0, !0, this.modal);
114
119
  }
115
120
  }
116
121
  updated(e) {
117
- const t = this._dlg();
122
+ const t = this._$dialog;
118
123
  t && (e.has("closedBy") && (this.closedBy ? t.setAttribute("closedby", this.closedBy) : t.removeAttribute("closedby")), e.has("lightDismiss") && (this.lightDismiss && "closedBy" in HTMLDialogElement.prototype ? (t.setAttribute("closedby", "any"), t.removeEventListener("click", this._onBackdropClick)) : this.lightDismiss ? t.addEventListener("click", this._onBackdropClick) : (t.removeEventListener("click", this._onBackdropClick), this.closedBy ? t.setAttribute("closedby", this.closedBy) : t.removeAttribute("closedby"))));
119
124
  }
120
125
  disconnectedCallback() {
121
- this._observer?.disconnect(), this._observer = null, this._teardownDialog(), super.disconnectedCallback();
126
+ this._teardownDialog(), super.disconnectedCallback();
122
127
  }
128
+ /** Removes all event listeners attached to the inner `<dialog>` and clears cached state. */
123
129
  _teardownDialog() {
124
- const e = this._dialogRef?.deref();
125
- e && (e.removeEventListener("close", this._onClose), e.removeEventListener("cancel", this._onCancel), e.removeEventListener("click", this._onBackdropClick), this._dialogRef = null, this._openerEl = null);
130
+ const e = this._$wired?.deref();
131
+ e && (e.removeEventListener("close", this._onClose), e.removeEventListener("cancel", this._onCancel), e.removeEventListener("click", this._onBackdropClick), this._$wired = null, this._$opener = null);
126
132
  }
133
+ /**
134
+ * Opens or closes the inner `<dialog>` and returns `true` if state actually changed.
135
+ *
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`).
139
+ */
127
140
  _applyOpen(e, t, l = !0) {
128
- const s = this._dlg();
129
- return s ? e ? s.open ? !1 : (this._openerEl = document.activeElement, l ? s.showModal() : s.show(), this.requestUpdate("open"), !0) : s.open ? (this._suppressNextCloseToggle = t, s.close(), this.requestUpdate("open"), !0) : !1 : !1;
141
+ 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;
130
143
  }
144
+ /** Dispatches `rc-dialog-toggle` with the current open state and return value. */
131
145
  _dispatchToggle(e) {
132
146
  this.dispatchEvent(
133
147
  new CustomEvent("rc-dialog-toggle", {
@@ -174,4 +188,4 @@ o([
174
188
  export {
175
189
  r as R
176
190
  };
177
- //# sourceMappingURL=rc-dialog-BGtJgQDG.js.map
191
+ //# sourceMappingURL=rc-dialog-Dpj3ERfv.js.map
@@ -0,0 +1 @@
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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"}
@@ -1,4 +1,4 @@
1
- import { R as e } from "./rc-dialog-BGtJgQDG.js";
1
+ import { R as e } from "./rc-dialog-Dpj3ERfv.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-BGtJgQDG.js";
1
+ import { R as r } from "./rc-dialog-Dpj3ERfv.js";
2
2
  export {
3
3
  r as RCDialog
4
4
  };
@@ -21,35 +21,30 @@ declare global {
21
21
  }
22
22
  }
23
23
  /**
24
- * Enhances a consumer-provided `<dialog>` child with drag, resize, and
25
- * accessible event forwarding. Renders nothing itself — the `<dialog>` element
26
- * remains in the document's light DOM for full CSS and AT access.
24
+ * Draggable, resizable wrapper for a native <dialog>, following the WAI-ARIA Dialog Modal
25
+ * pattern.
26
+ *
27
+ * @see {@link https://richardcarls.github.io/rc-webcomponents/components/rc-dialog rc-dialog docs}
28
+ * @see {@link https://www.w3.org/WAI/ARIA/apg/patterns/dialog-modal/ WAI-ARIA Dialog Modal pattern}
27
29
  *
28
30
  * @slot - Place a `<dialog>` element with your content here.
29
31
  *
30
32
  * @fires rc-dialog-open - Fired when the dialog opens via `showModal()` or `show()`.
31
33
  * @fires rc-dialog-toggle - Fired when user/native interaction changes open state.
32
- *
33
- * @fires rc-dialog-request-close - Fired before the dialog closes (Escape key,
34
- * backdrop click when `light-dismiss` is set, or a call to `requestClose()`).
35
- * **Cancelable** — call `preventDefault()` to block the close (e.g. unsaved-
36
- * changes guard). `detail: { returnValue: string }`
37
- *
34
+ * @fires rc-dialog-request-close - Fired before the dialog closes (cancellable).
38
35
  * @fires rc-dialog-cancel - Mirrors the inner `<dialog>` cancel event when the
39
36
  * close was not prevented. Backward-compatible alias for `rc-dialog-request-close`.
40
- *
41
37
  * @fires rc-dialog-close - Mirrors the inner `<dialog>` close event.
42
38
  * `detail: { returnValue: string }`
43
39
  *
44
- * @see https://www.w3.org/WAI/ARIA/apg/patterns/dialog-modal/
45
40
  */
46
41
  export declare class RCDialog extends LitElement {
47
42
  createRenderRoot(): this;
48
43
  /**
49
- * Allow the dialog to be moved by dragging. Use `move-handle` to restrict
50
- * dragging to a specific child element (e.g. a titlebar).
51
- * Named `movable` — not `draggable` — to avoid colliding with the
52
- * built-in HTML Drag and Drop `draggable` global attribute.
44
+ * Allow the dialog to be moved by dragging.
45
+ *
46
+ * Use `move-handle` to restrict dragging to a specific child
47
+ * element (e.g. a titlebar).
53
48
  */
54
49
  movable: boolean;
55
50
  /** CSS selector (within the inner `<dialog>`) for the drag handle element. */
@@ -65,8 +60,9 @@ export declare class RCDialog extends LitElement {
65
60
  /** Keyboard arrow-key step in px for resizing. */
66
61
  resizeStep: number;
67
62
  /**
68
- * Proxied to the inner `<dialog closedby="...">` attribute (Chrome 134+,
69
- * Safari 18.4+, Firefox 139+). Progressive enhancement — no-op in older browsers.
63
+ * Proxied to the inner `<dialog closedby="...">` attribute.
64
+ *
65
+ * Progressive enhancement, no-op in older browsers.
70
66
  *
71
67
  * - `'any'` — Escape OR backdrop click closes the dialog.
72
68
  * - `'closerequest'` — Escape only (browser default for modal dialogs).
@@ -75,19 +71,23 @@ export declare class RCDialog extends LitElement {
75
71
  */
76
72
  closedBy: 'any' | 'closerequest' | 'none' | '';
77
73
  /**
78
- * JS fallback for backdrop-click dismissal. When true, a click on the
79
- * `<dialog>` element itself (i.e. the backdrop area, not a child element)
80
- * calls `requestClose()`. Complements native `closed-by="any"` for browsers
81
- * that do not yet support the `closedby` attribute.
74
+ * When true and the dialog is modal, a click on the backdrop area calls
75
+ * `requestClose()`.
82
76
  */
83
77
  lightDismiss: boolean;
78
+ /**
79
+ * Whether to open as modal with controlled open. Default: `true`.
80
+ */
81
+ modal: boolean;
82
+ /** The inner `<dialog>` element, resolved from the direct light-DOM child. */
83
+ protected get _$dialog(): HTMLDialogElement | null;
84
84
  private _controlledOpen;
85
85
  private _defaultOpen;
86
- private _dialogRef;
87
- private _observer;
86
+ private readonly _dialogController;
87
+ private _$wired;
88
88
  private _suppressNextCloseToggle;
89
89
  /** The element that had focus when the dialog was opened; restored on close. */
90
- private _openerEl;
90
+ protected _$opener: Element | null;
91
91
  /** Whether the inner `<dialog>` is currently open. Host writes update silently. */
92
92
  get open(): boolean;
93
93
  set open(value: boolean | undefined);
@@ -98,42 +98,43 @@ export declare class RCDialog extends LitElement {
98
98
  get returnValue(): string;
99
99
  /** Opens the inner `<dialog>` as a modal and fires `rc-dialog-open`. */
100
100
  showModal(): void;
101
- /** Opens the inner `<dialog>` as a non-modal and fires `rc-dialog-open`. */
101
+ /**
102
+ * Opens the inner `<dialog>` (non-modal) and fires `rc-dialog-open`.
103
+ */
102
104
  show(): void;
103
105
  /** Closes the inner `<dialog>`, optionally setting a return value. */
104
106
  close(returnValue?: string): void;
105
107
  /**
106
108
  * Requests the inner `<dialog>` to close, firing a cancelable `cancel` event
107
- * first. If the consumer prevents `rc-dialog-request-close`, the close is
108
- * blocked. Falls back to a synthesized cancel → close sequence in browsers
109
- * that do not yet support the native `requestClose()` method.
109
+ * first.
110
110
  */
111
111
  requestClose(returnValue?: string): void;
112
- private _dlg;
113
112
  render(): symbol;
114
- connectedCallback(): void;
115
113
  firstUpdated(): void;
116
- private _setupDialog;
114
+ /** Wires event listeners, drag/resize controllers, and initial open state for the inner `<dialog>`. */
115
+ protected _setupDialog($dialog?: HTMLDialogElement | null): void;
117
116
  updated(changed: PropertyValues): void;
118
117
  disconnectedCallback(): void;
119
- private _teardownDialog;
120
- private _onClose;
118
+ /** Removes all event listeners attached to the inner `<dialog>` and clears cached state. */
119
+ protected _teardownDialog(): void;
120
+ protected _onClose: () => void;
121
121
  /**
122
- * Intercepts the native `cancel` event (Escape key or `requestClose()`).
123
- * Fires the cancelable `rc-dialog-request-close` event first. If prevented,
124
- * the native cancel is suppressed and the dialog stays open. If not prevented,
125
- * the backward-compatible `rc-dialog-cancel` is also fired and the browser
126
- * proceeds to close the dialog naturally (no explicit `dlg.close()` call here,
127
- * so the `requestClose()` fallback can close after `dispatchEvent` returns).
122
+ * Intercepts the native `cancel` event.
128
123
  */
129
- private _onCancel;
124
+ protected _onCancel: (e: Event) => void;
130
125
  /**
131
- * Detects backdrop clicks: a click whose `target` is the `<dialog>` element
132
- * itself (not a descendant) means the user clicked outside the dialog's
133
- * content box on the backdrop area.
126
+ * Detects backdrop clicks.
127
+ */
128
+ protected _onBackdropClick: (e: MouseEvent) => void;
129
+ /**
130
+ * Opens or closes the inner `<dialog>` and returns `true` if state actually changed.
131
+ *
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`).
134
135
  */
135
- private _onBackdropClick;
136
- private _applyOpen;
137
- private _dispatchToggle;
136
+ protected _applyOpen(open: boolean, silent: boolean, modal?: boolean): boolean;
137
+ /** Dispatches `rc-dialog-toggle` with the current open state and return value. */
138
+ protected _dispatchToggle(open: boolean): void;
138
139
  }
139
140
  export default RCDialog;
package/package.json CHANGED
@@ -3,14 +3,14 @@
3
3
  "publishConfig": {
4
4
  "access": "public"
5
5
  },
6
- "version": "0.2.0",
7
- "description": "Headless draggable and resizable native dialog wrapper, built with Lit",
6
+ "version": "0.3.1",
7
+ "description": "Draggable, resizable wrapper for a native <dialog>.",
8
8
  "repository": {
9
9
  "type": "git",
10
10
  "url": "git+https://github.com/richardcarls/rc-webcomponents.git",
11
11
  "directory": "packages/rc-dialog"
12
12
  },
13
- "homepage": "https://github.com/richardcarls/rc-webcomponents#readme",
13
+ "homepage": "https://richardcarls.github.io/rc-webcomponents/components/rc-dialog",
14
14
  "license": "MIT",
15
15
  "type": "module",
16
16
  "files": [
@@ -37,21 +37,18 @@
37
37
  ],
38
38
  "customElements": "dist/custom-elements.json",
39
39
  "scripts": {
40
- "dev": "vite",
41
40
  "build": "tsc && vite build && cem analyze",
42
41
  "cem:analyze": "cem analyze",
43
42
  "preview": "vite preview",
44
- "test:browser": "vitest",
45
- "test:browser:chrome": "vitest --project=chromium",
46
- "test:browser:firefox": "vitest --project=firefox",
47
- "yalc:publish": "yalc publish --push"
43
+ "test:browser": "vitest --run",
44
+ "test:browser:chrome": "vitest --run --project=chromium",
45
+ "test:browser:firefox": "vitest --run --project=firefox"
48
46
  },
49
47
  "dependencies": {
50
- "@rcarls/rc-common": "workspace:^"
48
+ "@rcarls/rc-common": "workspace:*"
51
49
  },
52
50
  "devDependencies": {
53
51
  "@custom-elements-manifest/analyzer": "0.11.0",
54
- "@guanghechen/rollup-plugin-copy": "^6.0.9",
55
52
  "@vitest/browser-playwright": "4.1.5",
56
53
  "lit": "^3.0.0",
57
54
  "playwright": "^1.56.0",
package/dist/demo.css DELETED
@@ -1,85 +0,0 @@
1
- *, *::before, *::after {
2
- box-sizing: border-box;
3
- }
4
-
5
- :root {
6
- color-scheme: light dark;
7
- --rc-accent: Highlight; /* Chrome doesn't support AccentColor on the open web */
8
- }
9
-
10
- @supports (color: AccentColor) {
11
- :root {
12
- --rc-accent: AccentColor;
13
- }
14
- }
15
-
16
- [data-theme="light"] { color-scheme: light; }
17
- [data-theme="dark"] { color-scheme: dark; }
18
-
19
- [data-theme="solarized-light"] {
20
- color-scheme: light;
21
- --rc-surface: #fdf6e3;
22
- --rc-text: #657b83;
23
- --rc-border: 1px solid #93a1a1;
24
- --rc-shadow: 0 2px 8px rgba(0, 0, 0, .12);
25
- }
26
-
27
- [data-theme="solarized-dark"] {
28
- color-scheme: dark;
29
- --rc-surface: #002b36;
30
- --rc-text: #839496;
31
- --rc-border: 1px solid #586e75;
32
- --rc-shadow: 0 2px 8px rgba(0, 0, 0, .3);
33
- }
34
-
35
- body {
36
- font-family: system-ui, sans-serif;
37
- margin: 0;
38
- }
39
-
40
- .demo-page {
41
- max-width: 60rem;
42
- margin: 0 auto;
43
- padding: 2rem 1.5rem;
44
- }
45
-
46
- .demo-controls {
47
- display: flex;
48
- align-items: center;
49
- gap: 1rem;
50
- margin-bottom: 2rem;
51
- padding-bottom: 1rem;
52
- border-bottom: 1px solid ButtonBorder;
53
- }
54
-
55
- .demo-controls .demo-title {
56
- flex: 1;
57
- }
58
-
59
- .demo-controls h1 {
60
- margin: 0 0 0.15rem;
61
- font-size: 1.5rem;
62
- }
63
-
64
- .demo-controls a {
65
- font-size: 0.8rem;
66
- }
67
-
68
- .demo-section {
69
- margin-bottom: 2rem;
70
- }
71
-
72
- .demo-section h2 {
73
- margin: 0 0 0.5rem;
74
- }
75
-
76
- .theme-picker {
77
- padding: 0.35em 0.75em;
78
- font-family: inherit;
79
- font-size: 0.8rem;
80
- cursor: pointer;
81
- border: 1px solid ButtonBorder;
82
- border-radius: 4px;
83
- background: Canvas;
84
- color: CanvasText;
85
- }
package/dist/demo.js DELETED
@@ -1,40 +0,0 @@
1
- const THEMES = ['', 'light', 'dark', 'solarized-light', 'solarized-dark'];
2
- const LABELS = ['Auto', 'Light', 'Dark', 'Solarized ☀', 'Solarized ☾'];
3
-
4
- const stored = localStorage.getItem('rc-demo-theme') ?? '';
5
- applyTheme(stored);
6
-
7
- function applyTheme(theme) {
8
- if (theme) {
9
- document.documentElement.dataset.theme = theme;
10
- } else {
11
- delete document.documentElement.dataset.theme;
12
- }
13
- }
14
-
15
- function currentIndex() {
16
- const current = document.documentElement.dataset.theme ?? '';
17
- const idx = THEMES.indexOf(current);
18
- return idx === -1 ? 0 : idx;
19
- }
20
-
21
- function updateButtons() {
22
- const label = LABELS[currentIndex()];
23
- document.querySelectorAll('.theme-picker').forEach((btn) => {
24
- btn.textContent = label;
25
- });
26
- }
27
-
28
- window.cycleTheme = function () {
29
- const next = THEMES[(currentIndex() + 1) % THEMES.length];
30
- applyTheme(next);
31
- localStorage.setItem('rc-demo-theme', next);
32
- updateButtons();
33
- };
34
-
35
- document.addEventListener('DOMContentLoaded', () => {
36
- updateButtons();
37
- document.querySelectorAll('.theme-picker').forEach((btn) => {
38
- btn.addEventListener('click', window.cycleTheme);
39
- });
40
- });
@@ -1 +0,0 @@
1
- {"version":3,"file":"rc-dialog-BGtJgQDG.js","sources":["../src/rc-dialog.ts"],"sourcesContent":["import { LitElement, nothing, type PropertyValues } from 'lit';\nimport { property } from 'lit/decorators.js';\nimport { DragController, ResizeController } 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 * Enhances a consumer-provided `<dialog>` child with drag, resize, and\n * accessible event forwarding. Renders nothing itself — the `<dialog>` element\n * remains in the document's light DOM for full CSS and AT access.\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 *\n * @fires rc-dialog-request-close - Fired before the dialog closes (Escape key,\n * backdrop click when `light-dismiss` is set, or a call to `requestClose()`).\n * **Cancelable** — call `preventDefault()` to block the close (e.g. unsaved-\n * changes guard). `detail: { returnValue: string }`\n *\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 *\n * @fires rc-dialog-close - Mirrors the inner `<dialog>` close event.\n * `detail: { returnValue: string }`\n *\n * @see https://www.w3.org/WAI/ARIA/apg/patterns/dialog-modal/\n */\nexport class RCDialog extends LitElement {\n override createRenderRoot() { return this; }\n\n /**\n * Allow the dialog to be moved by dragging. Use `move-handle` to restrict\n * dragging to a specific child element (e.g. a titlebar).\n * Named `movable` — not `draggable` — to avoid colliding with the\n * built-in HTML Drag and Drop `draggable` global attribute.\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 (Chrome 134+,\n * Safari 18.4+, Firefox 139+). 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 * JS fallback for backdrop-click dismissal. When true, a click on the\n * `<dialog>` element itself (i.e. the backdrop area, not a child element)\n * calls `requestClose()`. Complements native `closed-by=\"any\"` for browsers\n * that do not yet support the `closedby` attribute.\n */\n @property({ type: Boolean, attribute: 'light-dismiss' })\n lightDismiss = false;\n\n // ---- Native <dialog> delegation ----------------------------------------\n\n private _controlledOpen: boolean | undefined = undefined;\n private _defaultOpen = false;\n private _dialogRef: WeakRef<HTMLDialogElement> | null = null;\n // Initialized in connectedCallback — MutationObserver is browser-only.\n private _observer: MutationObserver | null = null;\n private _suppressNextCloseToggle = false;\n /** The element that had focus when the dialog was opened; restored on close. */\n private _openerEl: 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 { return this._dlg()?.open ?? false; }\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);\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 { return this._defaultOpen; }\n set defaultOpen(value: boolean) {\n const oldValue = this._defaultOpen;\n\n this._defaultOpen = value;\n\n if (this._controlledOpen === undefined && value) {\n this._applyOpen(true, true);\n }\n\n this.requestUpdate('defaultOpen', oldValue);\n }\n\n /** The return value set when the dialog was closed. */\n get returnValue(): string { return this._dlg()?.returnValue ?? ''; }\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 /** Opens the inner `<dialog>` as a non-modal and fires `rc-dialog-open`. */\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 { this._dlg()?.close(returnValue); }\n\n /**\n * Requests the inner `<dialog>` to close, firing a cancelable `cancel` event\n * first. If the consumer prevents `rc-dialog-request-close`, the close is\n * blocked. Falls back to a synthesized cancel → close sequence in browsers\n * that do not yet support the native `requestClose()` method.\n */\n requestClose(returnValue?: string): void {\n const dlg = this._dlg();\n if (!dlg) return;\n if ('requestClose' in dlg && typeof dlg.requestClose === 'function') {\n dlg.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 = !dlg.dispatchEvent(ev);\n if (!prevented) dlg.close(returnValue);\n }\n }\n\n // ---- Internals ----------------------------------------------------------\n\n private _dlg(): HTMLDialogElement | null {\n return this._dialogRef?.deref() ?? this.querySelector<HTMLDialogElement>(':scope > dialog');\n }\n\n override render() { return nothing; }\n\n override connectedCallback() {\n super.connectedCallback();\n this._observer = new MutationObserver(() => this._setupDialog());\n this._observer.observe(this, { childList: true });\n }\n\n override firstUpdated() {\n this._setupDialog();\n }\n\n private _setupDialog() {\n const dlg = this._dlg();\n if (!dlg) {\n if (import.meta.env.DEV) {\n console.warn(\n '[rc-dialog] No <dialog> child found. Place a <dialog> element ' +\n 'directly inside <rc-dialog>.',\n this,\n );\n }\n return;\n }\n\n if (this._dialogRef?.deref() === dlg) return;\n\n this._teardownDialog();\n this._dialogRef = new WeakRef(dlg);\n\n if (import.meta.env.DEV) {\n const hasLabel =\n dlg.hasAttribute('aria-labelledby') || dlg.hasAttribute('aria-label');\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 dlg,\n );\n }\n if (dlg.getAttribute('role') === 'alertdialog' && !dlg.hasAttribute('aria-describedby')) {\n console.warn(\n '[rc-dialog] <dialog role=\"alertdialog\"> should have aria-describedby ' +\n 'pointing to the alert message text.',\n dlg,\n );\n }\n }\n\n dlg.addEventListener('close', this._onClose);\n dlg.addEventListener('cancel', this._onCancel);\n\n if (this.lightDismiss && 'closedBy' in HTMLDialogElement.prototype) {\n dlg.setAttribute('closedby', 'any');\n } else if (this.lightDismiss) {\n dlg.addEventListener('click', this._onBackdropClick);\n } else {\n if (this.closedBy) dlg.setAttribute('closedby', this.closedBy);\n }\n\n if (this.movable || this.moveHandle) {\n const handle = this.moveHandle\n ? (dlg.querySelector<Element>(this.moveHandle) ?? dlg)\n : dlg;\n new DragController(this, {\n target: dlg,\n 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: dlg,\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);\n } else if (this.defaultOpen) {\n this._applyOpen(true, true);\n }\n }\n\n override updated(changed: PropertyValues) {\n const dlg = this._dlg();\n if (!dlg) return;\n\n if (changed.has('closedBy')) {\n if (this.closedBy) dlg.setAttribute('closedby', this.closedBy);\n else dlg.removeAttribute('closedby');\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 dlg.setAttribute('closedby', 'any');\n dlg.removeEventListener('click', this._onBackdropClick);\n } else if (this.lightDismiss) {\n dlg.addEventListener('click', this._onBackdropClick);\n } else {\n dlg.removeEventListener('click', this._onBackdropClick);\n if (this.closedBy) dlg.setAttribute('closedby', this.closedBy);\n else dlg.removeAttribute('closedby');\n }\n }\n }\n\n override disconnectedCallback() {\n this._observer?.disconnect();\n this._observer = null;\n this._teardownDialog();\n super.disconnectedCallback();\n }\n\n private _teardownDialog(): void {\n const dlg = this._dialogRef?.deref();\n if (!dlg) return;\n\n dlg.removeEventListener('close', this._onClose);\n dlg.removeEventListener('cancel', this._onCancel);\n dlg.removeEventListener('click', this._onBackdropClick);\n this._dialogRef = null;\n this._openerEl = null;\n }\n\n private _onClose = () => {\n // Restore focus to the element that triggered the open, per APG focus management.\n if (this._openerEl instanceof HTMLElement && this._openerEl.isConnected) {\n this._openerEl.focus();\n }\n this._openerEl = 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 (Escape key or `requestClose()`).\n * Fires the cancelable `rc-dialog-request-close` event first. If prevented,\n * the native cancel is suppressed and the dialog stays open. If not prevented,\n * the backward-compatible `rc-dialog-cancel` is also fired and the browser\n * proceeds to close the dialog naturally (no explicit `dlg.close()` call here,\n * so the `requestClose()` fallback can close after `dispatchEvent` returns).\n */\n private _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(\n new CustomEvent('rc-dialog-cancel', { bubbles: true, composed: true }),\n );\n }\n };\n\n /**\n * Detects backdrop clicks: a click whose `target` is the `<dialog>` element\n * itself (not a descendant) means the user clicked outside the dialog's\n * content box on the backdrop area.\n */\n private _onBackdropClick = (e: MouseEvent) => {\n if (e.target === this._dlg()) this.requestClose();\n };\n\n private _applyOpen(open: boolean, silent: boolean, modal = true): boolean {\n const dlg = this._dlg();\n if (!dlg) return false;\n\n if (open) {\n if (dlg.open) return false;\n // Capture focus owner before the dialog steals it, so we can restore on close.\n this._openerEl = document.activeElement;\n modal ? dlg.showModal() : dlg.show();\n this.requestUpdate('open');\n return true;\n }\n\n if (!dlg.open) return false;\n\n this._suppressNextCloseToggle = silent;\n dlg.close();\n this.requestUpdate('open');\n\n return true;\n }\n\n private _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","requestCloseEvent","value","oldValue","returnValue","dlg","ev","nothing","handle","DragController","ResizeController","changed","open","silent","modal","__decorateClass","property"],"mappings":"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"}