@rcarls/rc-dialog 0.1.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.
@@ -0,0 +1,536 @@
1
+ {
2
+ "schemaVersion": "1.0.0",
3
+ "readme": "",
4
+ "modules": [
5
+ {
6
+ "kind": "javascript-module",
7
+ "path": "src/define.ts",
8
+ "declarations": [],
9
+ "exports": [
10
+ {
11
+ "kind": "custom-element-definition",
12
+ "name": "rc-dialog",
13
+ "declaration": {
14
+ "name": "RCDialog",
15
+ "module": "/src/index.js"
16
+ }
17
+ },
18
+ {
19
+ "kind": "js",
20
+ "name": "*",
21
+ "declaration": {
22
+ "name": "*",
23
+ "module": "src/index.js"
24
+ }
25
+ }
26
+ ]
27
+ },
28
+ {
29
+ "kind": "javascript-module",
30
+ "path": "src/index.ts",
31
+ "declarations": [],
32
+ "exports": [
33
+ {
34
+ "kind": "js",
35
+ "name": "*",
36
+ "declaration": {
37
+ "name": "*",
38
+ "module": "src/rc-dialog.js"
39
+ }
40
+ }
41
+ ]
42
+ },
43
+ {
44
+ "kind": "javascript-module",
45
+ "path": "src/rc-dialog.ts",
46
+ "declarations": [
47
+ {
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.",
50
+ "name": "RCDialog",
51
+ "slots": [
52
+ {
53
+ "description": "Place a `<dialog>` element with your content here.",
54
+ "name": ""
55
+ }
56
+ ],
57
+ "members": [
58
+ {
59
+ "kind": "field",
60
+ "name": "movable",
61
+ "type": {
62
+ "text": "boolean"
63
+ },
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.",
66
+ "attribute": "movable",
67
+ "reflects": true
68
+ },
69
+ {
70
+ "kind": "field",
71
+ "name": "moveHandle",
72
+ "type": {
73
+ "text": "string"
74
+ },
75
+ "default": "''",
76
+ "description": "CSS selector (within the inner `<dialog>`) for the drag handle element.",
77
+ "attribute": "move-handle"
78
+ },
79
+ {
80
+ "kind": "field",
81
+ "name": "moveBounds",
82
+ "type": {
83
+ "text": "'viewport' | 'parent'"
84
+ },
85
+ "default": "'viewport'",
86
+ "description": "Bounds constraint for movement.",
87
+ "attribute": "move-bounds"
88
+ },
89
+ {
90
+ "kind": "field",
91
+ "name": "moveStep",
92
+ "type": {
93
+ "text": "number"
94
+ },
95
+ "default": "4",
96
+ "description": "Keyboard arrow-key step in px for moving.",
97
+ "attribute": "move-step"
98
+ },
99
+ {
100
+ "kind": "field",
101
+ "name": "resize",
102
+ "type": {
103
+ "text": "'none' | 'both' | 'horizontal' | 'vertical'"
104
+ },
105
+ "default": "'none'",
106
+ "description": "Enable resizing, mirroring the CSS `resize` property values.",
107
+ "attribute": "resize",
108
+ "reflects": true
109
+ },
110
+ {
111
+ "kind": "field",
112
+ "name": "resizeThreshold",
113
+ "type": {
114
+ "text": "number"
115
+ },
116
+ "default": "8",
117
+ "description": "Edge hit-test thickness in px for resize detection.",
118
+ "attribute": "resize-threshold"
119
+ },
120
+ {
121
+ "kind": "field",
122
+ "name": "resizeStep",
123
+ "type": {
124
+ "text": "number"
125
+ },
126
+ "default": "4",
127
+ "description": "Keyboard arrow-key step in px for resizing.",
128
+ "attribute": "resize-step"
129
+ },
130
+ {
131
+ "kind": "field",
132
+ "name": "closedBy",
133
+ "type": {
134
+ "text": "'any' | 'closerequest' | 'none' | ''"
135
+ },
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.",
138
+ "attribute": "closed-by",
139
+ "reflects": true
140
+ },
141
+ {
142
+ "kind": "field",
143
+ "name": "lightDismiss",
144
+ "type": {
145
+ "text": "boolean"
146
+ },
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.",
149
+ "attribute": "light-dismiss"
150
+ },
151
+ {
152
+ "kind": "field",
153
+ "name": "_controlledOpen",
154
+ "type": {
155
+ "text": "boolean | undefined"
156
+ },
157
+ "privacy": "private",
158
+ "default": "undefined"
159
+ },
160
+ {
161
+ "kind": "field",
162
+ "name": "_defaultOpen",
163
+ "type": {
164
+ "text": "boolean"
165
+ },
166
+ "privacy": "private",
167
+ "default": "false"
168
+ },
169
+ {
170
+ "kind": "field",
171
+ "name": "_dialogRef",
172
+ "type": {
173
+ "text": "WeakRef<HTMLDialogElement> | null"
174
+ },
175
+ "privacy": "private",
176
+ "default": "null"
177
+ },
178
+ {
179
+ "kind": "field",
180
+ "name": "_observer",
181
+ "type": {
182
+ "text": "MutationObserver | null"
183
+ },
184
+ "privacy": "private",
185
+ "default": "null"
186
+ },
187
+ {
188
+ "kind": "field",
189
+ "name": "_suppressNextCloseToggle",
190
+ "type": {
191
+ "text": "boolean"
192
+ },
193
+ "privacy": "private",
194
+ "default": "false"
195
+ },
196
+ {
197
+ "kind": "field",
198
+ "name": "_openerEl",
199
+ "type": {
200
+ "text": "Element | null"
201
+ },
202
+ "privacy": "private",
203
+ "default": "null",
204
+ "description": "The element that had focus when the dialog was opened; restored on close."
205
+ },
206
+ {
207
+ "kind": "field",
208
+ "name": "open",
209
+ "type": {
210
+ "text": "boolean"
211
+ },
212
+ "description": "Whether the inner `<dialog>` is currently open. Host writes update silently.",
213
+ "attribute": "open",
214
+ "reflects": true
215
+ },
216
+ {
217
+ "kind": "field",
218
+ "name": "defaultOpen",
219
+ "type": {
220
+ "text": "boolean"
221
+ },
222
+ "description": "Initial uncontrolled open state.",
223
+ "attribute": "default-open"
224
+ },
225
+ {
226
+ "kind": "field",
227
+ "name": "returnValue",
228
+ "type": {
229
+ "text": "string"
230
+ },
231
+ "description": "The return value set when the dialog was closed.",
232
+ "readonly": true
233
+ },
234
+ {
235
+ "kind": "method",
236
+ "name": "showModal",
237
+ "return": {
238
+ "type": {
239
+ "text": "void"
240
+ }
241
+ },
242
+ "description": "Opens the inner `<dialog>` as a modal and fires `rc-dialog-open`."
243
+ },
244
+ {
245
+ "kind": "method",
246
+ "name": "show",
247
+ "return": {
248
+ "type": {
249
+ "text": "void"
250
+ }
251
+ },
252
+ "description": "Opens the inner `<dialog>` as a non-modal and fires `rc-dialog-open`."
253
+ },
254
+ {
255
+ "kind": "method",
256
+ "name": "close",
257
+ "return": {
258
+ "type": {
259
+ "text": "void"
260
+ }
261
+ },
262
+ "parameters": [
263
+ {
264
+ "name": "returnValue",
265
+ "optional": true,
266
+ "type": {
267
+ "text": "string"
268
+ }
269
+ }
270
+ ],
271
+ "description": "Closes the inner `<dialog>`, optionally setting a return value."
272
+ },
273
+ {
274
+ "kind": "method",
275
+ "name": "requestClose",
276
+ "return": {
277
+ "type": {
278
+ "text": "void"
279
+ }
280
+ },
281
+ "parameters": [
282
+ {
283
+ "name": "returnValue",
284
+ "optional": true,
285
+ "type": {
286
+ "text": "string"
287
+ }
288
+ }
289
+ ],
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
+ }
301
+ },
302
+ {
303
+ "kind": "method",
304
+ "name": "_setupDialog",
305
+ "privacy": "private"
306
+ },
307
+ {
308
+ "kind": "method",
309
+ "name": "_teardownDialog",
310
+ "privacy": "private",
311
+ "return": {
312
+ "type": {
313
+ "text": "void"
314
+ }
315
+ }
316
+ },
317
+ {
318
+ "kind": "field",
319
+ "name": "_onClose",
320
+ "privacy": "private"
321
+ },
322
+ {
323
+ "kind": "field",
324
+ "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)."
327
+ },
328
+ {
329
+ "kind": "field",
330
+ "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."
333
+ },
334
+ {
335
+ "kind": "method",
336
+ "name": "_applyOpen",
337
+ "privacy": "private",
338
+ "return": {
339
+ "type": {
340
+ "text": "boolean"
341
+ }
342
+ },
343
+ "parameters": [
344
+ {
345
+ "name": "open",
346
+ "type": {
347
+ "text": "boolean"
348
+ }
349
+ },
350
+ {
351
+ "name": "silent",
352
+ "type": {
353
+ "text": "boolean"
354
+ }
355
+ },
356
+ {
357
+ "name": "modal",
358
+ "default": "true"
359
+ }
360
+ ]
361
+ },
362
+ {
363
+ "kind": "method",
364
+ "name": "_dispatchToggle",
365
+ "privacy": "private",
366
+ "return": {
367
+ "type": {
368
+ "text": "void"
369
+ }
370
+ },
371
+ "parameters": [
372
+ {
373
+ "name": "open",
374
+ "type": {
375
+ "text": "boolean"
376
+ }
377
+ }
378
+ ]
379
+ }
380
+ ],
381
+ "events": [
382
+ {
383
+ "name": "rc-dialog-open",
384
+ "type": {
385
+ "text": "CustomEvent"
386
+ },
387
+ "description": "Fired when the dialog opens via `showModal()` or `show()`."
388
+ },
389
+ {
390
+ "name": "rc-dialog-toggle",
391
+ "type": {
392
+ "text": "CustomEvent"
393
+ },
394
+ "description": "Fired when user/native interaction changes open state."
395
+ },
396
+ {
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 }`",
398
+ "name": "rc-dialog-request-close"
399
+ },
400
+ {
401
+ "description": "Mirrors the inner `<dialog>` cancel event when the close was not prevented. Backward-compatible alias for `rc-dialog-request-close`.",
402
+ "name": "rc-dialog-cancel"
403
+ },
404
+ {
405
+ "description": "Mirrors the inner `<dialog>` close event. `detail: { returnValue: string }`",
406
+ "name": "rc-dialog-close"
407
+ }
408
+ ],
409
+ "attributes": [
410
+ {
411
+ "name": "movable",
412
+ "type": {
413
+ "text": "boolean"
414
+ },
415
+ "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.",
417
+ "fieldName": "movable"
418
+ },
419
+ {
420
+ "name": "move-handle",
421
+ "type": {
422
+ "text": "string"
423
+ },
424
+ "default": "''",
425
+ "description": "CSS selector (within the inner `<dialog>`) for the drag handle element.",
426
+ "fieldName": "moveHandle"
427
+ },
428
+ {
429
+ "name": "move-bounds",
430
+ "type": {
431
+ "text": "'viewport' | 'parent'"
432
+ },
433
+ "default": "'viewport'",
434
+ "description": "Bounds constraint for movement.",
435
+ "fieldName": "moveBounds"
436
+ },
437
+ {
438
+ "name": "move-step",
439
+ "type": {
440
+ "text": "number"
441
+ },
442
+ "default": "4",
443
+ "description": "Keyboard arrow-key step in px for moving.",
444
+ "fieldName": "moveStep"
445
+ },
446
+ {
447
+ "name": "resize",
448
+ "type": {
449
+ "text": "'none' | 'both' | 'horizontal' | 'vertical'"
450
+ },
451
+ "default": "'none'",
452
+ "description": "Enable resizing, mirroring the CSS `resize` property values.",
453
+ "fieldName": "resize"
454
+ },
455
+ {
456
+ "name": "resize-threshold",
457
+ "type": {
458
+ "text": "number"
459
+ },
460
+ "default": "8",
461
+ "description": "Edge hit-test thickness in px for resize detection.",
462
+ "fieldName": "resizeThreshold"
463
+ },
464
+ {
465
+ "name": "resize-step",
466
+ "type": {
467
+ "text": "number"
468
+ },
469
+ "default": "4",
470
+ "description": "Keyboard arrow-key step in px for resizing.",
471
+ "fieldName": "resizeStep"
472
+ },
473
+ {
474
+ "name": "closed-by",
475
+ "type": {
476
+ "text": "'any' | 'closerequest' | 'none' | ''"
477
+ },
478
+ "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.",
480
+ "fieldName": "closedBy"
481
+ },
482
+ {
483
+ "name": "light-dismiss",
484
+ "type": {
485
+ "text": "boolean"
486
+ },
487
+ "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.",
489
+ "fieldName": "lightDismiss"
490
+ },
491
+ {
492
+ "name": "open",
493
+ "type": {
494
+ "text": "boolean"
495
+ },
496
+ "description": "Whether the inner `<dialog>` is currently open. Host writes update silently.",
497
+ "fieldName": "open"
498
+ },
499
+ {
500
+ "name": "default-open",
501
+ "type": {
502
+ "text": "boolean"
503
+ },
504
+ "description": "Initial uncontrolled open state.",
505
+ "fieldName": "defaultOpen"
506
+ }
507
+ ],
508
+ "superclass": {
509
+ "name": "LitElement",
510
+ "package": "lit"
511
+ },
512
+ "tagName": "rc-dialog",
513
+ "customElement": true
514
+ }
515
+ ],
516
+ "exports": [
517
+ {
518
+ "kind": "js",
519
+ "name": "RCDialog",
520
+ "declaration": {
521
+ "name": "RCDialog",
522
+ "module": "src/rc-dialog.ts"
523
+ }
524
+ },
525
+ {
526
+ "kind": "js",
527
+ "name": "default",
528
+ "declaration": {
529
+ "name": "RCDialog",
530
+ "module": "src/rc-dialog.ts"
531
+ }
532
+ }
533
+ ]
534
+ }
535
+ ]
536
+ }
package/dist/demo.css ADDED
@@ -0,0 +1,85 @@
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 ADDED
@@ -0,0 +1,40 @@
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
+ });