@moni-labs/moni-ui 0.4.13 → 0.4.16
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/custom-elements.json +101 -81
- package/dist/browser/moni-ui.iife.min.js +1538 -1384
- package/dist/browser/moni-ui.iife.min.js.br +0 -0
- package/dist/browser/moni-ui.iife.min.js.gz +0 -0
- package/dist/browser/moni-ui.iife.min.js.map +1 -1
- package/dist/browser/moni-ui.min.js +2751 -2501
- package/dist/browser/moni-ui.min.js.br +0 -0
- package/dist/browser/moni-ui.min.js.gz +0 -0
- package/dist/browser/moni-ui.min.js.map +1 -1
- package/dist/cdn/chunks/{class-map-DsL1Jr2T.js → class-map-QyT9W7rZ.js} +1 -1
- package/dist/cdn/chunks/{decorate-DxJYS4gw.js → decorate-B7wZvwrn.js} +629 -543
- package/dist/cdn/chunks/if-defined-5hr_ccFw.js +1 -0
- package/dist/cdn/chunks/{live-D52JqeKf.js → live-Hm1Di_ND.js} +1 -1
- package/dist/cdn/components/moni-app-bar.js +1 -1
- package/dist/cdn/components/moni-badge.js +1 -1
- package/dist/cdn/components/moni-bottom-sheet.js +2 -1
- package/dist/cdn/components/moni-button-group.js +1 -1
- package/dist/cdn/components/moni-button-segment.js +1 -1
- package/dist/cdn/components/moni-button.js +1 -1
- package/dist/cdn/components/moni-card.js +1 -1
- package/dist/cdn/components/moni-carousel.js +1 -1
- package/dist/cdn/components/moni-checkbox.js +1 -1
- package/dist/cdn/components/moni-chip.js +1 -1
- package/dist/cdn/components/moni-color-field.js +1 -1
- package/dist/cdn/components/moni-context-menu.js +1 -1
- package/dist/cdn/components/moni-dialog.js +1 -1
- package/dist/cdn/components/moni-divider.js +1 -1
- package/dist/cdn/components/moni-expansion.js +1 -1
- package/dist/cdn/components/moni-fab-menu.js +1 -1
- package/dist/cdn/components/moni-fab.js +1 -1
- package/dist/cdn/components/moni-file-field.js +1 -1
- package/dist/cdn/components/moni-icon.js +1 -1
- package/dist/cdn/components/moni-list-item.js +1 -1
- package/dist/cdn/components/moni-list.js +1 -1
- package/dist/cdn/components/moni-loading-indicator.js +1 -1
- package/dist/cdn/components/moni-menu-item.js +1 -1
- package/dist/cdn/components/moni-menu.js +1 -1
- package/dist/cdn/components/moni-morph-modal.js +3 -2
- package/dist/cdn/components/moni-nav-item.js +1 -1
- package/dist/cdn/components/moni-nav.js +1 -1
- package/dist/cdn/components/moni-progress.js +1 -1
- package/dist/cdn/components/moni-radio.js +1 -1
- package/dist/cdn/components/moni-ripple.js +1 -1
- package/dist/cdn/components/moni-segmented-button.js +1 -1
- package/dist/cdn/components/moni-select-option.js +1 -1
- package/dist/cdn/components/moni-select.js +512 -473
- package/dist/cdn/components/moni-shape.js +1 -1
- package/dist/cdn/components/moni-side-sheet.js +1 -1
- package/dist/cdn/components/moni-slider.js +1 -1
- package/dist/cdn/components/moni-snackbar.js +1 -1
- package/dist/cdn/components/moni-split-button.js +1 -1
- package/dist/cdn/components/moni-step.js +1 -1
- package/dist/cdn/components/moni-stepper.js +1 -1
- package/dist/cdn/components/moni-switch.js +1 -1
- package/dist/cdn/components/moni-tab.js +1 -1
- package/dist/cdn/components/moni-tabs.js +1 -1
- package/dist/cdn/components/moni-text-field.js +122 -95
- package/dist/cdn/components/moni-textarea.js +52 -52
- package/dist/cdn/components/moni-time-picker.js +1 -1
- package/dist/cdn/components/moni-toolbar.js +1 -1
- package/dist/cdn/components/moni-tooltip.js +1 -1
- package/dist/cdn/components/moni-typography.js +1 -1
- package/dist/cdn/importmap.json +98 -98
- package/dist/components/_base/field-styles.d.ts.map +1 -1
- package/dist/components/_base/field-styles.js +662 -576
- package/dist/components/moni-bottom-sheet.d.ts +19 -5
- package/dist/components/moni-bottom-sheet.d.ts.map +1 -1
- package/dist/components/moni-bottom-sheet.js +111 -30
- package/dist/components/moni-morph-modal.d.ts +10 -0
- package/dist/components/moni-morph-modal.d.ts.map +1 -1
- package/dist/components/moni-morph-modal.js +323 -217
- package/dist/components/moni-select.d.ts +16 -16
- package/dist/components/moni-select.d.ts.map +1 -1
- package/dist/components/moni-select.js +797 -727
- package/dist/components/moni-text-field.d.ts +15 -15
- package/dist/components/moni-text-field.d.ts.map +1 -1
- package/dist/components/moni-text-field.js +224 -180
- package/dist/components/moni-textarea.d.ts +13 -13
- package/dist/components/moni-textarea.d.ts.map +1 -1
- package/dist/components/moni-textarea.js +127 -122
- package/docs/api.json +109 -89
- package/docs/assets/moni-color-field/shape--square.png +0 -0
- package/docs/assets/moni-file-field/shape--square.png +0 -0
- package/docs/assets/moni-morph-modal/autoHeight--false.png +0 -0
- package/docs/assets/moni-morph-modal/autoHeight--true.png +0 -0
- package/docs/components/bottom-sheet.md +2 -1
- package/docs/components/morph-modal.md +16 -7
- package/docs/components/select.md +74 -74
- package/docs/components/text-field.md +75 -66
- package/docs/components/textarea.md +51 -51
- package/docs/llms.txt +3 -3
- package/package.json +1 -1
- package/src/components/_base/field-styles.ts +723 -637
- package/src/components/moni-bottom-sheet.test.ts +331 -0
- package/src/components/moni-bottom-sheet.ts +117 -29
- package/src/components/moni-morph-modal.test.ts +490 -413
- package/src/components/moni-morph-modal.ts +2274 -2162
- package/src/components/moni-select.test.ts +489 -466
- package/src/components/moni-select.ts +1963 -1815
- package/src/components/moni-text-field.test.ts +366 -342
- package/src/components/moni-text-field.ts +717 -645
- package/src/components/moni-textarea.test.ts +201 -197
- package/src/components/moni-textarea.ts +476 -460
- package/dist/cdn/chunks/if-defined-DdzvcoI7.js +0 -1
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* @license MIT
|
|
5
5
|
* @contributors Moni Labs & Contributors
|
|
6
6
|
*/
|
|
7
|
-
import { css } from
|
|
7
|
+
import { css } from "lit";
|
|
8
8
|
/**
|
|
9
9
|
* Shared visual rules for all field-like input components.
|
|
10
10
|
*
|
|
@@ -55,580 +55,666 @@ import { css } from 'lit';
|
|
|
55
55
|
* @see {@link sharedStyles} — Token bridge consumed by this stylesheet.
|
|
56
56
|
* @see {@link interactionStyles} — State layer (not used directly in fields).
|
|
57
57
|
*/
|
|
58
|
-
export const fieldStyles = css `
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
Uses !important to win specificity over .border and [class*='round']. */
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
directly to the <input> so that the floating label overlaps it correctly. */
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
an <output> follows the icon. The explicit class always wins and places
|
|
172
|
-
the icon on the right edge regardless of sibling count. */
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
so the field's visual design is fully controlled by Moni's CSS. */
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
-webkit-background-clip + -webkit-text-fill-color override the yellow tint. */
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
to prevent layout shift from the border width change. */
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
A max-height of 12rem (~8 lines) prevents uncontrolled page growth. */
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
component can render its own UI. The native controls are still active for
|
|
238
|
-
accessibility (click propagates through the transparent overlay). */
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
58
|
+
export const fieldStyles = css `
|
|
59
|
+
:host {
|
|
60
|
+
display: block;
|
|
61
|
+
/* Fields are full-width by default; the parent layout controls sizing. */
|
|
62
|
+
inline-size: 100%;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/* ─── Base field container ───────────────────────────────────────────────── */
|
|
66
|
+
.field {
|
|
67
|
+
/* Internal height token — overridden by size modifiers (.small, .large, .extra). */
|
|
68
|
+
--_input: 3rem;
|
|
69
|
+
/* Vertical start offset used for textarea padding and label positioning. */
|
|
70
|
+
--_start: 1.2rem;
|
|
71
|
+
/* Computed vertical center — used to position absolutely-placed icons. */
|
|
72
|
+
--_middle: calc(var(--_input, 0) / 2);
|
|
73
|
+
|
|
74
|
+
/* Default field shape: bottom border only (BeerCSS / MD3 "filled" style). */
|
|
75
|
+
border-radius: 0.25rem 0.25rem 0 0;
|
|
76
|
+
min-block-size: var(--_input);
|
|
77
|
+
display: flex;
|
|
78
|
+
flex-direction: column;
|
|
79
|
+
position: relative;
|
|
80
|
+
inline-size: 100%;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/* ─── Shape overrides ────────────────────────────────────────────────────── */
|
|
84
|
+
|
|
85
|
+
/* Square: removes all border-radius regardless of other modifiers.
|
|
86
|
+
Uses !important to win specificity over .border and [class*='round']. */
|
|
87
|
+
.field.square,
|
|
88
|
+
.field.square.border,
|
|
89
|
+
.field.square[class*="round"] {
|
|
90
|
+
border-radius: 0 !important;
|
|
91
|
+
}
|
|
92
|
+
.field.square > :is(input, textarea, select) {
|
|
93
|
+
border-radius: 0 !important;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/* ─── Fill variant ───────────────────────────────────────────────────────── */
|
|
97
|
+
/* Unsets background/color on the container; the background is applied
|
|
98
|
+
directly to the <input> so that the floating label overlaps it correctly. */
|
|
99
|
+
.field.fill {
|
|
100
|
+
--_background: var(--surface-container-highest);
|
|
101
|
+
background-color: unset !important;
|
|
102
|
+
color: unset !important;
|
|
103
|
+
}
|
|
104
|
+
.field.fill > :is(input, select, textarea) {
|
|
105
|
+
background-color: var(--_background);
|
|
106
|
+
/* z-index: 0 ensures the background renders above the ::before layer. */
|
|
107
|
+
z-index: 0;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/* ─── Size variants ──────────────────────────────────────────────────────── */
|
|
111
|
+
.field.small {
|
|
112
|
+
--_input: 2.5rem;
|
|
113
|
+
--_start: 1rem;
|
|
114
|
+
}
|
|
115
|
+
.field.large {
|
|
116
|
+
--_input: 3.5rem;
|
|
117
|
+
--_start: 1.4rem;
|
|
118
|
+
}
|
|
119
|
+
.field.extra {
|
|
120
|
+
--_input: 4rem;
|
|
121
|
+
--_start: 1.6rem;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/* ─── Border (outlined) variant ─────────────────────────────────────────── */
|
|
125
|
+
/* Adds full border-radius and outline-variant stroke on all four sides. */
|
|
126
|
+
.field.border {
|
|
127
|
+
border-radius: 0.25rem;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/* ─── Round / pill variants ──────────────────────────────────────────────── */
|
|
131
|
+
/* Applied when class matches the 'round' substring (e.g. .round, .round-sm). */
|
|
132
|
+
.field[class*="round"].small {
|
|
133
|
+
border-radius: 1.25rem;
|
|
134
|
+
}
|
|
135
|
+
.field[class*="round"] {
|
|
136
|
+
border-radius: 1.5rem;
|
|
137
|
+
}
|
|
138
|
+
.field[class*="round"].large {
|
|
139
|
+
border-radius: 1.75rem;
|
|
140
|
+
}
|
|
141
|
+
.field[class*="round"].extra {
|
|
142
|
+
border-radius: 2rem;
|
|
143
|
+
}
|
|
144
|
+
/* Compact rounding for dense forms without falling back to square corners. */
|
|
145
|
+
.field.small-round,
|
|
146
|
+
.field.small-round.small,
|
|
147
|
+
.field.small-round.large,
|
|
148
|
+
.field.small-round.extra {
|
|
149
|
+
border-radius: 0.5rem;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/* ─── Icon positioning ───────────────────────────────────────────────────── */
|
|
153
|
+
/* Generic rule: absolutely positions any icon/image/svg inside the field. */
|
|
154
|
+
.field > :is(i, img, svg) {
|
|
155
|
+
position: absolute;
|
|
156
|
+
inset: calc((var(--_input, 0) / 2) - 0.75rem) auto auto auto;
|
|
157
|
+
cursor: pointer;
|
|
158
|
+
z-index: 10;
|
|
159
|
+
inline-size: 1.5rem;
|
|
160
|
+
block-size: 1.5rem;
|
|
161
|
+
margin: auto 0;
|
|
162
|
+
pointer-events: none;
|
|
163
|
+
}
|
|
164
|
+
/* Leading icon: explicit class wins over :first-child heuristic. */
|
|
165
|
+
.field > :is(i, img, svg):first-child,
|
|
166
|
+
.field > .leading-icon {
|
|
167
|
+
inset: calc(var(--_middle, 0) - 0.75rem) auto auto 1rem;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/* Trailing icon: BeerCSS uses :last-child:not(:first-child) which fails when
|
|
171
|
+
an <output> follows the icon. The explicit class always wins and places
|
|
172
|
+
the icon on the right edge regardless of sibling count. */
|
|
173
|
+
.field > :is(i, img, svg):last-child:not(:first-child),
|
|
174
|
+
.field > .trailing-icon {
|
|
175
|
+
inset: calc(var(--_middle, 0) - 0.75rem) 1rem auto auto;
|
|
176
|
+
/* Prevent the inline-start override from the generic rule above. */
|
|
177
|
+
inset-inline-start: auto !important;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
/* Error state: trailing icons inherit the error color. */
|
|
181
|
+
.field.invalid > i {
|
|
182
|
+
color: var(--error);
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
/* ─── Native form element reset ──────────────────────────────────────────── */
|
|
186
|
+
/* 'all: unset' strips browser-default styles (appearance, border, font, etc.)
|
|
187
|
+
so the field's visual design is fully controlled by Moni's CSS. */
|
|
188
|
+
.field > :is(input, textarea, select) {
|
|
189
|
+
all: unset;
|
|
190
|
+
position: relative;
|
|
191
|
+
display: block;
|
|
192
|
+
box-sizing: border-box;
|
|
193
|
+
border-radius: inherit;
|
|
194
|
+
/* Default border is transparent; visible only in .border and focus states. */
|
|
195
|
+
border: 0.0625rem solid transparent;
|
|
196
|
+
padding: 0 0.9375rem;
|
|
197
|
+
font-family: inherit;
|
|
198
|
+
font-size: 1rem;
|
|
199
|
+
min-block-size: var(--_input);
|
|
200
|
+
outline: none;
|
|
201
|
+
z-index: 1;
|
|
202
|
+
background: none;
|
|
203
|
+
resize: none; /* Textareas use field-sizing:content instead of manual resize. */
|
|
204
|
+
text-align: start;
|
|
205
|
+
cursor: text;
|
|
206
|
+
color: var(--on-surface);
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
/* Ensure date/time input values align to start (browser quirk on some platforms). */
|
|
210
|
+
input::-webkit-date-and-time-value {
|
|
211
|
+
text-align: start;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
/* Autofill: preserve text color when the browser applies its autofill highlight.
|
|
215
|
+
-webkit-background-clip + -webkit-text-fill-color override the yellow tint. */
|
|
216
|
+
:is(input, select, textarea):is(:-webkit-autofill, :autofill) {
|
|
217
|
+
-webkit-background-clip: text;
|
|
218
|
+
-webkit-text-fill-color: var(--on-surface);
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
/* On focus, increase border width by 1px — shift padding inward by 1px
|
|
222
|
+
to prevent layout shift from the border width change. */
|
|
223
|
+
.field > :is(input, textarea, select):focus {
|
|
224
|
+
border: 0.125rem solid transparent;
|
|
225
|
+
padding-inline: 0.875rem;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
/* Textareas without explicit rows grow automatically using field-sizing:content.
|
|
229
|
+
A max-height of 12rem (~8 lines) prevents uncontrolled page growth. */
|
|
230
|
+
.field > textarea:not([rows]) {
|
|
231
|
+
field-sizing: content;
|
|
232
|
+
max-block-size: 12rem;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
/* ─── Transparent native picker controls ─────────────────────────────────── */
|
|
236
|
+
/* File and color inputs, and date/time picker indicators are hidden so the
|
|
237
|
+
component can render its own UI. The native controls are still active for
|
|
238
|
+
accessibility (click propagates through the transparent overlay). */
|
|
239
|
+
input[type="file"],
|
|
240
|
+
input[type="color"],
|
|
241
|
+
:not(.field)
|
|
242
|
+
> input:is([type^="date"], [type^="time"], [type="month"], [type="week"]),
|
|
243
|
+
input::-webkit-calendar-picker-indicator {
|
|
244
|
+
opacity: 0;
|
|
245
|
+
position: absolute;
|
|
246
|
+
inset: 0;
|
|
247
|
+
inline-size: 100%;
|
|
248
|
+
block-size: 100%;
|
|
249
|
+
margin: 0;
|
|
250
|
+
padding: 0;
|
|
251
|
+
border: 0;
|
|
252
|
+
outline: 0;
|
|
253
|
+
z-index: 2 !important;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
/* On fine-pointer (mouse) devices, push the calendar picker indicator behind
|
|
257
|
+
the field content so it doesn't interfere with other clickable elements. */
|
|
258
|
+
@media (pointer: fine) {
|
|
259
|
+
.field > input::-webkit-calendar-picker-indicator {
|
|
260
|
+
z-index: -1 !important;
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
/* Remove browser-native search field decorations. */
|
|
265
|
+
input::-webkit-search-decoration,
|
|
266
|
+
input::-webkit-search-cancel-button,
|
|
267
|
+
input::-webkit-search-results-button,
|
|
268
|
+
input::-webkit-search-results-decoration,
|
|
269
|
+
input::-webkit-inner-spin-button,
|
|
270
|
+
input::-webkit-outer-spin-button {
|
|
271
|
+
display: none;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
/* Remove the browser spinner on number inputs — use explicit stepper UI instead. */
|
|
275
|
+
input[type="number"] {
|
|
276
|
+
appearance: textfield;
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
/* ─── Border variant: field-level border colors ──────────────────────────── */
|
|
280
|
+
.field.border > :is(input, textarea, select) {
|
|
281
|
+
border-color: var(--outline);
|
|
282
|
+
}
|
|
283
|
+
.field.border > :is(input, textarea, select):focus {
|
|
284
|
+
border-color: var(--primary);
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
/* Round variants add extra inline padding to clear the curved edges. */
|
|
288
|
+
.field[class*="round"] > :is(input, textarea, select) {
|
|
289
|
+
padding-inline: 1.4376rem;
|
|
290
|
+
}
|
|
291
|
+
.field[class*="round"] > :is(input, textarea, select):focus {
|
|
292
|
+
padding-inline: 1.375rem;
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
/* ─── Icon padding accommodation ─────────────────────────────────────────── */
|
|
296
|
+
/* .prefix / .suffix shift the input's inline padding to make room for icons. */
|
|
297
|
+
.field.prefix > :is(input, textarea, select) {
|
|
298
|
+
padding-inline-start: 2.9375rem;
|
|
299
|
+
}
|
|
300
|
+
.field.prefix > :is(input, textarea, select):focus {
|
|
301
|
+
padding-inline-start: 2.875rem;
|
|
302
|
+
}
|
|
303
|
+
.field.suffix > :is(input, textarea, select) {
|
|
304
|
+
padding-inline-end: 2.9375rem;
|
|
305
|
+
}
|
|
306
|
+
.field.suffix > :is(input, textarea, select):focus {
|
|
307
|
+
padding-inline-end: 2.875rem;
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
/* ─── Underline (non-border, non-round) bottom border ─────────────────────── */
|
|
311
|
+
/* Default M3 filled field style: only the bottom border is visible. */
|
|
312
|
+
.field:not(.border, [class*="round"]) > :is(input, textarea, select) {
|
|
313
|
+
border-block-end-color: var(--outline);
|
|
314
|
+
}
|
|
315
|
+
.field:not(.border, [class*="round"]) > :is(input, textarea, select):focus {
|
|
316
|
+
border-block-end-color: var(--primary);
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
/* Round non-bordered fields get a subtle elevation shadow instead of a border. */
|
|
320
|
+
.field[class*="round"]:not(.border, .fill) > :is(input, textarea, select),
|
|
321
|
+
.field[class*="round"]:not(.border) > :is(input, textarea, select):focus {
|
|
322
|
+
box-shadow: var(--elevate1);
|
|
323
|
+
}
|
|
324
|
+
.field[class*="round"]:not(.border, .fill)
|
|
325
|
+
> :is(input, textarea, select):focus {
|
|
326
|
+
box-shadow: var(--elevate2);
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
/* ─── Invalid / error state borders ─────────────────────────────────────── */
|
|
330
|
+
.field.invalid:not(.border, [class*="round"]) > :is(input, textarea, select),
|
|
331
|
+
.field.invalid:not(.border, [class*="round"])
|
|
332
|
+
> :is(input, textarea, select):focus {
|
|
333
|
+
border-block-end-color: var(--error);
|
|
334
|
+
}
|
|
335
|
+
.field.invalid.border > :is(input, textarea, select),
|
|
336
|
+
.field.invalid.border > :is(input, textarea, select):focus {
|
|
337
|
+
border-color: var(--error);
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
/* ─── Disabled state ─────────────────────────────────────────────────────── */
|
|
341
|
+
/* Reduces opacity on the entire field container when the native control is
|
|
342
|
+
disabled, rather than applying separate rules to each child. */
|
|
343
|
+
.field:has(> :disabled) {
|
|
344
|
+
opacity: 0.5;
|
|
345
|
+
cursor: not-allowed;
|
|
346
|
+
}
|
|
347
|
+
.field > :disabled {
|
|
348
|
+
cursor: not-allowed;
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
/* ─── Select element ─────────────────────────────────────────────────────── */
|
|
352
|
+
/* Remove browser-native select appearance; the component renders its own dropdown. */
|
|
353
|
+
.field > select {
|
|
354
|
+
user-select: none;
|
|
355
|
+
appearance: none;
|
|
356
|
+
-webkit-appearance: none;
|
|
357
|
+
background-image: none;
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
/* ─── Block-start padding for label accommodation ────────────────────────── */
|
|
361
|
+
/* Inputs with a floating label need top padding to create space for the
|
|
362
|
+
label when it lifts above the input. Selects always lift their label. */
|
|
363
|
+
.field > :is(input, select) {
|
|
364
|
+
padding-block-start: 1rem;
|
|
365
|
+
}
|
|
366
|
+
/* No-label and border+fill fields: remove the top padding offset. */
|
|
367
|
+
.field:not(.label) > :is(input, select),
|
|
368
|
+
.field.border:not(.fill) > :is(input, select) {
|
|
369
|
+
padding-block-start: 0;
|
|
370
|
+
}
|
|
371
|
+
/* Textareas use the --_start token to align with the label baseline. */
|
|
372
|
+
.field > textarea {
|
|
373
|
+
padding-block-start: var(--_start) !important;
|
|
374
|
+
}
|
|
375
|
+
.field > textarea:focus {
|
|
376
|
+
/* 0.01rem compensates for the border width increase on focus. */
|
|
377
|
+
padding-block-start: calc(var(--_start, 0) - 0.01rem) !important;
|
|
378
|
+
}
|
|
379
|
+
.field:not(.label) > textarea,
|
|
380
|
+
.field.border:not(.fill) > textarea {
|
|
381
|
+
padding-block-start: calc(var(--_start, 0) - 0.5rem) !important;
|
|
382
|
+
}
|
|
383
|
+
.field:not(.label) > textarea:focus,
|
|
384
|
+
.field.border:not(.fill) > textarea:focus {
|
|
385
|
+
padding-block-start: calc(var(--_start, 0) - 0.51rem) !important;
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
/* ─── Floating label ─────────────────────────────────────────────────────── */
|
|
389
|
+
/* The label starts at full font-size (1rem) vertically centered in the field.
|
|
390
|
+
On focus or when value is present, it scales down to 0.75rem and lifts
|
|
391
|
+
to the top of the field container. */
|
|
392
|
+
.field.label > label {
|
|
393
|
+
--_start: 1rem;
|
|
394
|
+
position: absolute;
|
|
395
|
+
inset: -0.5rem 0.9375rem 0 var(--_start);
|
|
396
|
+
display: flex;
|
|
397
|
+
/* Full height + 1rem (for label overhang) centers the label vertically. */
|
|
398
|
+
block-size: calc(var(--_input, 0) + 1rem);
|
|
399
|
+
line-height: calc(var(--_input, 0) + 1rem);
|
|
400
|
+
font-size: 1rem;
|
|
401
|
+
transition: all 0.2s;
|
|
402
|
+
gap: 0.25rem;
|
|
403
|
+
white-space: nowrap;
|
|
404
|
+
/* The label is purely decorative from a layout perspective; it must never
|
|
405
|
+
intercept pointer events meant for the underlying input. */
|
|
406
|
+
pointer-events: none;
|
|
407
|
+
color: var(--on-surface-variant);
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
/* Round fields: label aligns with the increased inline padding. */
|
|
411
|
+
.field.label[class*="round"] > label {
|
|
412
|
+
inset: -0.5rem 1.9375rem 0 var(--_start);
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
/* ─── Label lift selector group ──────────────────────────────────────────── */
|
|
416
|
+
/* The label lifts (scales down + moves up) in four conditions:
|
|
417
|
+
1. label.active — the component sets this class directly (readonly inputs).
|
|
418
|
+
2. :focus + label — when the native control is focused.
|
|
419
|
+
3. [placeholder]:not(:placeholder-shown) + label — when a value is present.
|
|
420
|
+
4. select + label — selects always show their label lifted.
|
|
421
|
+
5. input.active + label — for programmatically activated inputs. */
|
|
422
|
+
|
|
423
|
+
/* Border + prefix + no-fill variant needs a reduced --_start offset. */
|
|
424
|
+
.field.label.border.prefix:not(.fill)
|
|
425
|
+
> :is(
|
|
426
|
+
label.active,
|
|
427
|
+
:focus + label,
|
|
428
|
+
[placeholder]:not(:placeholder-shown) + label,
|
|
429
|
+
select + label,
|
|
430
|
+
input.active + label
|
|
431
|
+
) {
|
|
432
|
+
--_start: 1rem;
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
/* Round field label and round border prefix field label override. */
|
|
436
|
+
.field.label[class*="round"] > label,
|
|
437
|
+
.field.label.border.prefix[class*="round"]:not(.fill)
|
|
438
|
+
> :is(
|
|
439
|
+
label.active,
|
|
440
|
+
:focus + label,
|
|
441
|
+
[placeholder]:not(:placeholder-shown) + label,
|
|
442
|
+
select + label,
|
|
443
|
+
input.active + label
|
|
444
|
+
) {
|
|
445
|
+
--_start: 1.5rem;
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
.field.label.small-round > label {
|
|
449
|
+
--_start: 1rem;
|
|
450
|
+
inset: -0.5rem 0.9375rem 0 var(--_start);
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
/* Prefix fields: shift the label's inline-start to clear the leading icon. */
|
|
454
|
+
.field.label.prefix > label {
|
|
455
|
+
--_start: 3rem;
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
/* Lifted label: shrinks to 0.75rem and collapses to the top of the field. */
|
|
459
|
+
.field.label
|
|
460
|
+
> :is(
|
|
461
|
+
label.active,
|
|
462
|
+
:focus + label,
|
|
463
|
+
[placeholder]:not(:placeholder-shown) + label,
|
|
464
|
+
select + label,
|
|
465
|
+
input.active + label
|
|
466
|
+
) {
|
|
467
|
+
block-size: 2.5rem;
|
|
468
|
+
line-height: 2.5rem;
|
|
469
|
+
font-size: 0.75rem;
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
/* Border variant: label collapses to 1rem height with a notch cut effect. */
|
|
473
|
+
.field.label.border:not(.fill)
|
|
474
|
+
> :is(
|
|
475
|
+
label.active,
|
|
476
|
+
:focus + label,
|
|
477
|
+
[placeholder]:not(:placeholder-shown) + label,
|
|
478
|
+
select + label,
|
|
479
|
+
input.active + label
|
|
480
|
+
) {
|
|
481
|
+
block-size: 1rem;
|
|
482
|
+
line-height: 1rem;
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
/* ─── Border notch (label gap in the top border) ─────────────────────────── */
|
|
486
|
+
/* The ::after pseudo creates the horizontal line to the right of the lifted
|
|
487
|
+
label, visually cutting a notch into the top border of .field.border. */
|
|
488
|
+
.field.label.border:not(.fill) > label::after {
|
|
489
|
+
content: "";
|
|
490
|
+
display: block;
|
|
491
|
+
margin: 0.5rem 0 0 0;
|
|
492
|
+
border-block-start: 0.0625rem solid var(--outline);
|
|
493
|
+
block-size: 1rem;
|
|
494
|
+
transition: none;
|
|
495
|
+
flex: auto;
|
|
496
|
+
}
|
|
497
|
+
.field.label.border:not(.fill) > :focus + label::after {
|
|
498
|
+
/* On focus, the notch line becomes primary-colored. */
|
|
499
|
+
border-block-start: 0.125rem solid var(--primary);
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
/* ─── Border notch clipping (clip-path) ──────────────────────────────────── */
|
|
503
|
+
/* When the label is lifted, a clip-path cuts a gap in the top border of the
|
|
504
|
+
input element itself, creating the appearance of the label floating within
|
|
505
|
+
the border's top edge. The clip-path dimensions account for label width. */
|
|
506
|
+
.field.label.border.square:not(.fill)
|
|
507
|
+
> :is(input, textarea):is(
|
|
508
|
+
:focus,
|
|
509
|
+
[placeholder]:not(:placeholder-shown),
|
|
510
|
+
.active
|
|
511
|
+
),
|
|
512
|
+
.field.label.border.square:not(.fill) > select,
|
|
513
|
+
.field.label.border.square:not(.fill) > input.active,
|
|
514
|
+
.field.label.border.square:not(.fill) > select.active {
|
|
515
|
+
clip-path: polygon(
|
|
516
|
+
-2% -2%,
|
|
517
|
+
0.75rem -2%,
|
|
518
|
+
0.75rem 0.5rem,
|
|
519
|
+
calc(100% - 1rem) 0.5rem,
|
|
520
|
+
calc(100% - 1rem) -2%,
|
|
521
|
+
102% -2%,
|
|
522
|
+
102% 102%,
|
|
523
|
+
-2% 102%
|
|
524
|
+
);
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
/* Prefix variant: clip starts further right to clear the leading icon text. */
|
|
528
|
+
.field.label.border.prefix.square:not(.fill)
|
|
529
|
+
> :is(input, textarea):is(
|
|
530
|
+
:focus,
|
|
531
|
+
[placeholder]:not(:placeholder-shown),
|
|
532
|
+
.active
|
|
533
|
+
),
|
|
534
|
+
.field.label.border.prefix.square:not(.fill) > select,
|
|
535
|
+
.field.label.border.prefix.square:not(.fill) > input.active,
|
|
536
|
+
.field.label.border.prefix.square:not(.fill) > select.active {
|
|
537
|
+
clip-path: polygon(
|
|
538
|
+
-2% -2%,
|
|
539
|
+
0.75rem -2%,
|
|
540
|
+
0.75rem 0.5rem,
|
|
541
|
+
calc(100% - 1rem) 0.5rem,
|
|
542
|
+
calc(100% - 1rem) -2%,
|
|
543
|
+
102% -2%,
|
|
544
|
+
102% 102%,
|
|
545
|
+
-2% 102%
|
|
546
|
+
);
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
/* Round and square border fields use a wider notch to clear the curved border. */
|
|
550
|
+
.field.label.border[class*="round"]:not(.fill)
|
|
551
|
+
> :is(input, textarea):is(
|
|
552
|
+
:focus,
|
|
553
|
+
[placeholder]:not(:placeholder-shown),
|
|
554
|
+
.active
|
|
555
|
+
),
|
|
556
|
+
.field.label.border[class*="round"]:not(.fill) > select,
|
|
557
|
+
.field.label.border:not(.fill)
|
|
558
|
+
> :is(input, textarea):is(
|
|
559
|
+
:focus,
|
|
560
|
+
[placeholder]:not(:placeholder-shown),
|
|
561
|
+
.active
|
|
562
|
+
),
|
|
563
|
+
.field.label.border:not(.fill) > select {
|
|
564
|
+
clip-path: polygon(
|
|
565
|
+
-2% -2%,
|
|
566
|
+
0.75rem -2%,
|
|
567
|
+
0.75rem 0.5rem,
|
|
568
|
+
calc(100% - 1rem) 0.5rem,
|
|
569
|
+
calc(100% - 1rem) -2%,
|
|
570
|
+
102% -2%,
|
|
571
|
+
102% 102%,
|
|
572
|
+
-2% 102%
|
|
573
|
+
);
|
|
574
|
+
}
|
|
575
|
+
|
|
576
|
+
.field.label.border.prefix[class*="round"]:not(.fill)
|
|
577
|
+
> :is(input, textarea):is(
|
|
578
|
+
:focus,
|
|
579
|
+
[placeholder]:not(:placeholder-shown),
|
|
580
|
+
.active
|
|
581
|
+
),
|
|
582
|
+
.field.label.border.prefix[class*="round"]:not(.fill) > select,
|
|
583
|
+
.field.label.border.prefix:not(.fill)
|
|
584
|
+
> :is(input, textarea):is(
|
|
585
|
+
:focus,
|
|
586
|
+
[placeholder]:not(:placeholder-shown),
|
|
587
|
+
.active
|
|
588
|
+
),
|
|
589
|
+
.field.label.border.prefix:not(.fill) > select {
|
|
590
|
+
clip-path: polygon(
|
|
591
|
+
-2% -2%,
|
|
592
|
+
0.75rem -2%,
|
|
593
|
+
0.75rem 0.5rem,
|
|
594
|
+
calc(100% - 1rem) 0.5rem,
|
|
595
|
+
calc(100% - 1rem) -2%,
|
|
596
|
+
102% -2%,
|
|
597
|
+
102% 102%,
|
|
598
|
+
-2% 102%
|
|
599
|
+
);
|
|
600
|
+
}
|
|
601
|
+
|
|
602
|
+
.field.label.border.round:not(.fill)
|
|
603
|
+
> :is(input, textarea):is(
|
|
604
|
+
:focus,
|
|
605
|
+
[placeholder]:not(:placeholder-shown),
|
|
606
|
+
.active
|
|
607
|
+
),
|
|
608
|
+
.field.label.border.round:not(.fill) > select,
|
|
609
|
+
.field.label.border.round:not(.fill) > input.active,
|
|
610
|
+
.field.label.border.round:not(.fill) > select.active {
|
|
611
|
+
clip-path: polygon(
|
|
612
|
+
-2% -2%,
|
|
613
|
+
1.25rem -2%,
|
|
614
|
+
1.25rem 0.5rem,
|
|
615
|
+
calc(100% - 2rem) 0.5rem,
|
|
616
|
+
calc(100% - 2rem) -2%,
|
|
617
|
+
102% -2%,
|
|
618
|
+
102% 102%,
|
|
619
|
+
-2% 102%
|
|
620
|
+
) !important;
|
|
621
|
+
}
|
|
622
|
+
|
|
623
|
+
.field.label.border.small-round:not(.fill)
|
|
624
|
+
> :is(input, textarea):is(
|
|
625
|
+
:focus,
|
|
626
|
+
[placeholder]:not(:placeholder-shown),
|
|
627
|
+
.active
|
|
628
|
+
),
|
|
629
|
+
.field.label.border.small-round:not(.fill) > select,
|
|
630
|
+
.field.label.border.small-round:not(.fill) > input.active,
|
|
631
|
+
.field.label.border.small-round:not(.fill) > select.active {
|
|
632
|
+
clip-path: polygon(
|
|
633
|
+
-2% -2%,
|
|
634
|
+
0.75rem -2%,
|
|
635
|
+
0.75rem 0.5rem,
|
|
636
|
+
calc(100% - 1rem) 0.5rem,
|
|
637
|
+
calc(100% - 1rem) -2%,
|
|
638
|
+
102% -2%,
|
|
639
|
+
102% 102%,
|
|
640
|
+
-2% 102%
|
|
641
|
+
) !important;
|
|
642
|
+
}
|
|
643
|
+
|
|
644
|
+
/* ─── Label color changes ─────────────────────────────────────────────────── */
|
|
645
|
+
/* On focus: label turns primary-colored to draw attention. */
|
|
646
|
+
.field.label > :focus + label {
|
|
647
|
+
color: var(--primary);
|
|
648
|
+
}
|
|
649
|
+
|
|
650
|
+
/* On error: label and notch line turn error-colored. */
|
|
651
|
+
.field.label.invalid > label,
|
|
652
|
+
.field.label.invalid > label::after {
|
|
653
|
+
color: var(--error) !important;
|
|
654
|
+
border-color: var(--error) !important;
|
|
655
|
+
}
|
|
656
|
+
|
|
657
|
+
/* ─── Helper / error output ──────────────────────────────────────────────── */
|
|
658
|
+
/* The <output> element below the field shows helper text or validation errors. */
|
|
659
|
+
.field > output {
|
|
660
|
+
display: inline-block;
|
|
661
|
+
font-size: 0.75rem;
|
|
662
|
+
background: none !important;
|
|
663
|
+
padding: 0.25rem 1rem;
|
|
664
|
+
line-height: 1.25rem;
|
|
665
|
+
align-self: start;
|
|
666
|
+
color: var(--on-surface-variant);
|
|
667
|
+
}
|
|
668
|
+
/* Error output overrides the neutral helper color. */
|
|
669
|
+
.field > output.invalid {
|
|
670
|
+
color: var(--error) !important;
|
|
671
|
+
}
|
|
672
|
+
/* Round fields: increase horizontal padding to align with the curved edge. */
|
|
673
|
+
.field[class*="round"] > output {
|
|
674
|
+
padding: 0.25rem 1.5rem;
|
|
675
|
+
}
|
|
676
|
+
/* Show only one output at a time: helper OR error, never both. */
|
|
677
|
+
.field.invalid > output:not(.invalid),
|
|
678
|
+
.field:not(.invalid) > output.invalid {
|
|
679
|
+
display: none;
|
|
680
|
+
}
|
|
681
|
+
|
|
682
|
+
/* ─── Footer wrapper (textarea & multi-line fields) ───────────────────────── */
|
|
683
|
+
/* Lays out helper text (left) and character counter (right) on the same row,
|
|
684
|
+
matching the M3 spec for supporting-text + character-counter pairs. */
|
|
685
|
+
.field > .footer {
|
|
686
|
+
display: flex;
|
|
687
|
+
align-items: center;
|
|
688
|
+
justify-content: space-between;
|
|
689
|
+
gap: 1rem;
|
|
690
|
+
padding: 0;
|
|
691
|
+
min-block-size: 1.25rem;
|
|
692
|
+
}
|
|
693
|
+
.field > .footer > output {
|
|
694
|
+
display: inline-block;
|
|
695
|
+
font-size: 0.75rem;
|
|
696
|
+
background: none !important;
|
|
697
|
+
padding: 0.25rem 1rem;
|
|
698
|
+
line-height: 1.25rem;
|
|
699
|
+
align-self: center;
|
|
700
|
+
color: var(--on-surface-variant);
|
|
701
|
+
}
|
|
702
|
+
.field > .footer > output.invalid {
|
|
703
|
+
color: var(--error) !important;
|
|
704
|
+
}
|
|
705
|
+
/* Character counter — right-aligned, same typographic style as the helper. */
|
|
706
|
+
.field > .footer > .counter {
|
|
707
|
+
padding: 0.25rem 1rem;
|
|
708
|
+
color: var(--on-surface-variant);
|
|
709
|
+
}
|
|
710
|
+
/* Spacer pushes counter to the right when there is no helper text. */
|
|
711
|
+
.field > .footer > .spacer {
|
|
712
|
+
flex: 1;
|
|
713
|
+
}
|
|
714
|
+
/* Same exclusive show logic as direct <output> elements. */
|
|
715
|
+
.field.invalid > .footer > output:not(.invalid),
|
|
716
|
+
.field:not(.invalid) > .footer > output.invalid {
|
|
717
|
+
display: none;
|
|
718
|
+
}
|
|
633
719
|
`;
|
|
634
720
|
export default fieldStyles;
|