mtrl 0.5.2 → 0.5.3

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 (69) hide show
  1. package/dist/index.cjs +1 -1
  2. package/dist/index.js +1 -1
  3. package/dist/package.json +1 -1
  4. package/dist/styles.css +1 -1
  5. package/package.json +3 -2
  6. package/src/styles/abstract/_base.scss +2 -0
  7. package/src/styles/abstract/_config.scss +28 -0
  8. package/src/styles/abstract/_functions.scss +124 -0
  9. package/src/styles/abstract/_mixins.scss +401 -0
  10. package/src/styles/abstract/_theme.scss +269 -0
  11. package/src/styles/abstract/_variables.scss +338 -0
  12. package/src/styles/base/_reset.scss +86 -0
  13. package/src/styles/base/_typography.scss +155 -0
  14. package/src/styles/components/_badge.scss +183 -0
  15. package/src/styles/components/_bottom-app-bar.scss +103 -0
  16. package/src/styles/components/_button.scss +756 -0
  17. package/src/styles/components/_card.scss +401 -0
  18. package/src/styles/components/_carousel.scss +645 -0
  19. package/src/styles/components/_checkbox.scss +231 -0
  20. package/src/styles/components/_chips.scss +639 -0
  21. package/src/styles/components/_datepicker.scss +358 -0
  22. package/src/styles/components/_dialog.scss +259 -0
  23. package/src/styles/components/_divider.scss +57 -0
  24. package/src/styles/components/_extended-fab.scss +309 -0
  25. package/src/styles/components/_fab.scss +244 -0
  26. package/src/styles/components/_list.scss +774 -0
  27. package/src/styles/components/_menu.scss +245 -0
  28. package/src/styles/components/_navigation-mobile.scss +244 -0
  29. package/src/styles/components/_navigation-system.scss +151 -0
  30. package/src/styles/components/_navigation.scss +407 -0
  31. package/src/styles/components/_progress.scss +101 -0
  32. package/src/styles/components/_radios.scss +187 -0
  33. package/src/styles/components/_search.scss +306 -0
  34. package/src/styles/components/_segmented-button.scss +227 -0
  35. package/src/styles/components/_select.scss +274 -0
  36. package/src/styles/components/_sheet.scss +236 -0
  37. package/src/styles/components/_slider.scss +264 -0
  38. package/src/styles/components/_snackbar.scss +211 -0
  39. package/src/styles/components/_switch.scss +305 -0
  40. package/src/styles/components/_tabs.scss +421 -0
  41. package/src/styles/components/_textfield.scss +1024 -0
  42. package/src/styles/components/_timepicker.scss +451 -0
  43. package/src/styles/components/_tooltip.scss +241 -0
  44. package/src/styles/components/_top-app-bar.scss +225 -0
  45. package/src/styles/main.scss +129 -0
  46. package/src/styles/themes/_autumn.scss +105 -0
  47. package/src/styles/themes/_base-theme.scss +85 -0
  48. package/src/styles/themes/_baseline.scss +173 -0
  49. package/src/styles/themes/_bluekhaki.scss +125 -0
  50. package/src/styles/themes/_brownbeige.scss +125 -0
  51. package/src/styles/themes/_browngreen.scss +125 -0
  52. package/src/styles/themes/_forest.scss +77 -0
  53. package/src/styles/themes/_greenbeige.scss +125 -0
  54. package/src/styles/themes/_index.scss +19 -0
  55. package/src/styles/themes/_material.scss +125 -0
  56. package/src/styles/themes/_ocean.scss +77 -0
  57. package/src/styles/themes/_sageivory.scss +125 -0
  58. package/src/styles/themes/_spring.scss +77 -0
  59. package/src/styles/themes/_summer.scss +87 -0
  60. package/src/styles/themes/_sunset.scss +60 -0
  61. package/src/styles/themes/_tealcaramel.scss +125 -0
  62. package/src/styles/themes/_winter.scss +77 -0
  63. package/src/styles/utilities/_colors.scss +154 -0
  64. package/src/styles/utilities/_flexbox.scss +194 -0
  65. package/src/styles/utilities/_layout.scss +665 -0
  66. package/src/styles/utilities/_ripple.scss +79 -0
  67. package/src/styles/utilities/_spacing.scss +139 -0
  68. package/src/styles/utilities/_typography.scss +178 -0
  69. package/src/styles/utilities/_visibility.scss +142 -0
