@duskmoon-dev/core 1.4.0 → 1.6.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.
@@ -4,7 +4,84 @@
4
4
  */
5
5
 
6
6
  @layer components {
7
- /* Base Textarea */
7
+ /* ============================================
8
+ * TEXTAREA CONTAINER
9
+ * ============================================ */
10
+
11
+ .textarea-container {
12
+ position: relative;
13
+ display: flex;
14
+ flex-direction: column;
15
+ gap: 0.25rem;
16
+ width: 100%;
17
+ }
18
+
19
+ /* ============================================
20
+ * TEXTAREA LABEL
21
+ * ============================================ */
22
+
23
+ .textarea-label {
24
+ display: block;
25
+ font-size: 0.875rem;
26
+ font-weight: 500;
27
+ line-height: 1.25rem;
28
+ color: var(--color-on-surface);
29
+ margin-bottom: 0.25rem;
30
+ }
31
+
32
+ /* Floating Label */
33
+ .textarea-label-floating {
34
+ position: absolute;
35
+ top: 0.75rem;
36
+ left: 1rem;
37
+ font-size: 1rem;
38
+ font-weight: 400;
39
+ color: var(--color-on-surface-variant);
40
+ pointer-events: none;
41
+ transition: all 150ms ease-in-out;
42
+ transform-origin: left top;
43
+ z-index: 1;
44
+ }
45
+
46
+ /* Floating label active state - when textarea has content or focus */
47
+ .textarea:focus ~ .textarea-label-floating,
48
+ .textarea:not(:placeholder-shown) ~ .textarea-label-floating {
49
+ top: -0.5rem;
50
+ left: 0.75rem;
51
+ font-size: 0.75rem;
52
+ font-weight: 500;
53
+ color: var(--color-primary);
54
+ background-color: var(--color-surface);
55
+ padding: 0 0.25rem;
56
+ }
57
+
58
+ /* Floating label for filled variant */
59
+ .textarea-filled ~ .textarea-label-floating {
60
+ background-color: transparent;
61
+ }
62
+
63
+ .textarea-filled:focus ~ .textarea-label-floating,
64
+ .textarea-filled:not(:placeholder-shown) ~ .textarea-label-floating {
65
+ top: 0.25rem;
66
+ left: 0.75rem;
67
+ background-color: transparent;
68
+ }
69
+
70
+ /* ============================================
71
+ * HELPER TEXT
72
+ * ============================================ */
73
+
74
+ .textarea-helper {
75
+ font-size: 0.75rem;
76
+ line-height: 1rem;
77
+ color: var(--color-on-surface-variant);
78
+ margin-top: 0.25rem;
79
+ }
80
+
81
+ /* ============================================
82
+ * BASE TEXTAREA
83
+ * ============================================ */
84
+
8
85
  .textarea {
9
86
  display: block;
10
87
  width: 100%;
@@ -52,6 +129,15 @@
52
129
  cursor: default;
53
130
  }
54
131
 
132
+ /* Full Width */
133
+ .textarea-full {
134
+ width: 100%;
135
+ }
136
+
137
+ /* ============================================
138
+ * VARIANTS
139
+ * ============================================ */
140
+
55
141
  /* Filled Variant */
56
142
  .textarea-filled {
57
143
  background-color: var(--color-surface-container);
@@ -94,23 +180,68 @@
94
180
  box-shadow: none;
95
181
  }
96
182
 
97
- /* Color Variants */
183
+ /* ============================================
184
+ * COLOR VARIANTS
185
+ * ============================================ */
186
+
187
+ /* Primary */
188
+ .textarea-primary {
189
+ border-color: var(--color-primary);
190
+ }
191
+
98
192
  .textarea-primary:focus-visible {
99
193
  border-color: var(--color-primary);
100
194
  box-shadow: 0 0 0 3px color-mix(in oklch, var(--color-primary) 10%, transparent);
101
195
  }
102
196
 
197
+ .textarea-filled.textarea-primary {
198
+ border-bottom-color: var(--color-primary);
199
+ }
200
+
201
+ .textarea-filled.textarea-primary:focus-visible {
202
+ border-bottom-color: var(--color-primary);
203
+ }
204
+
205
+ /* Secondary */
206
+ .textarea-secondary {
207
+ border-color: var(--color-secondary);
208
+ }
209
+
103
210
  .textarea-secondary:focus-visible {
104
211
  border-color: var(--color-secondary);
105
212
  box-shadow: 0 0 0 3px color-mix(in oklch, var(--color-secondary) 10%, transparent);
106
213
  }
107
214
 
215
+ .textarea-filled.textarea-secondary {
216
+ border-bottom-color: var(--color-secondary);
217
+ }
218
+
219
+ .textarea-filled.textarea-secondary:focus-visible {
220
+ border-bottom-color: var(--color-secondary);
221
+ }
222
+
223
+ /* Tertiary */
224
+ .textarea-tertiary {
225
+ border-color: var(--color-tertiary);
226
+ }
227
+
108
228
  .textarea-tertiary:focus-visible {
109
229
  border-color: var(--color-tertiary);
110
230
  box-shadow: 0 0 0 3px color-mix(in oklch, var(--color-tertiary) 10%, transparent);
111
231
  }
112
232
 
113
- /* Semantic Colors */
233
+ .textarea-filled.textarea-tertiary {
234
+ border-bottom-color: var(--color-tertiary);
235
+ }
236
+
237
+ .textarea-filled.textarea-tertiary:focus-visible {
238
+ border-bottom-color: var(--color-tertiary);
239
+ }
240
+
241
+ /* ============================================
242
+ * SEMANTIC COLORS
243
+ * ============================================ */
244
+
114
245
  .textarea-error {
115
246
  border-color: var(--color-error);
116
247
  }
@@ -120,6 +251,10 @@
120
251
  box-shadow: 0 0 0 3px color-mix(in oklch, var(--color-error) 10%, transparent);
121
252
  }
