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,756 @@
1
+ // src/components/button/_styles.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
+ $component: '#{base.$prefix}-button';
9
+
10
+ // =============================================================================
11
+ // BUTTON COMPONENT STYLES
12
+ // =============================================================================
13
+ // Supports:
14
+ // - Multiple variants (filled, elevated, tonal, outlined, text)
15
+ // - Icon integration
16
+ // - Progress indicator integration
17
+ // - Circular/icon-only buttons
18
+ // - Ripple effects
19
+ // - State layers
20
+ // - Accessibility focus indicators
21
+ // =============================================================================
22
+
23
+ .#{$component} {
24
+ // Base styles
25
+ position: relative;
26
+ display: inline-flex;
27
+ align-items: center;
28
+ justify-content: center;
29
+ min-width: v.button('min-width');
30
+ height: v.button('height');
31
+ padding: 0 v.button('padding-horizontal');
32
+ border: none;
33
+ border-radius: v.button('border-radius');
34
+ background-color: transparent;
35
+ color: inherit;
36
+ font: inherit;
37
+ text-decoration: none;
38
+ cursor: pointer;
39
+ user-select: none;
40
+ vertical-align: middle;
41
+ appearance: none;
42
+ overflow: hidden;
43
+ will-change: border-radius, transform;
44
+
45
+ // Typography
46
+ @include m.typography('label-large');
47
+
48
+ // Default to round shape (pill-shaped)
49
+ border-radius: v.button('border-radius');
50
+
51
+ // Explicitly apply fast transition to border-radius
52
+ transition:
53
+ background-color v.motion('duration-short2') v.motion('easing-standard'),
54
+ color v.motion('duration-short2') v.motion('easing-standard'),
55
+ box-shadow v.motion('duration-short2') v.motion('easing-standard'),
56
+ border-radius v.motion('duration-short1') v.motion('easing-standard-accelerate'),
57
+ transform v.motion('duration-short1') v.motion('easing-standard-accelerate');
58
+
59
+ // Focus styles
60
+ &:focus {
61
+ outline: none;
62
+ }
63
+
64
+ &:focus-visible {
65
+ outline: 2px solid t.color('outline');
66
+ outline-offset: 2px;
67
+ }
68
+
69
+ // Interactive states
70
+ &:disabled {
71
+ pointer-events: none;
72
+ color: t.alpha('surface', 0.38);
73
+ background-color: t.alpha('surface', 0.12);
74
+
75
+ .#{$component}-icon {
76
+ color: t.alpha('surface', 0.38);
77
+ }
78
+ }
79
+
80
+ // State layer for ripple effect
81
+ &::before {
82
+ content: '';
83
+ position: absolute;
84
+ top: 0;
85
+ left: 0;
86
+ right: 0;
87
+ bottom: 0;
88
+ background-color: currentColor;
89
+ opacity: 0;
90
+ pointer-events: none;
91
+ transition: opacity 0.2s cubic-bezier(0.4, 0, 0.2, 1);
92
+ }
93
+
94
+ // Ensure proper layout with icons
95
+ &-icon {
96
+ display: inline-flex;
97
+ align-items: center;
98
+ justify-content: center;
99
+ width: 22px;
100
+ height: 22px;
101
+
102
+ svg {
103
+ width: 22px;
104
+ height: 22px;
105
+ }
106
+
107
+ + .#{$component}-text {
108
+ margin-left: 8px;
109
+ }
110
+ }
111
+
112
+ // Progress element styling
113
+ &-progress {
114
+ display: inline-flex;
115
+ align-items: center;
116
+ justify-content: center;
117
+ margin-inline-end: 8px;
118
+ width: 20px;
119
+ height: 20px;
120
+
121
+ // When it's the mtrl-progress element itself
122
+ &.#{base.$prefix}-progress {
123
+ // Reset progress default size since we're setting it here
124
+ width: 20px;
125
+ height: 20px;
126
+
127
+ &-canvas {
128
+ color: currentColor;
129
+ }
130
+ }
131
+
132
+ // In text-only buttons (no icon), progress acts like an icon
133
+ &:first-child {
134
+ margin-inline-start: 0;
135
+ }
136
+
137
+ // When following a visible icon, add left margin too
138
+ .#{$component}-icon:not([style*="display: none"]) + & {
139
+ margin-inline-start: 4px;
140
+ }
141
+ }
142
+
143
+ &-text {
144
+ // Text truncation for long button labels
145
+ @include m.truncate;
146
+
147
+ .#{$component}--icon-only & {
148
+ @include m.visually-hidden;
149
+ }
150
+ }
151
+
152
+ // Circular buttons
153
+ &--circular {
154
+ flex: none !important;
155
+ border-radius: 50%;
156
+ padding: 8px;
157
+ min-width: unset;
158
+ width: 40px !important ;
159
+ height: 40px;
160
+ display: inline-flex;
161
+ align-items: center;
162
+ justify-content: center;
163
+
164
+ // Material Design 3 Accessibility Requirement:
165
+ // Icon buttons must have a minimum touch target of 48x48dp
166
+ // even when their visual size appears smaller
167
+
168
+ // Circular buttons should always remain circular when pressed
169
+ &:active,
170
+ &.#{$component}--active {
171
+ border-radius: 50%;
172
+ &.#{$component}--square {
173
+ border-radius: 12px !important;
174
+ }
175
+ }
176
+
177
+ &.#{$component}--square {
178
+ border-radius: 12px;
179
+ }
180
+
181
+ // Size-specific circular button dimensions
182
+ &.#{$component}--xs {
183
+ // Ensure minimum 48dp touch target for accessibility
184
+ width: v.button('height-xs');
185
+ height: v.button('height-xs');
186
+ padding: 8px;
187
+
188
+
189
+ // Adjust icon size to maintain visual proportions
190
+ .#{$component}-icon {
191
+ width: v.button('icon-size-xs');
192
+ height: v.button('icon-size-xs');
193
+
194
+ svg {
195
+ width: v.button('icon-size-xs');
196
+ height: v.button('icon-size-xs');
197
+ }
198
+ }
199
+
200
+
201
+ }
202
+
203
+ &.#{$component}--s {
204
+ // Ensure minimum 48dp touch target for accessibility
205
+ width: v.button('height-s');
206
+ height: v.button('height-s');
207
+ padding: 8px;
208
+
209
+ // Standard icon size for S
210
+ .#{$component}-icon {
211
+ width: v.button('icon-size-s');
212
+ height: v.button('icon-size-s');
213
+
214
+ svg {
215
+ width: v.button('icon-size-s');
216
+ height: v.button('icon-size-s');
217
+ }
218
+ }
219
+ }
220
+
221
+ &.#{$component}--m {
222
+ width: v.button('height-m');
223
+ height: v.button('height-m');
224
+ padding: 12px;
225
+ }
226
+
227
+ &.#{$component}--l {
228
+ width: v.button('height-l');
229
+ height: v.button('height-l');
230
+ padding: 20px;
231
+ }
232
+
233
+ &.#{$component}--xl {
234
+ width: v.button('height-xl');
235
+ height: v.button('height-xl');
236
+ padding: 32px;
237
+ }
238
+
239
+ .#{$component}-icon {
240
+ margin: 0;
241
+ }
242
+
243
+ // Hide text in circular buttons
244
+ .#{$component}-text {
245
+ display: none;
246
+ }
247
+
248
+ // Progress in circular buttons
249
+ .#{$component}-progress {
250
+ margin: 0;
251
+
252
+ &.#{base.$prefix}-progress {
253
+ width: 24px;
254
+ height: 24px;
255
+ }
256
+ }
257
+
258
+ // Override padding adjustments for circular buttons
259
+ &.#{$component}--progress {
260
+ padding: 0 !important;
261
+ }
262
+ }
263
+
264
+ &--icon {
265
+ padding: 0 v.button('padding-horizontal') 0 calc(v.button('padding-horizontal') / 2 + 4px);
266
+ }
267
+
268
+ // Shape variants
269
+ &--round {
270
+ // Default round shape - already applied in base styles
271
+ // Sizes M, L, XL get special pill-shaped radius
272
+ &.#{$component}--m {
273
+ border-radius: calc(v.button('height-m') / 2);
274
+ }
275
+
276
+ &.#{$component}--l {
277
+ border-radius: calc(v.button('height-l') / 2);
278
+ }
279
+
280
+ &.#{$component}--xl {
281
+ border-radius: calc(v.button('height-xl') / 2);
282
+ }
283
+ }
284
+
285
+ &--square {
286
+ // Square shape with size-specific border radius
287
+ &.#{$component}--xs,
288
+ &.#{$component}--s {
289
+ border-radius: f.get-shape('medium'); // 12dp
290
+ }
291
+
292
+ &.#{$component}--m {
293
+ border-radius: f.get-shape('large'); // 16dp
294
+ }
295
+
296
+ &.#{$component}--l,
297
+ &.#{$component}--xl {
298
+ border-radius: f.get-shape('extra-large'); // 28dp
299
+ }
300
+
301
+ // Pressed state for square buttons - no morphing needed
302
+ &:active,
303
+ &.#{$component}--active {
304
+ // Square buttons maintain their border radius when pressed
305
+ }
306
+ }
307
+
308
+ // Size variants
309
+ &--xs {
310
+ height: v.button('height-xs');
311
+ padding: 0 v.button('padding-xs');
312
+ min-width: 48px;
313
+
314
+ &.#{$component}--icon {
315
+ padding: 0 v.button('padding-xs') 0 calc(v.button('padding-xs') / 2 + 4px);
316
+ }
317
+
318
+ &.#{$component}--progress {
319
+ padding: 0 v.button('padding-xs') 0 calc(v.button('padding-xs') / 2 + 4px);
320
+ }
321
+
322
+ &.#{$component}--text {
323
+ padding: 0 calc(v.button('padding-xs') - 4px);
324
+ }
325
+
326
+ .#{$component}-icon {
327
+ width: v.button('icon-size-xs');
328
+ height: v.button('icon-size-xs');
329
+
330
+ svg {
331
+ width: v.button('icon-size-xs');
332
+ height: v.button('icon-size-xs');
333
+ }
334
+ }
335
+
336
+ .#{$component}-progress {
337
+ width: v.button('icon-size-xs');
338
+ height: v.button('icon-size-xs');
339
+
340
+ &.#{base.$prefix}-progress {
341
+ width: v.button('icon-size-xs');
342
+ height: v.button('icon-size-xs');
343
+ }
344
+ }
345
+ }
346
+
347
+ &--s {
348
+ // S is the default size, already defined in base styles
349
+ // Explicitly setting them here for clarity
350
+ height: v.button('height-s');
351
+ padding: 0 v.button('padding-s');
352
+
353
+ &.#{$component}--icon {
354
+ padding: 0 v.button('padding-s') 0 calc(v.button('padding-s') / 2 + 4px);
355
+ }
356
+
357
+ &.#{$component}--progress {
358
+ padding: 0 v.button('padding-s') 0 calc(v.button('padding-s') / 2 + 4px);
359
+ }
360
+
361
+ &.#{$component}--text {
362
+ padding: 0 v.button('padding-horizontal-small');
363
+ }
364
+ }
365
+
366
+ &--m {
367
+ height: v.button('height-m');
368
+ padding: 0 v.button('padding-m');
369
+ min-width: 80px;
370
+
371
+ &.#{$component}--icon {
372
+ padding: 0 v.button('padding-m') 0 calc(v.button('padding-m') / 2 + 8px);
373
+ }
374
+
375
+ &.#{$component}--progress {
376
+ padding: 0 v.button('padding-m') 0 calc(v.button('padding-m') / 2 + 8px);
377
+ }
378
+
379
+ &.#{$component}--text {
380
+ padding: 0 calc(v.button('padding-m') - 4px);
381
+ }
382
+
383
+ .#{$component}-icon {
384
+ width: v.button('icon-size-m');
385
+ height: v.button('icon-size-m');
386
+
387
+ svg {
388
+ width: v.button('icon-size-m');
389
+ height: v.button('icon-size-m');
390
+ }
391
+ }
392
+
393
+ .#{$component}-progress {
394
+ width: v.button('icon-size-m');
395
+ height: v.button('icon-size-m');
396
+
397
+ &.#{base.$prefix}-progress {
398
+ width: v.button('icon-size-m');
399
+ height: v.button('icon-size-m');
400
+ }
401
+ }
402
+ }
403
+
404
+ &--l {
405
+ height: v.button('height-l');
406
+ padding: 0 v.button('padding-l');
407
+ min-width: 120px;
408
+
409
+ // Use larger typography for L and XL sizes
410
+ @include m.typography('title-large');
411
+
412
+ &.#{$component}--icon {
413
+ padding: 0 v.button('padding-l') 0 calc(v.button('padding-l') / 2 + 12px);
414
+ }
415
+
416
+ &.#{$component}--progress {
417
+ padding: 0 v.button('padding-l') 0 calc(v.button('padding-l') / 2 + 12px);
418
+ }
419
+
420
+ &.#{$component}--text {
421
+ padding: 0 calc(v.button('padding-l') - 8px);
422
+ }
423
+
424
+ .#{$component}-icon {
425
+ width: v.button('icon-size-l');
426
+ height: v.button('icon-size-l');
427
+
428
+ svg {
429
+ width: v.button('icon-size-l');
430
+ height: v.button('icon-size-l');
431
+ }
432
+
433
+ + .#{$component}-text {
434
+ margin-left: 16px;
435
+ }
436
+ }
437
+
438
+ .#{$component}-progress {
439
+ width: v.button('icon-size-l');
440
+ height: v.button('icon-size-l');
441
+ margin-inline-end: 16px;
442
+
443
+ &.#{base.$prefix}-progress {
444
+ width: v.button('icon-size-l');
445
+ height: v.button('icon-size-l');
446
+ }
447
+ }
448
+ }
449
+
450
+ &--xl {
451
+ height: v.button('height-xl');
452
+ padding: 0 v.button('padding-xl');
453
+ min-width: 160px;
454
+
455
+ // Use larger typography for L and XL sizes
456
+ @include m.typography('headline-medium');
457
+
458
+ &.#{$component}--icon {
459
+ padding: 0 v.button('padding-xl') 0 calc(v.button('padding-xl') / 2 + 16px);
460
+ }
461
+
462
+ &.#{$component}--progress {
463
+ padding: 0 v.button('padding-xl') 0 calc(v.button('padding-xl') / 2 + 16px);
464
+ }
465
+
466
+ &.#{$component}--text {
467
+ padding: 0 calc(v.button('padding-xl') - 12px);
468
+ }
469
+
470
+ .#{$component}-icon {
471
+ width: v.button('icon-size-xl');
472
+ height: v.button('icon-size-xl');
473
+
474
+ svg {
475
+ width: v.button('icon-size-xl');
476
+ height: v.button('icon-size-xl');
477
+ }
478
+
479
+ + .#{$component}-text {
480
+ margin-left: 24px;
481
+ }
482
+ }
483
+
484
+ .#{$component}-progress {
485
+ width: v.button('icon-size-xl');
486
+ height: v.button('icon-size-xl');
487
+ margin-inline-end: 24px;
488
+
489
+ &.#{base.$prefix}-progress {
490
+ width: v.button('icon-size-xl');
491
+ height: v.button('icon-size-xl');
492
+ }
493
+ }
494
+ }
495
+
496
+ &--active {
497
+ // Common active state styling for all variants
498
+ box-shadow: none;
499
+
500
+ // Per MD3, buttons have a significantly more rectangular appearance when pressed
501
+ // Default to small shape
502
+ border-radius: f.get-shape('small');
503
+
504
+ // ARIA attribute to indicate active state for accessibility
505
+ &[aria-expanded="true"] {
506
+ // For compatibility with ARIA
507
+ }
508
+ }
509
+
510
+ // Size-specific active state border radius based on MD3 specs
511
+ // Only applies to round shape buttons - square buttons maintain their radius
512
+ &--round {
513
+ &.#{$component}--xs,
514
+ &.#{$component}--s {
515
+ &:active,
516
+ &.#{$component}--active {
517
+ // XS and S sizes use 12dp radius when pressed
518
+ border-radius: f.get-shape('medium');
519
+ }
520
+ }
521
+
522
+ &.#{$component}--m {
523
+ &:active,
524
+ &.#{$component}--active {
525
+ // M size uses 16dp radius when pressed
526
+ border-radius: f.get-shape('large');
527
+ }
528
+ }
529
+
530
+ &.#{$component}--l,
531
+ &.#{$component}--xl {
532
+ &:active,
533
+ &.#{$component}--active {
534
+ // L and XL sizes use 28dp radius when pressed
535
+ border-radius: f.get-shape('extra-large');
536
+ }
537
+ }
538
+ }
539
+
540
+ // FILLED BUTTON
541
+ &--filled {
542
+ background-color: t.color('primary');
543
+ color: t.color('on-primary');
544
+
545
+ // Progress inherits the on-primary color
546
+ .#{base.$prefix}-progress-canvas {
547
+ color: t.color('on-primary');
548
+ }
549
+
550
+ &:hover {
551
+ @include m.state-layer(t.color('on-primary'), 'hover');
552
+ // According to MD3, filled buttons DO have elevation on hover
553
+ @include m.elevation(1);
554
+ }
555
+
556
+ &:active,
557
+ &.#{$component}--active {
558
+ @include m.state-layer(t.color('on-primary'), 'pressed');
559
+ // MD3 reduces elevation on press
560
+ @include m.elevation(0);
561
+ }
562
+ &:disabled {
563
+ @include m.elevation(0);
564
+ }
565
+ }
566
+
567
+ // ELEVATED BUTTON
568
+ &--elevated {
569
+ background-color: t.color('surface-container-low');
570
+ color: t.color('primary');
571
+ @include m.elevation(1);
572
+
573
+ // Progress uses primary color
574
+ .#{base.$prefix}-progress-canvas {
575
+ color: t.color('primary');
576
+ }
577
+
578
+ &:hover {
579
+ @include m.state-layer(t.color('primary'), 'hover');
580
+ // MD3 increases elevation on hover
581
+ @include m.elevation(2);
582
+ }
583
+
584
+ &:active,
585
+ &.#{$component}--active {
586
+ @include m.state-layer(t.color('primary'), 'pressed');
587
+ // MD3 reduces elevation on press, but not completely removed
588
+ @include m.elevation(1);
589
+ }
590
+
591
+ &:disabled {
592
+ @include m.elevation(0);
593
+ box-shadow: none;
594
+ }
595
+
596
+ // Handle icon color in elevated button
597
+ .#{$component}-icon {
598
+ color: t.color('primary');
599
+ }
600
+ }
601
+
602
+ // TONAL BUTTON
603
+ &--tonal {
604
+ background-color: t.color('secondary-container');
605
+ color: t.color('on-secondary-container');
606
+ // MD3 tonal buttons have a subtle initial elevation
607
+ @include m.elevation(0);
608
+
609
+ // Progress uses on-secondary-container color
610
+ .#{base.$prefix}-progress-canvas {
611
+ color: t.color('on-secondary-container');
612
+ }
613
+
614
+ &:hover {
615
+ @include m.state-layer(t.color('on-secondary-container'), 'hover');
616
+ // MD3 tonal buttons have elevation on hover
617
+ @include m.elevation(1);
618
+ }
619
+
620
+ &:active,
621
+ &.#{$component}--active {
622
+ @include m.state-layer(t.color('on-secondary-container'), 'pressed');
623
+ // MD3 reduces elevation on press
624
+ @include m.elevation(0);
625
+ }
626
+
627
+ &:disabled {
628
+ box-shadow: none;
629
+ }
630
+ }
631
+
632
+ // OUTLINED BUTTON
633
+ &--outlined {
634
+ border: 1px solid rgba(var(--mtrl-sys-color-outline-rgb), 0.38);
635
+ color: t.color('primary');
636
+
637
+ // Progress uses primary color
638
+ .#{base.$prefix}-progress-canvas {
639
+ color: t.color('primary');
640
+ }
641
+
642
+ &:hover {
643
+ @include m.state-layer(t.color('primary'), 'hover');
644
+ }
645
+
646
+ &:active,
647
+ &.#{$component}--active {
648
+ @include m.state-layer(t.color('primary'), 'pressed');
649
+ }
650
+
651
+ &:disabled {
652
+ border: 1px solid t.alpha('outline', 0.12);
653
+ }
654
+ }
655
+
656
+ // TEXT BUTTON
657
+ &--text {
658
+ min-width: v.button('min-width');
659
+ padding: 0 v.button('padding-horizontal-small');
660
+ color: t.color('primary');
661
+
662
+ // Progress uses primary color
663
+ .#{base.$prefix}-progress-canvas {
664
+ color: t.color('primary');
665
+ }
666
+
667
+ &:hover {
668
+ @include m.state-layer(t.color('primary'), 'hover');
669
+ }
670
+
671
+ &:active,
672
+ &.#{$component}--active {
673
+ @include m.state-layer(t.color('primary'), 'pressed');
674
+ }
675
+
676
+ &:disabled {
677
+ background-color: transparent;
678
+ }
679
+ }
680
+
681
+ // Special case for icon-only buttons
682
+ &--icon-only {
683
+ min-width: v.button('height');
684
+ width: v.button('height');
685
+ padding: 0;
686
+ border-radius: 50%;
687
+ }
688
+
689
+ // When button has progress showing
690
+ &--progress {
691
+ // Reduce left padding when progress is showing, similar to icon buttons
692
+ padding: 0 v.button('padding-horizontal') 0 calc(v.button('padding-horizontal') / 2 + 4px);
693
+
694
+ // Per MD3, round buttons have a significantly more rectangular appearance when progress (active) is showing
695
+ // Square buttons maintain their standard border radius
696
+ &.#{$component}--round {
697
+ &.#{$component}--xs,
698
+ &.#{$component}--s {
699
+ border-radius: f.get-shape('medium') !important;
700
+ }
701
+
702
+ &.#{$component}--m {
703
+ border-radius: f.get-shape('large') !important;
704
+ }
705
+
706
+ &.#{$component}--l,
707
+ &.#{$component}--xl {
708
+ border-radius: f.get-shape('extra-large') !important;
709
+ }
710
+ }
711
+
712
+ // If button also has an icon, use even less left padding
713
+ &.#{$component}--icon {
714
+ padding: 0 v.button('padding-horizontal') 0 calc(v.button('padding-horizontal') / 2);
715
+ }
716
+ }
717
+ }
718
+
719
+ // FIX: Disabled on dark theme (recommandations do not work as expected)
720
+ body[data-theme-mode=dark] {
721
+ // Interactive states
722
+ .#{$component} {
723
+ &:disabled {
724
+ color: t.alpha('on-surface-dim', 0.38);
725
+ background-color: t.alpha('surface-dim', 0.12);
726
+
727
+ .#{$component}-text {
728
+ opacity: 0.38;
729
+ }
730
+ .#{$component}-icon {
731
+ opacity: 0.38;
732
+ color: t.alpha('on-surface-dim', 0.12);
733
+ }
734
+ }
735
+ }
736
+ }
737
+
738
+ // Add loading state styles
739
+ .#{$component} {
740
+ // Loading state animations
741
+ &[disabled] {
742
+ &.#{$component}--progress {
743
+ .#{$component}-progress {
744
+ // Ensure progress is visible in disabled state
745
+ opacity: 0.7;
746
+ }
747
+ }
748
+ }
749
+
750
+ // Smooth transitions when showing/hiding progress
751
+ .#{$component}-progress {
752
+ &.#{base.$prefix}-progress {
753
+ transition: opacity v.motion('duration-short2') v.motion('easing-standard');
754
+ }
755
+ }
756
+ }