@@ -0,0 +1,1024 @@
1
+ // src/styles/components/_textfield.scss
2
+ @use "../../styles/abstract/base" as base;
3
+ @use "../../styles/abstract/variables" as v;
4
+ @use "../../styles/abstract/functions" as f;
5
+ @use "../../styles/abstract/mixins" as m;
6
+ @use "../../styles/abstract/theme" as t;
7
+
8
+ // Define the component once
9
+ $component: "#{base.$prefix}-textfield";
10
+
11
+ // Autofill detection animations
12
+ @keyframes onAutoFillStart {
13
+ from {
14
+ opacity: 1;
15
+ }
16
+ to {
17
+ opacity: 1;
18
+ }
19
+ }
20
+
21
+ @keyframes onAutoFillCancel {
22
+ from {
23
+ opacity: 1;
24
+ }
25
+ to {
26
+ opacity: 1;
27
+ }
28
+ }
29
+
30
+ // ===== BASE STYLES =====
31
+ .#{$component} {
32
+ position: relative;
33
+ display: inline-flex;
34
+ flex-direction: column;
35
+ min-width: 210px;
36
+ // align-self: flex-start; // Prevents growing to fill the container's height
37
+ flex: 0 0 auto; // Don't grow or shrink; keep natural size
38
+ // Label
39
+ &-label {
40
+ @include m.typography("body-large");
41
+ user-select: none;
42
+ position: absolute;
43
+ left: 16px;
44
+ top: 50%;
45
+ transform: translateY(-50%);
46
+ transform-origin: left top;
47
+ pointer-events: none;
48
+ border-radius: 2px;
49
+ color: t.color("on-surface-variant");
50
+ transition: transform v.motion("duration-short4")
51
+ v.motion("easing-emphasized"),
52
+ color v.motion("duration-short2") v.motion("easing-standard"),
53
+ left v.motion("duration-short4") v.motion("easing-emphasized");
54
+ }
55
+
56
+ // Input element
57
+ &-input {
58
+ @include m.typography("body-large");
59
+ @include m.shape("extra-small");
60
+ padding: 13px 16px;
61
+ width: 100%;
62
+ height: 56px;
63
+ color: t.color("on-surface");
64
+ border: 0;
65
+ appearance: none;
66
+ outline: none;
67
+
68
+ // Animation to detect autofill
69
+ animation-name: onAutoFillCancel;
70
+ animation-duration: 10ms;
71
+
72
+ // Transition to help detect autofill changes
73
+ transition: background-color 0s ease-out 50000000s;
74
+
75
+ &::placeholder {
76
+ color: transparent;
77
+ }
78
+
79
+ // Autofill styles
80
+ &:-webkit-autofill {
81
+ animation-name: onAutoFillStart;
82
+ animation-duration: 10ms;
83
+ -webkit-text-fill-color: t.color("on-surface");
84
+ transition: background-color 5000s ease-in-out 0s; // Long transition to keep the background
85
+
86
+ & ~ .#{$component}-label {
87
+ transform: translateY(-95%) scale(0.75);
88
+ background-color: t.color("surface");
89
+ }
90
+ }
91
+
92
+ // Firefox autofill
93
+ &:autofill {
94
+ color: t.color("on-surface");
95
+
96
+ & ~ .#{$component}-label {
97
+ transform: translateY(-95%) scale(0.75);
98
+ background-color: t.color("surface");
99
+ }
100
+ }
101
+
102
+ // Non-empty input should also float the label
103
+ &:not(:placeholder-shown) {
104
+ & ~ .#{$component}-label {
105
+ transform: translateY(-95%) scale(0.75);
106
+ }
107
+ }
108
+ }
109
+
110
+ // Prefix text
111
+ &-prefix {
112
+ @include m.typography("body-large");
113
+ position: absolute;
114
+ left: 12px;
115
+ top: 50%;
116
+ transform: translateY(-50%);
117
+ color: t.color("on-surface");
118
+ pointer-events: none;
119
+ z-index: 2; // Increased to ensure it stays above input
120
+ white-space: nowrap; // Prevent text wrapping
121
+ max-width: 40%; // Prevent extreme overflow
122
+ overflow: hidden;
123
+ text-overflow: ellipsis;
124
+ transition: top v.motion("duration-short4") v.motion("easing-emphasized"); // Add transition for top position
125
+ }
126
+
127
+ // Suffix text
128
+ &-suffix {
129
+ @include m.typography("body-large");
130
+ position: absolute;
131
+ right: 16px;
132
+ top: 50%;
133
+ transform: translateY(-50%);
134
+ color: t.color("on-surface");
135
+ pointer-events: none;
136
+ z-index: 2; // Increased to ensure it stays above input
137
+ white-space: nowrap; // Prevent text wrapping
138
+ max-width: 40%; // Prevent extreme overflow
139
+ overflow: hidden;
140
+ text-overflow: ellipsis;
141
+ transition: top v.motion("duration-short4") v.motion("easing-emphasized"); // Add transition for top position
142
+ }
143
+
144
+ // Leading icon
145
+ &-leading-icon {
146
+ opacity: 0.85;
147
+ position: absolute;
148
+ left: 12px;
149
+ top: 50%;
150
+ transform: translateY(-50%);
151
+ display: flex;
152
+ align-items: center;
153
+ justify-content: center;
154
+ width: 24px;
155
+ height: 24px;
156
+ pointer-events: none;
157
+ color: t.color("on-surface-variant");
158
+ z-index: 1;
159
+ transition: top v.motion("duration-short4") v.motion("easing-emphasized"); // Add transition for top position
160
+
161
+ svg {
162
+ width: 20px;
163
+ height: 20px;
164
+ }
165
+ }
166
+
167
+ // Trailing icon
168
+ &-trailing-icon {
169
+ opacity: 0.85;
170
+ position: absolute;
171
+ right: 12px;
172
+ top: 50%;
173
+ transform: translateY(-50%);
174
+ display: flex;
175
+ align-items: center;
176
+ justify-content: center;
177
+ width: 24px;
178
+ height: 24px;
179
+ color: t.color("on-surface-variant");
180
+ z-index: 1;
181
+ cursor: pointer;
182
+ transition: top v.motion("duration-short4") v.motion("easing-emphasized"); // Add transition for top position
183
+
184
+ svg {
185
+ width: 20px;
186
+ height: 20px;
187
+ }
188
+ }
189
+
190
+ // Adjustments when prefix/suffix are present - base case styling
191
+ // JavaScript will handle dynamic sizing, these are fallbacks
192
+ &--with-prefix {
193
+ .#{$component}-label {
194
+ // Default value - will be overridden by JS for precise positioning
195
+ left: 48px;
196
+ }
197
+
198
+ .#{$component}-input {
199
+ // Default value - will be overridden by JS for precise padding
200
+ padding-left: 48px;
201
+ }
202
+ }
203
+
204
+ &--with-suffix {
205
+ .#{$component}-input {
206
+ // Default value - will be overridden by JS for precise padding
207
+ padding-right: 48px;
208
+ }
209
+ }
210
+
211
+ // Adjustments when icons are present
212
+ &--with-leading-icon {
213
+ .#{$component}-label {
214
+ left: 44px;
215
+ }
216
+
217
+ .#{$component}-input {
218
+ padding-left: 44px;
219
+ }
220
+
221
+ // If there's also a prefix, adjust positions
222
+ &.#{$component}--with-prefix {
223
+ .#{$component}-prefix {
224
+ left: 44px;
225
+ }
226
+
227
+ .#{$component}-label {
228
+ // Default value - will be overridden by JS for precise positioning
229
+ left: 76px;
230
+ }
231
+
232
+ .#{$component}-input {
233
+ // Default value - will be overridden by JS for precise padding
234
+ padding-left: 76px;
235
+ }
236
+ }
237
+ }
238
+
239
+ &--with-trailing-icon {
240
+ .#{$component}-input {
241
+ padding-right: 44px;
242
+ }
243
+
244
+ // If there's also a suffix, adjust positions
245
+ &.#{$component}--with-suffix {
246
+ .#{$component}-suffix {
247
+ right: 44px;
248
+ }
249
+
250
+ .#{$component}-input {
251
+ // Default value - will be overridden by JS for precise padding
252
+ padding-right: 76px;
253
+ }
254
+ }
255
+ }
256
+
257
+ // Error state
258
+ &--error {
259
+ border-color: t.color("error");
260
+
261
+ .#{$component}-label {
262
+ color: t.color("error");
263
+ }
264
+
265
+ .#{$component}-leading-icon,
266
+ .#{$component}-trailing-icon,
267
+ .#{$component}-prefix,
268
+ .#{$component}-suffix {
269
+ color: t.color("error");
270
+ }
271
+ }
272
+
273
+ // Disabled state
274
+ &--disabled {
275
+ .#{$component}-input {
276
+ opacity: 0.38;
277
+ border-color: t.color("on-surface");
278
+ background-color: t.alpha("on-surface", 0.04);
279
+ pointer-events: none;
280
+ }
281
+
282
+ .#{$component}-label {
283
+ color: t.color("on-surface");
284
+ opacity: 0.38;
285
+ }
286
+
287
+ .#{$component}-leading-icon,
288
+ .#{$component}-trailing-icon,
289
+ .#{$component}-prefix,
290
+ .#{$component}-suffix {
291
+ color: t.color("on-surface");
292
+ opacity: 0.38;
293
+ }
294
+ }
295
+
296
+ // Disabled state - legacy support for direct input disabled
297
+ &-input:disabled {
298
+ opacity: 0.38;
299
+ border-color: t.color("on-surface");
300
+ background-color: t.alpha("on-surface", 0.04);
301
+ pointer-events: none;
302
+
303
+ & ~ .#{$component}-label,
304
+ & ~ .#{$component}-leading-icon,
305
+ & ~ .#{$component}-trailing-icon,
306
+ & ~ .#{$component}-prefix,
307
+ & ~ .#{$component}-suffix {
308
+ color: t.color("on-surface");
309
+ opacity: 0.38;
310
+ }
311
+ }
312
+
313
+ // Helper text / Supporting text
314
+ &-helper {
315
+ @include m.typography("body-small");
316
+ position: absolute;
317
+ bottom: -18px;
318
+ left: 16px;
319
+ margin-top: 4px;
320
+ color: t.color("on-surface-variant");
321
+
322
+ &--error {
323
+ color: t.color("error");
324
+ }
325
+ }
326
+
327
+ // Required indicator
328
+ &-required {
329
+ color: t.color("error");
330
+ margin-left: 4px;
331
+ }
332
+
333
+ // Accessibility
334
+ @include m.reduced-motion {
335
+ &-label {
336
+ transition: none;
337
+ }
338
+
339
+ &-prefix,
340
+ &-suffix,
341
+ &-leading-icon,
342
+ &-trailing-icon {
343
+ transition: none;
344
+ }
345
+ }
346
+
347
+ // RTL support
348
+ @include m.rtl {
349
+ &-label {
350
+ left: auto;
351
+ right: 16px;
352
+ transform-origin: right top;
353
+ }
354
+
355
+ &-required {
356
+ margin-left: 0;
357
+ margin-right: 4px;
358
+ }
359
+
360
+ &-prefix {
361
+ left: auto;
362
+ right: 16px;
363
+ }
364
+
365
+ &-suffix {
366
+ right: auto;
367
+ left: 16px;
368
+ }
369
+
370
+ &-leading-icon {
371
+ left: auto;
372
+ right: 12px;
373
+ }
374
+
375
+ &-trailing-icon {
376
+ right: auto;
377
+ left: 12px;
378
+ }
379
+
380
+ &--with-prefix {
381
+ .#{$component}-label {
382
+ left: auto;
383
+ // Default value - will be overridden by JS for precise positioning
384
+ right: 48px;
385
+ }
386
+
387
+ .#{$component}-input {
388
+ padding-left: 16px;
389
+ // Default value - will be overridden by JS for precise padding
390
+ padding-right: 48px;
391
+ }
392
+ }
393
+
394
+ &--with-suffix {
395
+ .#{$component}-input {
396
+ padding-right: 16px;
397
+ // Default value - will be overridden by JS for precise padding
398
+ padding-left: 48px;
399
+ }
400
+ }
401
+
402
+ &--with-leading-icon {
403
+ .#{$component}-label {
404
+ left: auto;
405
+ right: 44px;
406
+ }
407
+
408
+ .#{$component}-input {
409
+ padding-left: 16px;
410
+ padding-right: 44px;
411
+ }
412
+
413
+ &.#{$component}--with-prefix {
414
+ .#{$component}-prefix {
415
+ left: auto;
416
+ right: 44px;
417
+ }
418
+
419
+ .#{$component}-label {
420
+ left: auto;
421
+ // Default value - will be overridden by JS for precise positioning
422
+ right: 76px;
423
+ }
424
+
425
+ .#{$component}-input {
426
+ padding-left: 16px;
427
+ // Default value - will be overridden by JS for precise padding
428
+ padding-right: 76px;
429
+ }
430
+ }
431
+ }
432
+
433
+ &--with-trailing-icon {
434
+ .#{$component}-input {
435
+ padding-right: 16px;
436
+ padding-left: 44px;
437
+ }
438
+
439
+ &.#{$component}--with-suffix {
440
+ .#{$component}-suffix {
441
+ right: auto;
442
+ left: 44px;
443
+ }
444
+
445
+ .#{$component}-input {
446
+ padding-right: 16px;
447
+ // Default value - will be overridden by JS for precise padding
448
+ padding-left: 76px;
449
+ }
450
+ }
451
+ }
452
+ }
453
+
454
+ // ===== FILLED VARIANT =====
455
+ &--filled {
456
+ .#{$component}-input {
457
+ background-color: t.color("surface-container-highest");
458
+ padding: 20px 16px 7px;
459
+ border-bottom: 1px solid t.color("outline");
460
+ border-radius: f.get-shape("extra-small") f.get-shape("extra-small") 0 0;
461
+ @include m.motion-transition(background-color, border-color);
462
+
463
+ // Autofill styles for filled variant
464
+ &:-webkit-autofill {
465
+ border-radius: f.get-shape("extra-small") f.get-shape("extra-small") 0 0;
466
+
467
+ & ~ .#{$component}-label {
468
+ transform: translateY(-95%) scale(0.75);
469
+ color: t.color("on-surface-variant");
470
+ }
471
+ }
472
+
473
+ &:autofill {
474
+ & ~ .#{$component}-label {
475
+ transform: translateY(-95%) scale(0.75);
476
+ color: t.color("on-surface-variant");
477
+ }
478
+ }
479
+ }
480
+
481
+ &::before {
482
+ content: "";
483
+ position: absolute;
484
+ opacity: 0;
485
+ bottom: 0;
486
+ width: 100%;
487
+ height: 2px;
488
+ background-color: t.color("primary");
489
+ border-radius: 0;
490
+ pointer-events: none;
491
+ transition: 0.2s opacity ease;
492
+ }
493
+
494
+ // Populated field (not empty) or focused field label position
495
+ &:not(.#{$component}--empty) .#{$component}-label,
496
+ &.#{$component}--focused .#{$component}-label {
497
+ transform: translateY(-95%) scale(0.75);
498
+ // Don't specify left position here - let JS handle it
499
+ }
500
+
501
+ // CSS-only fallback for when input has value (works without JS)
502
+ .#{$component}-input:not(:placeholder-shown) ~ .#{$component}-label {
503
+ transform: translateY(-95%) scale(0.75);
504
+ }
505
+
506
+ // Position adjustments for prefix/suffix when in filled focused/populated state
507
+ &.mtrl-textfield--with-prefix,
508
+ &.mtrl-textfield--with-suffix {
509
+ &:not(.#{$component}--empty),
510
+ &.#{$component}--focused {
511
+ .#{$component}-prefix,
512
+ .#{$component}-suffix {
513
+ top: 34px; // Align with input text when focused or populated
514
+ }
515
+ }
516
+ }
517
+ // Focus state
518
+ &.#{$component}--focused {
519
+ .#{$component}-label {
520
+ color: t.color("primary");
521
+ }
522
+
523
+ &::before {
524
+ opacity: 1;
525
+ }
526
+ }
527
+
528
+ // Error state
529
+ &.#{$component}--error {
530
+ &::before {
531
+ opacity: 1;
532
+ background-color: t.color("error");
533
+ }
534
+
535
+ .#{$component}-label {
536
+ color: t.color("error");
537
+ }
538
+ }
539
+
540
+ // Disabled state
541
+ &.#{$component}--disabled {
542
+ border-bottom-color: t.alpha("on-surface", 0.38);
543
+ pointer-events: none;
544
+
545
+ .#{$component}-input {
546
+ background-color: t.alpha("on-surface", 0.04);
547
+ }
548
+ }
549
+
550
+ // Prefix/suffix adjustments for filled variant
551
+ &.#{$component}--with-prefix {
552
+ .#{$component}-prefix {
553
+ top: 28px; // Align with input text in filled variant - default state
554
+ }
555
+ }
556
+
557
+ &.#{$component}--with-suffix {
558
+ .#{$component}-suffix {
559
+ top: 28px; // Align with input text in filled variant - default state
560
+ }
561
+ }
562
+
563
+ // Icon adjustments for filled variant
564
+ &.#{$component}--with-leading-icon {
565
+ .#{$component}-input {
566
+ padding: 20px 16px 7px 44px;
567
+ }
568
+
569
+ .#{$component}-label {
570
+ left: 44px;
571
+ }
572
+
573
+ .#{$component}-leading-icon {
574
+ top: 28px;
575
+ }
576
+ }
577
+
578
+ // Populated field (not empty) or focused field label position
579
+ &:not(.#{$component}--empty) .#{$component}-label,
580
+ &.#{$component}--focused .#{$component}-label {
581
+ // Important change: For outlined variant, when focused/populated
582
+ // we want to reset the left position back to default (or to JS calculated equivalent)
583
+ // to handle the label moving up above the field
584
+ // The JS will handle special positioning depending on if it's prefixed
585
+ left: 16px;
586
+ }
587
+
588
+ &.#{$component}--with-trailing-icon {
589
+ .#{$component}-input {
590
+ padding-right: 44px;
591
+ }
592
+
593
+ .#{$component}-trailing-icon {
594
+ top: 28px;
595
+ }
596
+ }
597
+
598
+ // RTL support
599
+ @include m.rtl {
600
+ .#{$component}-label {
601
+ left: auto;
602
+ right: 16px;
603
+ }
604
+
605
+ &.#{$component}--with-leading-icon {
606
+ .#{$component}-input {
607
+ padding: 20px 44px 7px 16px;
608
+ }
609
+
610
+ .#{$component}-label {
611
+ left: auto;
612
+ right: 44px;
613
+ }
614
+ }
615
+
616
+ &.#{$component}--with-trailing-icon {
617
+ .#{$component}-input {
618
+ padding-right: 16px;
619
+ padding-left: 44px;
620
+ }
621
+ }
622
+ }
623
+ }
624
+
625
+ // ===== OUTLINED VARIANT =====
626
+ &--outlined {
627
+ background-color: inherit;
628
+ border-radius: f.get-shape("extra-small");
629
+ @include m.motion-transition(border-color);
630
+
631
+ .#{$component}-input {
632
+ background-color: transparent;
633
+ padding: 12px 15px 13px;
634
+ border: 1px solid t.color("outline");
635
+ @include m.motion-transition(padding);
636
+
637
+ // Autofill styles for outlined variant
638
+ &:-webkit-autofill {
639
+ border-radius: f.get-shape("extra-small");
640
+
641
+ & ~ .#{$component}-label {
642
+ background-color: t.color("surface");
643
+ transform: translateY(-145%) scale(0.75);
644
+ }
645
+ }
646
+
647
+ &:autofill {
648
+ & ~ .#{$component}-label {
649
+ background-color: t.color("surface");
650
+ transform: translateY(-145%) scale(0.75);
651
+ }
652
+ }
653
+ }
654
+
655
+ .#{$component}-label {
656
+ background-color: inherit;
657
+ padding: 0 4px;
658
+ left: 14px;
659
+ top: 50%;
660
+ }
661
+
662
+ &::before {
663
+ content: "";
664
+ position: absolute;
665
+ opacity: 0;
666
+ width: 100%;
667
+ height: 100%;
668
+ border: 1.5px solid t.color("primary");
669
+ border-radius: f.get-shape("extra-small");
670
+ pointer-events: none;
671
+ transition: 0.1s opacity ease;
672
+ }
673
+
674
+ // Populated field (not empty) or focused field label position
675
+ &:not(.#{$component}--empty) .#{$component}-label,
676
+ &.#{$component}--focused .#{$component}-label {
677
+ padding: 0 4px;
678
+ transform: translateY(-147%) scale(0.75);
679
+ // Important change: For outlined variant, when focused/populated
680
+ // we want to reset the left position back to default (or to JS calculated equivalent)
681
+ // to handle the label moving up above the field
682
+ // The JS will handle special positioning depending on if it's prefixed
683
+ left: 14px;
684
+ }
685
+
686
+ // CSS-only fallback for when input has value (works without JS)
687
+ .#{$component}-input:not(:placeholder-shown) ~ .#{$component}-label {
688
+ padding: 0 4px;
689
+ transform: translateY(-147%) scale(0.75);
690
+ left: 14px;
691
+ background-color: t.color("surface");
692
+ }
693
+
694
+ // Focus state
695
+ &.#{$component}--focused {
696
+ &::before {
697
+ opacity: 1;
698
+ border-width: 2px;
699
+ }
700
+ // &:hover {
701
+ // &::before {
702
+
703
+ // }
704
+ // }
705
+
706
+ .#{$component}-label {
707
+ color: t.color("primary");
708
+ }
709
+ }
710
+
711
+ // Error state
712
+ &.#{$component}--error {
713
+ &::before {
714
+ opacity: 1;
715
+ border: 2px solid t.color("error");
716
+ }
717
+
718
+ .#{$component}-label {
719
+ color: t.color("error");
720
+ }
721
+ }
722
+
723
+ // Disabled state
724
+ &.#{$component}--disabled {
725
+ pointer-events: none;
726
+ &::before {
727
+ opacity: 1;
728
+ border: 1px solid t.alpha("on-surface", 0.38);
729
+ }
730
+ }
731
+
732
+ // Prefix/suffix vertical alignment for outlined variant
733
+ &.#{$component}--with-prefix {
734
+ .#{$component}-prefix {
735
+ top: 50%; // Centered vertically in outlined variant
736
+ }
737
+ }
738
+
739
+ &.#{$component}--with-suffix {
740
+ .#{$component}-suffix {
741
+ top: 50%; // Centered vertically in outlined variant
742
+ }
743
+ }
744
+
745
+ // Icon adjustments for outlined variant
746
+ &.#{$component}--with-leading-icon {
747
+ .#{$component}-input {
748
+ padding-left: 44px;
749
+ }
750
+
751
+ .#{$component}-label {
752
+ left: 44px;
753
+ }
754
+
755
+ // Important change: For outlined variant, when focused/populated
756
+ // we still reset to 12px position (default)
757
+ &:not(.#{$component}--empty) .#{$component}-label,
758
+ &.#{$component}--focused .#{$component}-label {
759
+ left: 14px;
760
+ }
761
+ }
762
+
763
+ &.#{$component}--with-trailing-icon {
764
+ .#{$component}-input {
765
+ padding-right: 44px;
766
+ }
767
+ }
768
+
769
+ // RTL support
770
+ @include m.rtl {
771
+ &:not(.#{$component}--empty) .#{$component}-label,
772
+ &.#{$component}--focused .#{$component}-label {
773
+ left: auto;
774
+ right: 12px;
775
+ }
776
+
777
+ &.#{$component}--focused .#{$component}-label {
778
+ right: 12px;
779
+ }
780
+
781
+ &.#{$component}--error .#{$component}-label {
782
+ right: 12px;
783
+ }
784
+
785
+ &.#{$component}--with-leading-icon {
786
+ .#{$component}-input {
787
+ padding-left: 16px;
788
+ padding-right: 44px;
789
+ }
790
+
791
+ .#{$component}-label {
792
+ left: auto;
793
+ right: 44px;
794
+ }
795
+
796
+ &:not(.#{$component}--empty) .#{$component}-label,
797
+ &.#{$component}--focused .#{$component}-label {
798
+ // Reset to default value for focused state
799
+ right: 12px;
800
+ left: auto;
801
+ }
802
+ }
803
+
804
+ &.#{$component}--with-trailing-icon {
805
+ .#{$component}-input {
806
+ padding-right: 16px;
807
+ padding-left: 44px;
808
+ }
809
+ }
810
+ }
811
+ }
812
+
813
+ // Multiline styles
814
+ &--multiline {
815
+ .#{$component}-input {
816
+ min-height: 100px;
817
+ height: auto;
818
+ resize: vertical;
819
+ padding-top: 12px;
820
+ }
821
+
822
+ .#{$component}-prefix,
823
+ .#{$component}-suffix {
824
+ top: 28px;
825
+ }
826
+
827
+ .#{$component}-label {
828
+ top: 24px;
829
+ }
830
+ }
831
+
832
+ // Support for multiline inputs
833
+ &-input[type="multiline"] {
834
+ min-height: 100px;
835
+ height: auto; // Allow height to adjust based on content
836
+ max-height: none; // Remove max-height constraint from regular inputs
837
+ flex-shrink: 1; // Allow some shrinking for multiline
838
+
839
+ & ~ .#{$component}-leading-icon,
840
+ & ~ .#{$component}-trailing-icon,
841
+ & ~ .#{$component}-prefix,
842
+ & ~ .#{$component}-suffix {
843
+ top: 20px;
844
+ transform: none;
845
+ }
846
+ }
847
+
848
+ // ===== DENSITY VARIANTS =====
849
+ // Compact density (40px height)
850
+ &--density-compact {
851
+ .#{$component}-input {
852
+ height: 40px;
853
+ padding: 8px 16px;
854
+ @include m.typography("body-medium"); // Slightly smaller text
855
+ }
856
+
857
+ // Adjust label position for compact
858
+ .#{$component}-label {
859
+ @include m.typography("body-medium");
860
+ }
861
+
862
+ // Adjust icon positions for compact height
863
+ .#{$component}-leading-icon,
864
+ .#{$component}-trailing-icon {
865
+ width: 20px;
866
+ height: 20px;
867
+
868
+ svg {
869
+ width: 16px;
870
+ height: 16px;
871
+ }
872
+ }
873
+
874
+ // Adjust prefix/suffix position for compact
875
+ .#{$component}-prefix,
876
+ .#{$component}-suffix {
877
+ @include m.typography("body-medium");
878
+ }
879
+
880
+ // Filled variant with compact density
881
+ &.#{$component}--filled {
882
+ .#{$component}-input {
883
+ padding: 12px 16px 4px; // Adjusted for filled variant
884
+ }
885
+
886
+ // Populated/focused label position
887
+ &:not(.#{$component}--empty) .#{$component}-label,
888
+ &.#{$component}--focused .#{$component}-label {
889
+ transform: translateY(-90%) scale(0.75); // Adjusted for compact height
890
+ }
891
+
892
+ // Adjust prefix/suffix position when focused/populated
893
+ &.mtrl-textfield--with-prefix,
894
+ &.mtrl-textfield--with-suffix {
895
+ &:not(.#{$component}--empty),
896
+ &.#{$component}--focused {
897
+ .#{$component}-prefix,
898
+ .#{$component}-suffix {
899
+ top: 22px; // Adjusted for compact filled variant
900
+ }
901
+ }
902
+ }
903
+
904
+ // Adjust icons for filled compact
905
+ .#{$component}-leading-icon,
906
+ .#{$component}-trailing-icon {
907
+ top: 20px; // Adjusted for compact filled
908
+ }
909
+ }
910
+
911
+ // Outlined variant with compact density
912
+ &.#{$component}--outlined {
913
+ .#{$component}-input {
914
+ padding: 8px 15px 9px;
915
+ }
916
+
917
+ // Focused/populated position
918
+ &:not(.#{$component}--empty) .#{$component}-label,
919
+ &.#{$component}--focused .#{$component}-label {
920
+ transform: translateY(-130%) scale(0.75); // Same as default, scale is important
921
+ }
922
+ }
923
+
924
+ // Multiline with compact density
925
+ &.#{$component}--multiline {
926
+ .#{$component}-input {
927
+ min-height: 40px;
928
+ padding: 8px 16px;
929
+ }
930
+ }
931
+
932
+ // Adjust element positions for compact with icons
933
+ &.#{$component}--with-leading-icon {
934
+ .#{$component}-label {
935
+ left: 40px; // Reduced from 44px
936
+ }
937
+
938
+ .#{$component}-input {
939
+ padding-left: 40px;
940
+ }
941
+
942
+ &.#{$component}--with-prefix {
943
+ .#{$component}-prefix {
944
+ left: 40px;
945
+ }
946
+
947
+ .#{$component}-label {
948
+ left: 68px; // Adjusted for compact
949
+ }
950
+
951
+ .#{$component}-input {
952
+ padding-left: 68px;
953
+ }
954
+ }
955
+ }
956
+
957
+ &.#{$component}--with-trailing-icon {
958
+ .#{$component}-input {
959
+ padding-right: 40px;
960
+ }
961
+
962
+ &.#{$component}--with-suffix {
963
+ .#{$component}-suffix {
964
+ right: 40px;
965
+ }
966
+
967
+ .#{$component}-input {
968
+ padding-right: 68px;
969
+ }
970
+ }
971
+ }
972
+
973
+ // RTL adjustments for compact density
974
+ @include m.rtl {
975
+ &.#{$component}--with-leading-icon {
976
+ .#{$component}-label {
977
+ left: auto;
978
+ right: 40px;
979
+ }
980
+
981
+ .#{$component}-input {
982
+ padding-left: 16px;
983
+ padding-right: 40px;
984
+ }
985
+
986
+ &.#{$component}--with-prefix {
987
+ .#{$component}-prefix {
988
+ left: auto;
989
+ right: 40px;
990
+ }
991
+
992
+ .#{$component}-label {
993
+ left: auto;
994
+ right: 68px;
995
+ }
996
+
997
+ .#{$component}-input {
998
+ padding-left: 16px;
999
+ padding-right: 68px;
1000
+ }
1001
+ }
1002
+ }
1003
+
1004
+ &.#{$component}--with-trailing-icon {
1005
+ .#{$component}-input {
1006
+ padding-right: 16px;
1007
+ padding-left: 40px;
1008
+ }
1009
+
1010
+ &.#{$component}--with-suffix {
1011
+ .#{$component}-suffix {
1012
+ right: auto;
1013
+ left: 40px;
1014
+ }
1015
+
1016
+ .#{$component}-input {
1017
+ padding-right: 16px;
1018
+ padding-left: 68px;
1019
+ }
1020
+ }
1021
+ }
1022
+ }
1023
+ }
1024
+ }