@duskmoon-dev/core 1.4.0 → 1.5.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.
@@ -39,12 +39,24 @@
39
39
  box-shadow: 0 0 0 3px color-mix(in oklch, var(--color-primary) 10%, transparent);
40
40
  }
41
41
 
42
- .tree-select-trigger:disabled {
42
+ .tree-select-trigger:disabled,
43
+ .tree-select-trigger[aria-disabled="true"] {
43
44
  cursor: not-allowed;
44
45
  opacity: 0.5;
45
46
  background-color: var(--color-surface-container);
46
47
  }
47
48
 
49
+ /* Support for div-based trigger (when using clear button) */
50
+ div.tree-select-trigger {
51
+ user-select: none;
52
+ }
53
+
54
+ div.tree-select-trigger:focus-visible {
55
+ outline: none;
56
+ border-color: var(--color-primary);
57
+ box-shadow: 0 0 0 3px color-mix(in oklch, var(--color-primary) 10%, transparent);
58
+ }
59
+
48
60
  /* Value Display */
49
61
  .tree-select-value {
50
62
  flex: 1;
@@ -105,6 +117,11 @@
105
117
  background-color: var(--color-surface-container-high);
106
118
  }
107
119
 
120
+ .tree-select-clear svg {
121
+ width: 1rem;
122
+ height: 1rem;
123
+ }
124
+
108
125
  /* Tree Select Dropdown */
109
126
  .tree-select-dropdown {
110
127
  position: absolute;
@@ -127,9 +144,10 @@
127
144
  display: block;
128
145
  }
129
146
 
130
- /* Popover API Support - Browser handles visibility, JS handles positioning */
147
+ /* Popover API Support */
131
148
  .tree-select-dropdown[popover] {
132
- /* Reset browser defaults - positioning handled by JavaScript */
149
+ /* Reset browser defaults for proper positioning */
150
+ position: absolute;
133
151
  inset: unset;
134
152
  margin: 0;
135
153
  border: 1px solid var(--color-outline-variant);
@@ -139,6 +157,21 @@
139
157
  display: block;
140
158
  }
141
159
 
160
+ /* CSS Anchor Positioning for modern browsers */
161
+ @supports (anchor-name: --tree-select) {
162
+ .tree-select {
163
+ anchor-name: --tree-select;
164
+ }
165
+
166
+ .tree-select-dropdown[popover] {
167
+ position-anchor: --tree-select;
168
+ top: anchor(bottom);
169
+ left: anchor(left);
170
+ right: anchor(right);
171
+ position-try-fallbacks: flip-block;
172
+ }
173
+ }
174
+
142
175
  /* Search Input in Dropdown */
143
176
  .tree-select-search {
144
177
  display: flex;
@@ -15,6 +15,12 @@ export const css = `/**
15
15
  padding: 0 1rem;
16
16
  background-color: var(--color-surface);
17
17
  color: var(--color-on-surface);
18
+ box-shadow: 0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1);
19
+ }
20
+
21
+ /* Static App Bar (default) */
22
+ .appbar-static {
23
+ position: static;
18
24
  }
19
25
 
20
26
  /* Fixed App Bar */
@@ -33,19 +39,47 @@ export const css = `/**
33
39
  z-index: 1000;
34
40
  }
35
41
 
36
- /* App Bar with Shadow */
42
+ /* Top App Bar (default) */
43
+ .appbar-top {
44
+ top: 0;
45
+ }
46
+
47
+ /* Bottom App Bar */
48
+ .appbar-bottom {
49
+ position: fixed;
50
+ bottom: 0;
51
+ left: 0;
52
+ right: 0;
53
+ top: auto;
54
+ z-index: 1000;
55
+ }
56
+
57
+ /* App Bar with Shadow (elevated) */
37
58
  .appbar-elevated {
38
59
  box-shadow: 0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1);
39
60
  }
40
61
 
62
+ /* Flat App Bar (no shadow) */
63
+ .appbar-flat {
64
+ box-shadow: none;
65
+ }
66
+
41
67
  /* App Bar with Border */
42
68
  .appbar-bordered {
43
69
  border-bottom: 1px solid var(--color-outline-variant);
70
+ box-shadow: none;
44
71
  }
45
72
 
46
73
  /* Transparent App Bar */
47
74
  .appbar-transparent {
48
75
  background-color: transparent;
76
+ box-shadow: none;
77
+ }
78
+
79
+ /* Backdrop Blur */
80
+ .appbar-blur {
81
+ backdrop-filter: blur(8px);
82
+ -webkit-backdrop-filter: blur(8px);
49
83
  }
50
84
 
51
85
  /* App Bar Navigation Icon */
@@ -168,6 +202,114 @@ export const css = `/**
168
202
  font-size: 1.5rem;
169
203
  }
170
204
 
205
+ /* Compact Size */
206
+ .appbar-compact {
207
+ min-height: 3rem;
208
+ padding: 0 0.75rem;
209
+ }
210
+
211
+ .appbar-compact .appbar-title,
212
+ .appbar-compact .appbar-heading {
213
+ font-size: 1rem;
214
+ line-height: 1.5rem;
215
+ }
216
+
217
+ .appbar-compact .appbar-nav,
218
+ .appbar-compact .appbar-action,
219
+ .appbar-compact .appbar-back {
220
+ width: 2rem;
221
+ height: 2rem;
222
+ }
223
+
224
+ /* Comfortable Size */
225
+ .appbar-comfortable {
226
+ min-height: 5rem;
227
+ padding: 0 1.5rem;
228
+ }
229
+
230
+ .appbar-comfortable .appbar-title,
231
+ .appbar-comfortable .appbar-heading {
232
+ font-size: 1.5rem;
233
+ line-height: 2rem;
234
+ }
235
+
236
+ /* Section Classes */
237
+ .appbar-leading {
238
+ display: flex;
239
+ align-items: center;
240
+ gap: 0.25rem;
241
+ flex-shrink: 0;
242
+ }
243
+
244
+ .appbar-trailing {
245
+ display: flex;
246
+ align-items: center;
247
+ gap: 0.25rem;
248
+ flex-shrink: 0;
249
+ margin-left: auto;
250
+ }
251
+
252
+ /* Heading Text */
253
+ .appbar-heading {
254
+ font-size: 1.25rem;
255
+ font-weight: 500;
256
+ line-height: 1.75rem;
257
+ margin: 0;
258
+ overflow: hidden;
259
+ text-overflow: ellipsis;
260
+ white-space: nowrap;
261
+ }
262
+
263
+ /* Back Button */
264
+ .appbar-back {
265
+ display: flex;
266
+ align-items: center;
267
+ justify-content: center;
268
+ width: 2.5rem;
269
+ height: 2.5rem;
270
+ color: var(--color-on-surface);
271
+ background-color: transparent;
272
+ border: none;
273
+ border-radius: 50%;
274
+ cursor: pointer;
275
+ transition: background-color 150ms ease-in-out;
276
+ flex-shrink: 0;
277
+ }
278
+
279
+ .appbar-back:hover {
280
+ background-color: var(--color-surface-container);
281
+ }
282
+
283
+ .appbar-back:focus-visible {
284
+ outline: 2px solid var(--color-primary);
285
+ outline-offset: 2px;
286
+ }
287
+
288
+ /* Search Input (direct on element) */
289
+ .appbar .appbar-search,
290
+ input.appbar-search {
291
+ flex: 1;
292
+ max-width: 32rem;
293
+ padding: 0.5rem 1rem;
294
+ font-size: 0.875rem;
295
+ color: var(--color-on-surface);
296
+ background-color: var(--color-surface-container);
297
+ border: none;
298
+ border-radius: 9999px;
299
+ transition: background-color 150ms ease-in-out;
300
+ }
301
+
302
+ .appbar .appbar-search:focus,
303
+ input.appbar-search:focus {
304
+ outline: none;
305
+ background-color: var(--color-surface-container-high);
306
+ }
307
+
308
+ .appbar .appbar-search::placeholder,
309
+ input.appbar-search::placeholder {
310
+ color: var(--color-on-surface-variant);
311
+ }
312
+
171
313
  /* Color Variants */
172
314
  .appbar-primary {
173
315
  background-color: var(--color-primary);
@@ -206,10 +348,53 @@ export const css = `/**
206
348
  color: var(--color-on-secondary-container);
207
349
  }
208
350
 
351
+ .appbar-secondary .appbar-subtitle {
352
+ color: var(--color-on-secondary);
353
+ opacity: 0.8;
354
+ }
355
+
356
+ .appbar-tertiary {
357
+ background-color: var(--color-tertiary);
358
+ color: var(--color-on-tertiary);
359
+ }
360
+
361
+ .appbar-tertiary .appbar-nav,
362
+ .appbar-tertiary .appbar-action {
363
+ color: var(--color-on-tertiary);
364
+ }
365
+
366
+ .appbar-tertiary .appbar-nav:hover,
367
+ .appbar-tertiary .appbar-action:hover {
368
+ background-color: var(--color-tertiary-container);
369
+ color: var(--color-on-tertiary-container);
370
+ }
371
+
372
+ .appbar-tertiary .appbar-subtitle {
373
+ color: var(--color-on-tertiary);
374
+ opacity: 0.8;
375
+ }
376
+
377
+ /* Surface Variants */
209
378
  .appbar-surface {
379
+ background-color: var(--color-surface);
380
+ }
381
+
382
+ .appbar-surface-container {
210
383
  background-color: var(--color-surface-container);
211
384
  }
212
385
 
386
+ .appbar-surface-container-low {
387
+ background-color: var(--color-surface-container-low);
388
+ }
389
+
390
+ .appbar-surface-container-high {
391
+ background-color: var(--color-surface-container-high);
392
+ }
393
+
394
+ .appbar-surface-container-highest {
395
+ background-color: var(--color-surface-container-highest);
396
+ }
397
+
213
398
  /* Center Title */
214
399
  .appbar-center {
215
400
  justify-content: space-between;
@@ -0,0 +1,425 @@
1
+ // Auto-generated from cascader.css
2
+ export const css = `/**
3
+ * Cascader Component Styles
4
+ * DuskMoonUI - Multi-level dropdown selection with horizontal panels
5
+ */
6
+
7
+ @layer components {
8
+ /* Base Cascader */
9
+ .cascader {
10
+ position: relative;
11
+ display: inline-flex;
12
+ flex-direction: column;
13
+ width: 100%;
14
+ }
15
+
16
+ /* Cascader Trigger */
17
+ .cascader-trigger {
18
+ display: flex;
19
+ align-items: center;
20
+ justify-content: space-between;
21
+ width: 100%;
22
+ padding: 0.75rem 1rem;
23
+ font-size: 1rem;
24
+ line-height: 1.5rem;
25
+ color: var(--color-on-surface);
26
+ background-color: var(--color-surface);
27
+ border: 1px solid var(--color-outline);
28
+ border-radius: 0.5rem;
29
+ cursor: pointer;
30
+ transition: border-color 150ms ease-in-out, box-shadow 150ms ease-in-out;
31
+ }
32
+
33
+ .cascader-trigger:hover:not(:disabled) {
34
+ border-color: var(--color-on-surface-variant);
35
+ }
36
+
37
+ .cascader-trigger:focus {
38
+ outline: none;
39
+ border-color: var(--color-primary);
40
+ box-shadow: 0 0 0 3px color-mix(in oklch, var(--color-primary) 10%, transparent);
41
+ }
42
+
43
+ .cascader-trigger:disabled {
44
+ cursor: not-allowed;
45
+ opacity: 0.5;
46
+ background-color: var(--color-surface-container);
47
+ }
48
+
49
+ /* Value Display */
50
+ .cascader-value {
51
+ flex: 1;
52
+ display: flex;
53
+ align-items: center;
54
+ gap: 0.5rem;
55
+ overflow: hidden;
56
+ text-overflow: ellipsis;
57
+ white-space: nowrap;
58
+ color: var(--color-on-surface);
59
+ }
60
+
61
+ /* Placeholder */
62
+ .cascader-placeholder {
63
+ color: var(--color-on-surface-variant);
64
+ }
65
+
66
+ /* Path Display (breadcrumb-style) */
67
+ .cascader-path {
68
+ display: flex;
69
+ align-items: center;
70
+ gap: 0.25rem;
71
+ overflow: hidden;
72
+ text-overflow: ellipsis;
73
+ white-space: nowrap;
74
+ }
75
+
76
+ .cascader-path-separator {
77
+ color: var(--color-on-surface-variant);
78
+ font-size: 0.875rem;
79
+ }
80
+
81
+ /* Dropdown Arrow */
82
+ .cascader-arrow {
83
+ display: flex;
84
+ align-items: center;
85
+ justify-content: center;
86
+ width: 1.25rem;
87
+ height: 1.25rem;
88
+ color: var(--color-on-surface-variant);
89
+ flex-shrink: 0;
90
+ transition: transform 150ms ease-in-out;
91
+ }
92
+
93
+ .cascader-open .cascader-arrow {
94
+ transform: rotate(180deg);
95
+ }
96
+
97
+ /* Clear Button */
98
+ .cascader-clear {
99
+ display: flex;
100
+ align-items: center;
101
+ justify-content: center;
102
+ width: 1.25rem;
103
+ height: 1.25rem;
104
+ padding: 0;
105
+ color: var(--color-on-surface-variant);
106
+ background-color: transparent;
107
+ border: none;
108
+ border-radius: 50%;
109
+ cursor: pointer;
110
+ flex-shrink: 0;
111
+ transition: background-color 150ms ease-in-out;
112
+ }
113
+
114
+ .cascader-clear:hover {
115
+ background-color: var(--color-surface-container-high);
116
+ }
117
+
118
+ /* Cascader Dropdown */
119
+ .cascader-dropdown {
120
+ position: absolute;
121
+ top: 100%;
122
+ left: 0;
123
+ z-index: 50;
124
+ display: none;
125
+ margin-top: 0.25rem;
126
+ background-color: var(--color-surface);
127
+ border: 1px solid var(--color-outline-variant);
128
+ border-radius: 0.5rem;
129
+ box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
130
+ overflow: hidden;
131
+ }
132
+
133
+ .cascader-open .cascader-dropdown {
134
+ display: flex;
135
+ }
136
+
137
+ /* Popover API Support */
138
+ .cascader-dropdown[popover] {
139
+ inset: unset;
140
+ margin: 0;
141
+ border: 1px solid var(--color-outline-variant);
142
+ }
143
+
144
+ .cascader-dropdown[popover]:popover-open {
145
+ display: flex;
146
+ }
147
+
148
+ /* CSS Anchor Positioning for modern browsers */
149
+ @supports (anchor-name: --anchor) {
150
+ .cascader-trigger {
151
+ anchor-name: --cascader-anchor;
152
+ }
153
+
154
+ .cascader-dropdown[popover] {
155
+ position-anchor: --cascader-anchor;
156
+ top: anchor(bottom);
157
+ left: anchor(left);
158
+ margin-top: 0.25rem;
159
+ position-try-fallbacks: flip-block;
160
+ }
161
+ }
162
+
163
+ /* Fallback for browsers without anchor positioning */
164
+ @supports not (anchor-name: --anchor) {
165
+ .cascader {
166
+ position: relative;
167
+ }
168
+
169
+ .cascader-dropdown[popover]:popover-open {
170
+ position: absolute;
171
+ top: 100%;
172
+ left: 0;
173
+ margin-top: 0.25rem;
174
+ }
175
+ }
176
+
177
+ /* Panels Container (horizontal layout) */
178
+ .cascader-panels {
179
+ display: flex;
180
+ max-height: 16rem;
181
+ }
182
+
183
+ /* Individual Panel */
184
+ .cascader-panel {
185
+ display: flex;
186
+ flex-direction: column;
187
+ min-width: 10rem;
188
+ max-width: 14rem;
189
+ overflow-y: auto;
190
+ border-right: 1px solid var(--color-outline-variant);
191
+ }
192
+
193
+ .cascader-panel:last-child {
194
+ border-right: none;
195
+ }
196
+
197
+ /* Panel Header (optional) */
198
+ .cascader-panel-header {
199
+ padding: 0.5rem 0.75rem;
200
+ font-size: 0.75rem;
201
+ font-weight: 600;
202
+ color: var(--color-on-surface-variant);
203
+ text-transform: uppercase;
204
+ letter-spacing: 0.05em;
205
+ background-color: var(--color-surface-container);
206
+ border-bottom: 1px solid var(--color-outline-variant);
207
+ }
208
+
209
+ /* Panel Options */
210
+ .cascader-options {
211
+ display: flex;
212
+ flex-direction: column;
213
+ padding: 0.25rem;
214
+ flex: 1;
215
+ overflow-y: auto;
216
+ }
217
+
218
+ /* Cascader Option */
219
+ .cascader-option {
220
+ display: flex;
221
+ align-items: center;
222
+ justify-content: space-between;
223
+ gap: 0.5rem;
224
+ padding: 0.5rem 0.75rem;
225
+ font-size: 0.875rem;
226
+ color: var(--color-on-surface);
227
+ background-color: transparent;
228
+ border: none;
229
+ border-radius: 0.375rem;
230
+ cursor: pointer;
231
+ text-align: left;
232
+ width: 100%;
233
+ transition: background-color 150ms ease-in-out;
234
+ }
235
+
236
+ .cascader-option:hover {
237
+ background-color: var(--color-surface-container);
238
+ }
239
+
240
+ .cascader-option-active {
241
+ background-color: var(--color-surface-container-high);
242
+ }
243
+
244
+ .cascader-option-selected {
245
+ background-color: var(--color-primary-container);
246
+ color: var(--color-on-primary-container);
247
+ }
248
+
249
+ .cascader-option-selected:hover {
250
+ background-color: color-mix(in oklch, var(--color-primary-container), black 5%);
251
+ }
252
+
253
+ .cascader-option-disabled {
254
+ opacity: 0.5;
255
+ cursor: not-allowed;
256
+ }
257
+
258
+ .cascader-option-disabled:hover {
259
+ background-color: transparent;
260
+ }
261
+
262
+ /* Option Label */
263
+ .cascader-option-label {
264
+ flex: 1;
265
+ overflow: hidden;
266
+ text-overflow: ellipsis;
267
+ white-space: nowrap;
268
+ }
269
+
270
+ /* Option Arrow (indicates has children) */
271
+ .cascader-option-arrow {
272
+ display: flex;
273
+ align-items: center;
274
+ justify-content: center;
275
+ width: 1rem;
276
+ height: 1rem;
277
+ color: var(--color-on-surface-variant);
278
+ flex-shrink: 0;
279
+ }
280
+
281
+ .cascader-option-selected .cascader-option-arrow {
282
+ color: var(--color-on-primary-container);
283
+ }
284
+
285
+ /* Search Input */
286
+ .cascader-search {
287
+ display: flex;
288
+ padding: 0.5rem;
289
+ border-bottom: 1px solid var(--color-outline-variant);
290
+ }
291
+
292
+ .cascader-search-input {
293
+ flex: 1;
294
+ padding: 0.5rem 0.75rem;
295
+ font-size: 0.875rem;
296
+ color: var(--color-on-surface);
297
+ background-color: var(--color-surface-container);
298
+ border: none;
299
+ border-radius: 0.375rem;
300
+ outline: none;
301
+ }
302
+
303
+ .cascader-search-input:focus {
304
+ background-color: var(--color-surface-container-high);
305
+ }
306
+
307
+ .cascader-search-input::placeholder {
308
+ color: var(--color-on-surface-variant);
309
+ }
310
+
311
+ /* Empty State */
312
+ .cascader-empty {
313
+ padding: 1.5rem;
314
+ text-align: center;
315
+ color: var(--color-on-surface-variant);
316
+ font-size: 0.875rem;
317
+ }
318
+
319
+ /* Size Variants */
320
+ .cascader-sm .cascader-trigger {
321
+ padding: 0.5rem 0.75rem;
322
+ font-size: 0.875rem;
323
+ border-radius: 0.375rem;
324
+ }
325
+
326
+ .cascader-sm .cascader-panel {
327
+ min-width: 8rem;
328
+ max-width: 12rem;
329
+ }
330
+
331
+ .cascader-sm .cascader-option {
332
+ padding: 0.375rem 0.5rem;
333
+ font-size: 0.8125rem;
334
+ }
335
+
336
+ .cascader-lg .cascader-trigger {
337
+ padding: 1rem 1.25rem;
338
+ font-size: 1.125rem;
339
+ border-radius: 0.625rem;
340
+ }
341
+
342
+ .cascader-lg .cascader-panel {
343
+ min-width: 12rem;
344
+ max-width: 16rem;
345
+ }
346
+
347
+ .cascader-lg .cascader-option {
348
+ padding: 0.625rem 1rem;
349
+ font-size: 1rem;
350
+ }
351
+
352
+ /* Outlined Variant (Default) */
353
+ .cascader-outlined .cascader-trigger {
354
+ background-color: var(--color-surface);
355
+ border: 1px solid var(--color-outline);
356
+ }
357
+
358
+ /* Filled Variant */
359
+ .cascader-filled .cascader-trigger {
360
+ background-color: var(--color-surface-container);
361
+ border: none;
362
+ border-bottom: 2px solid var(--color-outline);
363
+ border-radius: 0.5rem 0.5rem 0 0;
364
+ }
365
+
366
+ .cascader-filled .cascader-trigger:focus {
367
+ border-bottom-color: var(--color-primary);
368
+ box-shadow: none;
369
+ }
370
+
371
+ /* Error State */
372
+ .cascader-error .cascader-trigger {
373
+ border-color: var(--color-error);
374
+ }
375
+
376
+ .cascader-error .cascader-trigger:focus {
377
+ border-color: var(--color-error);
378
+ box-shadow: 0 0 0 3px color-mix(in oklch, var(--color-error) 10%, transparent);
379
+ }
380
+
381
+ /* Disabled State */
382
+ .cascader-disabled .cascader-trigger {
383
+ cursor: not-allowed;
384
+ opacity: 0.5;
385
+ background-color: var(--color-surface-container);
386
+ }
387
+
388
+ /* Loading State */
389
+ .cascader-loading .cascader-trigger {
390
+ cursor: wait;
391
+ }
392
+
393
+ .cascader-spinner {
394
+ display: inline-block;
395
+ width: 1rem;
396
+ height: 1rem;
397
+ border: 2px solid var(--color-outline);
398
+ border-top-color: var(--color-primary);
399
+ border-radius: 50%;
400
+ animation: cascader-spin 0.8s linear infinite;
401
+ }
402
+
403
+ @keyframes cascader-spin {
404
+ to { transform: rotate(360deg); }
405
+ }
406
+
407
+ /* Reduce Motion */
408
+ @media (prefers-reduced-motion: reduce) {
409
+ .cascader-trigger,
410
+ .cascader-arrow,
411
+ .cascader-option,
412
+ .cascader-clear {
413
+ transition: none;
414
+ }
415
+ .cascader-spinner {
416
+ animation: none;
417
+ }
418
+ }
419
+ }
420
+ `;
421
+
422
+ const sheet = new CSSStyleSheet();
423
+ sheet.replaceSync(css);
424
+ export const styles = sheet;
425
+ export default sheet;