@duskmoon-dev/core 1.19.4 → 1.19.6

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.
Files changed (42) hide show
  1. package/README.md +1 -1
  2. package/dist/components/alert.css +81 -3
  3. package/dist/components/dialog.css +29 -3
  4. package/dist/components/dropdown.css +91 -0
  5. package/dist/components/fab.css +182 -0
  6. package/dist/components/index.css +1119 -232
  7. package/dist/components/loading.css +105 -0
  8. package/dist/components/modal.css +66 -4
  9. package/dist/components/navigation.css +94 -54
  10. package/dist/components/progress.css +74 -0
  11. package/dist/components/radial-progress.css +47 -0
  12. package/dist/components/skeleton.css +13 -1
  13. package/dist/components/snackbar.css +48 -18
  14. package/dist/components/swap.css +116 -0
  15. package/dist/components/toast.css +188 -34
  16. package/dist/components/tooltip.css +2 -47
  17. package/dist/esm/components/alert.js +81 -3
  18. package/dist/esm/components/dialog.js +29 -3
  19. package/dist/esm/components/dropdown.d.ts +5 -0
  20. package/dist/esm/components/dropdown.js +100 -0
  21. package/dist/esm/components/fab.d.ts +5 -0
  22. package/dist/esm/components/fab.js +191 -0
  23. package/dist/esm/components/loading.d.ts +5 -0
  24. package/dist/esm/components/loading.js +114 -0
  25. package/dist/esm/components/modal.js +66 -4
  26. package/dist/esm/components/navigation.js +94 -54
  27. package/dist/esm/components/progress.js +74 -0
  28. package/dist/esm/components/radial-progress.d.ts +5 -0
  29. package/dist/esm/components/radial-progress.js +56 -0
  30. package/dist/esm/components/skeleton.js +13 -1
  31. package/dist/esm/components/snackbar.js +48 -18
  32. package/dist/esm/components/swap.d.ts +5 -0
  33. package/dist/esm/components/swap.js +125 -0
  34. package/dist/esm/components/toast.js +188 -34
  35. package/dist/esm/components/tooltip.js +2 -47
  36. package/dist/index.css +1119 -232
  37. package/dist/index.min.css +1 -1
  38. package/dist/standalone/duskmoonui-themes.css +1 -1
  39. package/dist/standalone/duskmoonui.css +1120 -233
  40. package/dist/standalone/duskmoonui.js +25 -9
  41. package/dist/standalone/duskmoonui.mjs +25 -9
  42. package/package.json +31 -1
@@ -0,0 +1,116 @@
1
+ /**
2
+ * Swap Component Styles
3
+ * Displays one of two non-interactive state indicators.
4
+ */
5
+
6
+ @layer components {
7
+ .swap {
8
+ position: relative;
9
+ display: inline-grid;
10
+ place-items: center;
11
+ vertical-align: middle;
12
+ cursor: pointer;
13
+ user-select: none;
14
+ }
15
+
16
+ .swap-input {
17
+ position: absolute;
18
+ inset: 0;
19
+ z-index: 1;
20
+ width: 100%;
21
+ height: 100%;
22
+ margin: 0;
23
+ opacity: 0;
24
+ cursor: pointer;
25
+ }
26
+
27
+ .swap-on,
28
+ .swap-off {
29
+ grid-area: 1 / 1;
30
+ display: inline-flex;
31
+ align-items: center;
32
+ justify-content: center;
33
+ inline-size: max-content;
34
+ max-inline-size: 100%;
35
+ transition: opacity 150ms ease-out, transform 150ms ease-out;
36
+ }
37
+
38
+ .swap-on {
39
+ opacity: 0;
40
+ visibility: hidden;
41
+ pointer-events: none;
42
+ }
43
+
44
+ .swap-off {
45
+ opacity: 1;
46
+ visibility: visible;
47
+ pointer-events: none;
48
+ }
49
+
50
+ .swap-input:checked ~ .swap-on,
51
+ .swap[aria-pressed="true"] > .swap-on {
52
+ opacity: 1;
53
+ visibility: visible;
54
+ }
55
+
56
+ .swap-input:checked ~ .swap-off,
57
+ .swap[aria-pressed="true"] > .swap-off {
58
+ opacity: 0;
59
+ visibility: hidden;
60
+ }
61
+
62
+ .swap:focus-visible,
63
+ .swap:has(.swap-input:focus-visible) {
64
+ outline: none;
65
+ box-shadow: 0 0 0 3px color-mix(in oklch, currentColor 20%, transparent);
66
+ border-radius: var(--radius-sm);
67
+ }
68
+
69
+ .swap:disabled,
70
+ .swap:has(.swap-input:disabled) {
71
+ cursor: not-allowed;
72
+ opacity: 0.5;
73
+ }
74
+
75
+ .swap-input:disabled {
76
+ cursor: not-allowed;
77
+ }
78
+
79
+ .swap-rotate .swap-on {
80
+ transform: rotate(-90deg) scale(0.8);
81
+ }
82
+
83
+ .swap-rotate .swap-off {
84
+ transform: rotate(0deg) scale(1);
85
+ }
86
+
87
+ .swap-rotate .swap-input:checked ~ .swap-on,
88
+ .swap-rotate[aria-pressed="true"] > .swap-on {
89
+ transform: rotate(0deg) scale(1);
90
+ }
91
+
92
+ .swap-rotate .swap-input:checked ~ .swap-off,
93
+ .swap-rotate[aria-pressed="true"] > .swap-off {
94
+ transform: rotate(90deg) scale(0.8);
95
+ }
96
+
97
+ /* Presentation-only override. It intentionally wins over semantic state. */
98
+ .swap.swap-active > .swap-on {
99
+ opacity: 1;
100
+ visibility: visible;
101
+ transform: rotate(0deg) scale(1);
102
+ }
103
+
104
+ .swap.swap-active > .swap-off {
105
+ opacity: 0;
106
+ visibility: hidden;
107
+ transform: rotate(90deg) scale(0.8);
108
+ }
109
+
110
+ @media (prefers-reduced-motion: reduce) {
111
+ .swap-on,
112
+ .swap-off {
113
+ transition: none;
114
+ }
115
+ }
116
+ }
@@ -15,17 +15,36 @@
15
15
  pointer-events: none;