122
253
 
254
+ .textarea-filled.textarea-error {
255
+ border-bottom-color: var(--color-error);
256
+ }
257
+
123
258
  .textarea-success {
124
259
  border-color: var(--color-success);
125
260
  }
@@ -129,6 +264,10 @@
129
264
  box-shadow: 0 0 0 3px color-mix(in oklch, var(--color-success) 10%, transparent);
130
265
  }
131
266
 
267
+ .textarea-filled.textarea-success {
268
+ border-bottom-color: var(--color-success);
269
+ }
270
+
132
271
  .textarea-warning {
133
272
  border-color: var(--color-warning);
134
273
  }
@@ -138,7 +277,14 @@
138
277
  box-shadow: 0 0 0 3px color-mix(in oklch, var(--color-warning) 10%, transparent);
139
278
  }
140
279
 
141
- /* Size Variants */
280
+ .textarea-filled.textarea-warning {
281
+ border-bottom-color: var(--color-warning);
282
+ }
283
+
284
+ /* ============================================
285
+ * SIZE VARIANTS
286
+ * ============================================ */
287
+
142
288
  .textarea-sm {
143
289
  min-height: 4rem;
144
290
  padding: 0.5rem 0.75rem;
@@ -155,11 +301,18 @@
155
301
  border-radius: 0.625rem;
156
302
  }
157
303
 
158
- /* Resize Options */
304
+ /* ============================================
305
+ * RESIZE OPTIONS
306
+ * ============================================ */
307
+
159
308
  .textarea-resize-none {
160
309
  resize: none;
161
310
  }
162
311
 
312
+ .textarea-resize-vertical {
313
+ resize: vertical;
314
+ }
315
+
163
316
  .textarea-resize-horizontal {
164
317
  resize: horizontal;
165
318
  }
@@ -168,19 +321,21 @@
168
321
  resize: both;
169
322
  }
170
323
 
171
- /* Auto-resize (requires JS) */
324
+ /* ============================================
325
+ * AUTO-RESIZE (requires JS)
326
+ * ============================================ */
327
+
328
+ .textarea-auto-resize,
172
329
  .textarea-autosize {
173
330
  resize: none;
174
331
  overflow: hidden;
332
+ min-height: 3rem;
333
+ field-sizing: content; /* Modern CSS - auto-grows without JS in supported browsers */
175
334
  }
176
335
 
177
- /* Character Counter */
178
- .textarea-wrapper {
179
- position: relative;
180
- display: flex;
181
- flex-direction: column;
182
- gap: 0.25rem;
183
- }
336
+ /* ============================================
337
+ * CHARACTER COUNTER
338
+ * ============================================ */
184
339
 
185
340
  .textarea-counter {
186
341
  font-size: 0.75rem;
@@ -189,13 +344,54 @@
189
344
  text-align: right;
190
345
  }
191
346
 
192
- .textarea-counter-error {
347
+ .textarea-counter-error,
348
+ .textarea-counter-exceeded {
349
+ color: var(--color-error);
350
+ }
351
+
352
+ /* ============================================
353
+ * CONTAINER STATES
354
+ * ============================================ */
355
+
356
+ .textarea-container-error .textarea-label {
357
+ color: var(--color-error);
358
+ }
359
+
360
+ .textarea-container-error .textarea-helper {
361
+ color: var(--color-error);
362
+ }
363
+
364
+ .textarea-container-error .textarea-label-floating {
365
+ color: var(--color-error);
366
+ }
367
+
368
+ .textarea-container-error .textarea:focus ~ .textarea-label-floating {
193
369
  color: var(--color-error);
194
370
  }
195
371
 
196
- /* Reduce Motion */
372
+ .textarea-container-success .textarea-label {
373
+ color: var(--color-success);
374
+ }
375
+
376
+ .textarea-container-success .textarea-helper {
377
+ color: var(--color-success);
378
+ }
379
+
380
+ .textarea-container-success .textarea-label-floating {
381
+ color: var(--color-success);
382
+ }
383
+
384
+ .textarea-container-success .textarea:focus ~ .textarea-label-floating {
385
+ color: var(--color-success);
386
+ }
387
+
388
+ /* ============================================
389
+ * REDUCE MOTION
390
+ * ============================================ */
391
+
197
392
  @media (prefers-reduced-motion: reduce) {
198
- .textarea {
393
+ .textarea,
394
+ .textarea-label-floating {
199
395
  transition: none;
200
396
  }
201
397
  }
@@ -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;