16
16
  }
17
17
 
18
+ /* Native command targets use the container as a manual popover. Reset the
19
+ user-agent popover box while preserving the existing positioning API. */
20
+ :where(.toast-container[popover]) {
21
+ inset: auto;
22
+ width: auto;
23
+ height: auto;
24
+ margin: 0;
25
+ overflow: visible;
26
+ color: inherit;
27
+ background: transparent;
28
+ border: 0;
29
+ }
30
+
31
+ .toast-container[popover]:not(:popover-open) {
32
+ display: none;
33
+ }
34
+
18
35
  /* Position Variants */
19
36
  .toast-container-top-right {
20
37
  top: 0;
21
38
  right: 0;
22
39
  align-items: flex-end;
40
+ padding-top: max(1rem, env(safe-area-inset-top));
23
41
  }
24
42
 
25
43
  .toast-container-top-left {
26
44
  top: 0;
27
45
  left: 0;
28
46
  align-items: flex-start;
47
+ padding-top: max(1rem, env(safe-area-inset-top));
29
48
  }
30
49
 
31
50
  .toast-container-top-center {
@@ -33,18 +52,21 @@
33
52
  left: 50%;
34
53
  transform: translateX(-50%);
35
54
  align-items: center;
55
+ padding-top: max(1rem, env(safe-area-inset-top));
36
56
  }
37
57
 
38
58
  .toast-container-bottom-right {
39
59
  bottom: 0;
40
60
  right: 0;
41
61
  align-items: flex-end;
62
+ padding-bottom: max(1rem, env(safe-area-inset-bottom));
42
63
  }
43
64
 
44
65
  .toast-container-bottom-left {
45
66
  bottom: 0;
46
67
  left: 0;
47
68
  align-items: flex-start;
69
+ padding-bottom: max(1rem, env(safe-area-inset-bottom));
48
70
  }
49
71
 
50
72
  .toast-container-bottom-center {
@@ -52,10 +74,20 @@
52
74
  left: 50%;
53
75
  transform: translateX(-50%);
54
76
  align-items: center;
77
+ padding-bottom: max(1rem, env(safe-area-inset-bottom));
55
78
  }
56
79
 
80
+ /* Logical aliases add RTL-aware placement without changing left/right. */
81
+ .toast-container-top-start { top: 0; inset-inline-start: 0; align-items: flex-start; }
82
+ .toast-container-top-end { top: 0; inset-inline-end: 0; align-items: flex-end; }
83
+ .toast-container-bottom-start { bottom: 0; inset-inline-start: 0; align-items: flex-start; }
84
+ .toast-container-bottom-end { bottom: 0; inset-inline-end: 0; align-items: flex-end; }
85
+
57
86
  /* Base Toast */
58
87
  .toast {
88
+ --_toast-accent-color: var(--color-primary);
89
+
90
+ position: relative;
59
91
  display: flex;
60
92
  align-items: flex-start;
61
93
  gap: 0.75rem;
@@ -86,9 +118,28 @@
86
118
  /* Toast Open State */
87
119
  .toast.toast-open,
88
120
  .toast.show,
89
- .toast-show {
121
+ .toast.toast-show {
122
+ opacity: 1;
123
+ transform: translateX(0) translateY(0);
124
+ visibility: visible;
125
+ pointer-events: auto;
126
+ }
127
+
128
+ /* A closed item cannot intercept input. Consumers should also use hidden,
129
+ inert, or unmounting when removing it from the accessibility tree. */
130
+ .toast:not(.toast-open):not(.show):not(.toast-show),
131
+ .toast[hidden],
132
+ .toast[inert],
133
+ .toast[aria-hidden="true"] {
134
+ pointer-events: none;
135
+ visibility: hidden;
136
+ }
137
+
138
+ .toast-container[popover]:popover-open .toast {
90
139
  opacity: 1;
91
140
  transform: translateX(0) translateY(0);
141
+ visibility: visible;
142
+ pointer-events: auto;
92
143
  }
93
144
 
94
145
  /* Toast Icon */
@@ -139,7 +190,7 @@
139
190
  cursor: pointer;
140
191
  transition: background-color 150ms ease-in-out, color 150ms ease-in-out;
141
192
  flex-shrink: 0;
142
- margin-left: auto;
193
+ margin-inline-start: auto;
143
194
  }
144
195
 
145
196
  .toast-close:hover {
@@ -157,10 +208,46 @@
157
208
  display: flex;
158
209
  gap: 0.5rem;
159
210
  margin-top: 0.5rem;
211
+ flex-wrap: wrap;
212
+ }
213
+
214
+ .toast-action {
215
+ display: inline-flex;
216
+ align-items: center;
217
+ justify-content: center;
218
+ width: fit-content;
219
+ min-height: 2rem;
220
+ padding: 0.375rem 0.75rem;
221
+ color: var(--color-primary);
222
+ font-size: 0.875rem;
223
+ font-weight: 500;
224
+ background-color: transparent;
225
+ border: 1px solid currentColor;
226
+ border-radius: var(--radius-sm);
227
+ cursor: pointer;
228
+ }
229
+
230
+ .toast-action:hover {
231
+ background-color: color-mix(in oklch, currentColor 10%, transparent);
232
+ }
233
+
234
+ .toast-action:focus-visible {
235
+ outline: none;
236
+ box-shadow: 0 0 0 3px color-mix(in oklch, currentColor 20%, transparent);
160
237
  }
161
238
 
162
239
  /* Type Variants */
240
+ .toast-accent {
241
+ --_toast-accent-color: var(--color-accent);
242
+ border-color: var(--color-accent);
243
+ }
244
+
245
+ .toast-accent .toast-icon {
246
+ color: var(--color-accent);
247
+ }
248
+
163
249
  .toast-info {
250
+ --_toast-accent-color: var(--color-info);
164
251
  border-color: var(--color-info);
165
252
  }
166
253
 
@@ -169,6 +256,7 @@
169
256
  }
170
257
 
171
258
  .toast-success {
259
+ --_toast-accent-color: var(--color-success);
172
260
  border-color: var(--color-success);
173
261
  }
174
262
 
@@ -177,6 +265,7 @@
177
265
  }
178
266
 
179
267
  .toast-warning {
268
+ --_toast-accent-color: var(--color-warning);
180
269
  border-color: var(--color-warning);
181
270
  }
182
271
 
@@ -185,6 +274,7 @@
185
274
  }
186
275
 
187
276
  .toast-error {
277
+ --_toast-accent-color: var(--color-error);
188
278
  border-color: var(--color-error);
189
279
  }
190
280
 
@@ -193,6 +283,7 @@
193
283
  }
194
284
 
195
285
  .toast-primary {
286
+ --_toast-accent-color: var(--color-primary);
196
287
  border-color: var(--color-primary);
197
288
  }
198
289
 
@@ -201,6 +292,7 @@
201
292
  }
202
293
 
203
294
  .toast-secondary {
295
+ --_toast-accent-color: var(--color-secondary);
204
296
  border-color: var(--color-secondary);
205
297
  }
206
298
 
@@ -209,6 +301,7 @@
209
301
  }
210
302
 
211
303
  .toast-tertiary {
304
+ --_toast-accent-color: var(--color-tertiary);
212
305
  border-color: var(--color-tertiary);
213
306
  }
214
307
 
@@ -216,15 +309,8 @@
216
309
  color: var(--color-tertiary);
217
310
  }
218
311
 
219
- .toast-accent {
220
- border-color: var(--color-accent);
221
- }
222
-
223
- .toast-accent .toast-icon {
224
- color: var(--color-accent);
225
- }
226
-
227
312
  .toast-neutral {
313
+ --_toast-accent-color: var(--color-neutral);
228
314
  border-color: var(--color-neutral);
229
315
  }
230
316
 
@@ -233,6 +319,7 @@
233
319
  }
234
320
 
235
321
  .toast-base {
322
+ --_toast-accent-color: var(--color-base-content);
236
323
  border-color: var(--color-base-content);
237
324
  }
238
325
 
@@ -241,58 +328,58 @@
241
328
  }
242
329
 
243
330
  /* Filled Variants */
331
+ .toast-filled.toast-accent {
332
+ background-color: var(--color-accent);
333
+ border-color: transparent;
334
+ color: var(--color-accent-content);
335
+ }
336
+
244
337
  .toast-filled.toast-info {
245
- background-color: var(--color-info-container);
338
+ background-color: var(--color-info);
246
339
  border-color: transparent;
247
- color: var(--color-on-info-container);
340
+ color: var(--color-info-content);
248
341
  }
249
342
 
250
343
  .toast-filled.toast-success {
251
- background-color: var(--color-success-container);
344
+ background-color: var(--color-success);
252
345
  border-color: transparent;
253
- color: var(--color-on-success-container);
346
+ color: var(--color-success-content);
254
347
  }
255
348
 
256
349
  .toast-filled.toast-warning {
257
- background-color: var(--color-warning-container);
350
+ background-color: var(--color-warning);
258
351
  border-color: transparent;
259
- color: var(--color-on-warning-container);
352
+ color: var(--color-warning-content);
260
353
  }
261
354
 
262
355
  .toast-filled.toast-error {
263
- background-color: var(--color-error-container);
356
+ background-color: var(--color-error);
264
357
  border-color: transparent;
265
- color: var(--color-on-error-container);
358
+ color: var(--color-error-content);
266
359
  }
267
360
 
268
361
  .toast-filled.toast-primary {
269
- background-color: var(--color-primary-container);
362
+ background-color: var(--color-primary);
270
363
  border-color: transparent;
271
- color: var(--color-on-primary-container);
364
+ color: var(--color-primary-content);
272
365
  }
273
366
 
274
367
  .toast-filled.toast-secondary {
275
- background-color: var(--color-secondary-container);
368
+ background-color: var(--color-secondary);
276
369
  border-color: transparent;
277
- color: var(--color-on-secondary-container);
370
+ color: var(--color-secondary-content);
278
371
  }
279
372
 
280
373
  .toast-filled.toast-tertiary {
281
- background-color: var(--color-tertiary-container);
374
+ background-color: var(--color-tertiary);
282
375
  border-color: transparent;
283
- color: var(--color-on-tertiary-container);
284
- }
285
-
286
- .toast-filled.toast-accent {
287
- background-color: color-mix(in oklch, var(--color-accent) 15%, var(--color-surface));
288
- border-color: transparent;
289
- color: var(--color-on-surface);
376
+ color: var(--color-tertiary-content);
290
377
  }
291
378
 
292
379
  .toast-filled.toast-neutral {
293
- background-color: color-mix(in oklch, var(--color-neutral) 15%, var(--color-surface));
380
+ background-color: var(--color-neutral);
294
381
  border-color: transparent;
295
- color: var(--color-on-surface);
382
+ color: var(--color-neutral-content);
296
383
  }
297
384
 
298
385
  .toast-filled.toast-base {
@@ -305,8 +392,16 @@
305
392
  .toast-title and .toast-message have explicit color rules that would otherwise
306
393
  override the filled variant's inherited on-container color. */
307
394
  .toast-filled .toast-title,
308
- .toast-filled .toast-message {
395
+ .toast-filled .toast-message,
396
+ .toast-filled .toast-icon,
397
+ .toast-filled .toast-close,
398
+ .toast-filled .toast-action {
399
+ color: inherit;
400
+ }
401
+
402
+ .toast-filled .toast-close:hover {
309
403
  color: inherit;
404
+ background-color: color-mix(in oklch, currentColor 12%, transparent);
310
405
  }
311
406
 
312
407
  /* Ghost Variant */
@@ -315,6 +410,7 @@
315
410
  border-color: transparent;
316
411
  }
317
412
 
413
+ .toast-ghost.toast-accent { color: var(--color-accent); }
318
414
  .toast-ghost.toast-primary { color: var(--color-primary); }
319
415
  .toast-ghost.toast-secondary { color: var(--color-secondary); }
320
416
  .toast-ghost.toast-tertiary { color: var(--color-tertiary); }
@@ -322,7 +418,6 @@
322
418
  .toast-ghost.toast-success { color: var(--color-success); }
323
419
  .toast-ghost.toast-warning { color: var(--color-warning); }
324
420
  .toast-ghost.toast-error { color: var(--color-error); }
325
- .toast-ghost.toast-accent { color: var(--color-accent); }
326
421
  .toast-ghost.toast-neutral { color: var(--color-neutral); }
327
422
  .toast-ghost.toast-base { color: var(--color-base-content); }
328
423
 
@@ -331,6 +426,49 @@
331
426
  color: inherit;
332
427
  }
333
428
 
429
+ /* Size and density variants retained by the public API. */
430
+ .toast-sm {
431
+ width: 18rem;
432
+ padding: 0.75rem;
433
+ }
434
+
435
+ .toast-lg {
436
+ width: 26rem;
437
+ padding: 1.25rem;
438
+ }
439
+
440
+ .toast-compact {
441
+ padding: 0.75rem;
442
+ gap: 0.5rem;
443
+ }
444
+
445
+ .toast-compact .toast-icon {
446
+ width: 1.25rem;
447
+ height: 1.25rem;
448
+ font-size: 1rem;
449
+ }
450
+
451
+ .toast-compact .toast-title { font-size: 0.8125rem; }
452
+ .toast-compact .toast-message { font-size: 0.8125rem; }
453
+
454
+ /* Accent edge and stacked presentation. */
455
+ .toast-accent::before {
456
+ content: "";
457
+ position: absolute;
458
+ inset-block: 0;
459
+ inset-inline-start: 0;
460
+ width: 0.25rem;
461
+ background-color: var(--_toast-accent-color);
462
+ border-start-start-radius: var(--radius-md);
463
+ border-end-start-radius: var(--radius-md);
464
+ }
465
+
466
+ .toast-container-stacked .toast:not(:first-child) {
467
+ margin-top: -0.75rem;
468
+ transform: scale(0.97);
469
+ opacity: 0.9;
470
+ }
471
+
334
472
  /* Progress Bar (for auto-dismiss) */
335
473
  .toast-progress {
336
474
  position: absolute;
@@ -361,5 +499,21 @@
361
499
  .toast-progress {
362
500
  animation: none;
363
501
  }
502
+
503
+ .toast-container { scroll-behavior: auto; }
504
+ }
505
+
506
+ @media (max-width: 40rem) {
507
+ .toast-container[popover] {
508
+ inset-inline: 0;
509
+ width: 100%;
510
+ transform: none;
511
+ align-items: stretch;
512
+ }
513
+
514
+ .toast {
515
+ width: 100%;
516
+ max-width: 100%;
517
+ }
364
518
  }
365
519
  }
@@ -76,53 +76,8 @@
76
76
  position-area: right;
77
77
  }
78
78
 
79
- /* ========================================
80
- * Arrow (preferred position only; may be wrong after flip)
81
- * ======================================== */
82
-
83
- .tooltip[popover]::before {
84
- content: '';
85
- position: absolute;
86
- width: 0;
87
- height: 0;
88
- border: 0.375rem solid transparent;
89
- }
90
-
91
- .tooltip-top[popover]::before,
92
- .tooltip[popover]:not(.tooltip-bottom):not(.tooltip-left):not(.tooltip-right)::before {
93
- top: 100%;
94
- left: 50%;
95
- transform: translateX(-50%);
96
- border-top-color: var(--tooltip-bg);
97
- }
98
-
99
- .tooltip-bottom[popover]::before {
100
- bottom: 100%;
101
- top: auto;
102
- left: 50%;
103
- transform: translateX(-50%);
104
- border-bottom-color: var(--tooltip-bg);
105
- border-top-color: transparent;
106
- }
107
-
108
- .tooltip-left[popover]::before {
109
- left: 100%;
110
- top: 50%;
111
- bottom: auto;
112
- transform: translateY(-50%);
113
- border-left-color: var(--tooltip-bg);
114
- border-top-color: transparent;
115
- }
116
-
117
- .tooltip-right[popover]::before {
118
- right: 100%;
119
- left: auto;
120
- top: 50%;
121
- bottom: auto;
122
- transform: translateY(-50%);
123
- border-right-color: var(--tooltip-bg);
124
- border-top-color: transparent;
125
- }
79
+ /* Automatic placement can flip independently of the preferred side. The
80
+ core stays arrowless instead of showing a misleading arrow. */
126
81
 
127
82
  /* ========================================
128
83
  * Color variants