@inchurch/matcha-theme 20.0.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 (112) hide show
  1. package/README.md +303 -0
  2. package/abstracts/_colors.scss +405 -0
  3. package/abstracts/_elevation.scss +102 -0
  4. package/abstracts/_functions.scss +1213 -0
  5. package/abstracts/_media-breakpoint.scss +23 -0
  6. package/abstracts/_typography.scss +127 -0
  7. package/base/_reset.scss +438 -0
  8. package/components/matcha-accordion.scss +157 -0
  9. package/components/matcha-audio-player.scss +32 -0
  10. package/components/matcha-autocomplete.scss +134 -0
  11. package/components/matcha-avatar.scss +161 -0
  12. package/components/matcha-badge.scss +120 -0
  13. package/components/matcha-breadcrumb.scss +126 -0
  14. package/components/matcha-button-toggle.scss +363 -0
  15. package/components/matcha-buttons.scss +784 -0
  16. package/components/matcha-calendar.scss +154 -0
  17. package/components/matcha-cards.scss +205 -0
  18. package/components/matcha-chart-card.scss +60 -0
  19. package/components/matcha-checkbox.scss +554 -0
  20. package/components/matcha-chip.scss +212 -0
  21. package/components/matcha-color-pick.scss +35 -0
  22. package/components/matcha-command-palette.scss +89 -0
  23. package/components/matcha-crop.scss +172 -0
  24. package/components/matcha-date.scss +81 -0
  25. package/components/matcha-divider.scss +45 -0
  26. package/components/matcha-draggable.scss +24 -0
  27. package/components/matcha-drawer.scss +235 -0
  28. package/components/matcha-drop-list.scss +390 -0
  29. package/components/matcha-emoji.scss +69 -0
  30. package/components/matcha-empty-state.scss +118 -0
  31. package/components/matcha-flag.scss +62 -0
  32. package/components/matcha-footer.scss +187 -0
  33. package/components/matcha-form-field.scss +552 -0
  34. package/components/matcha-form-section.scss +101 -0
  35. package/components/matcha-header.scss +325 -0
  36. package/components/matcha-highlight.scss +296 -0
  37. package/components/matcha-hint-text.scss +66 -0
  38. package/components/matcha-horizontal-tree.scss +317 -0
  39. package/components/matcha-icon.scss +106 -0
  40. package/components/matcha-image.scss +62 -0
  41. package/components/matcha-list.scss +212 -0
  42. package/components/matcha-menu.scss +86 -0
  43. package/components/matcha-modal.scss +234 -0
  44. package/components/matcha-nav.scss +450 -0
  45. package/components/matcha-notification.scss +197 -0
  46. package/components/matcha-option.scss +95 -0
  47. package/components/matcha-page-builder.scss +4186 -0
  48. package/components/matcha-paginator.scss +235 -0
  49. package/components/matcha-panel.scss +167 -0
  50. package/components/matcha-profile-card.scss +50 -0
  51. package/components/matcha-progress-bar.scss +209 -0
  52. package/components/matcha-radio.scss +528 -0
  53. package/components/matcha-ripple.scss +7 -0
  54. package/components/matcha-scrollbar.scss +35 -0
  55. package/components/matcha-scrollbox-shadow.scss +123 -0
  56. package/components/matcha-section.scss +105 -0
  57. package/components/matcha-select.scss +661 -0
  58. package/components/matcha-skeleton.scss +138 -0
  59. package/components/matcha-slide-toggle.scss +590 -0
  60. package/components/matcha-slider.scss +188 -0
  61. package/components/matcha-snack-bar.scss +266 -0
  62. package/components/matcha-spin.scss +252 -0
  63. package/components/matcha-spinner.scss +78 -0
  64. package/components/matcha-stepper.scss +177 -0
  65. package/components/matcha-table-cell.scss +41 -0
  66. package/components/matcha-table.scss +785 -0
  67. package/components/matcha-tabs.scss +469 -0
  68. package/components/matcha-text-editor.scss +151 -0
  69. package/components/matcha-time.scss +33 -0
  70. package/components/matcha-timepicker.scss +13 -0
  71. package/components/matcha-toolbar.scss +206 -0
  72. package/components/matcha-tooltip.scss +128 -0
  73. package/components/matcha-uploader.scss +215 -0
  74. package/css/matcha-style.css +76772 -0
  75. package/fonts/CircularStd-Black.eot +0 -0
  76. package/fonts/CircularStd-Black.svg +3426 -0
  77. package/fonts/CircularStd-Black.ttf +0 -0
  78. package/fonts/CircularStd-Black.woff +0 -0
  79. package/fonts/CircularStd-Black.woff2 +0 -0
  80. package/fonts/CircularStd-Bold.eot +0 -0
  81. package/fonts/CircularStd-Bold.otf +0 -0
  82. package/fonts/CircularStd-Bold.svg +13532 -0
  83. package/fonts/CircularStd-Bold.ttf +0 -0
  84. package/fonts/CircularStd-Bold.woff +0 -0
  85. package/fonts/CircularStd-Bold.woff2 +0 -0
  86. package/fonts/CircularStd-Medium.eot +0 -0
  87. package/fonts/CircularStd-Medium.otf +0 -0
  88. package/fonts/CircularStd-Medium.svg +13511 -0
  89. package/fonts/CircularStd-Medium.ttf +0 -0
  90. package/fonts/CircularStd-Medium.woff +0 -0
  91. package/fonts/CircularStd-Medium.woff2 +0 -0
  92. package/fonts/CircularStd-Regular.eot +0 -0
  93. package/fonts/CircularStd-Regular.otf +0 -0
  94. package/fonts/CircularStd-Regular.svg +2378 -0
  95. package/fonts/CircularStd-Regular.ttf +0 -0
  96. package/fonts/CircularStd-Regular.woff +0 -0
  97. package/fonts/CircularStd-Regular.woff2 +0 -0
  98. package/main.scss +262 -0
  99. package/package.json +11 -0
  100. package/tokens/_animations-tokens.scss +37 -0
  101. package/tokens/_breakpoints-tokens.scss +26 -0
  102. package/tokens/_color-tokens.scss +1153 -0
  103. package/tokens/_css-custom-properties.scss +568 -0
  104. package/tokens/_elevation-tokens.scss +33 -0
  105. package/tokens/_spacing-tokens.scss +94 -0
  106. package/tokens/_typography-tokens.scss +65 -0
  107. package/vendors/angular-editor.scss +56 -0
  108. package/vendors/angular-material-fixes.scss +297 -0
  109. package/vendors/calendar.scss +2880 -0
  110. package/vendors/charts.scss +92 -0
  111. package/vendors/ng5-slider.scss +56 -0
  112. package/vendors/ngx-material-timepicker.scss +50 -0
@@ -0,0 +1,784 @@
1
+ // =============================================================================
2
+ // matcha-buttons.scss — Button & Icon Button (modernized)
3
+ // Aligned with Figma: matcha/button + matcha/icon-button
4
+ // Sizes: SM(32) MD(40) LG(48) XL(56) + legacy aliases (tiny/small/medium/large/huge)
5
+ // Variants: Filled(default) Outline Ghost(basic) Alpha Link
6
+ // State layer: ::before opacity pattern (consistent with all DS components)
7
+ // =============================================================================
8
+
9
+ // ── Disabled mixins ─────────────────────────────────────────────────────────
10
+
11
+ @mixin _disabled-solid-button($theme) {
12
+ background: var(--matcha-color-disabled-bg, #{getDisabled($theme)});
13
+ color: var(--matcha-color-disabled-fg, #{getDisabledBgContrast($theme)});
14
+ box-shadow: 0 0 0 0px inset;
15
+ pointer-events: none;
16
+ }
17
+
18
+ @mixin _disabled-basic-button($theme) {
19
+ background: var(--matcha-color-surface, #{getSurface($theme)});
20
+ color: var(--matcha-color-disabled-bg, #{getDisabled($theme)});
21
+ box-shadow: 0 0 0 0px inset;
22
+ pointer-events: none;
23
+ }
24
+
25
+ @mixin _disabled-outline-button($theme) {
26
+ background: transparent;
27
+ color: var(--matcha-color-disabled-bg, #{getDisabled($theme)});
28
+ box-shadow: 0 0 0 var(--matcha-border-thin, 2px) inset;
29
+ pointer-events: none;
30
+ }
31
+
32
+ @mixin _disabled-alpha-button($theme) {
33
+ background: var(--matcha-color-disabled-bg-alpha, #{getDisabledAlpha($theme)});
34
+ color: var(--matcha-color-disabled-bg, #{getDisabled($theme)});
35
+ box-shadow: 0 0 0 0px inset;
36
+ pointer-events: none;
37
+ }
38
+
39
+ @mixin _disabled-link-button($theme) {
40
+ background: transparent;
41
+ color: var(--matcha-color-disabled-bg, #{getDisabled($theme)});
42
+ box-shadow: 0 0 0 0px inset;
43
+ pointer-events: none;
44
+ }
45
+
46
+ // ── Size classes (responsive, aligned with Figma XS/SM/MD/LG/XL) ────────────
47
+
48
+ @mixin generate-matcha-button-size-classes($helper-breakpoints) {
49
+ @each $breakpoint, $materialBreakpoint in $helper-breakpoints {
50
+ @include media-breakpoint($materialBreakpoint) {
51
+ $infix: if($materialBreakpoint == null, "", "-#{$breakpoint}");
52
+
53
+ // XS — 28px. Figma matcha/button XS: pad 8 · gap 2 · text/caption (11/400/14, letter 0.3)
54
+ &[size#{$infix}="xs"] {
55
+ padding: 0 var(--matcha-space-100, 8px);
56
+ font-size: var(--matcha-text-caption, 11px);
57
+ font-weight: var(--matcha-weight-regular, 400);
58
+ line-height: var(--matcha-leading-caption, 14px);
59
+ letter-spacing: var(--matcha-letter-spacing-caption, 0.3px);
60
+ height: 28px;
61
+ gap: var(--matcha-space-025, 2px);
62
+ }
63
+
64
+ // SM — 32px. Figma: pad 8 · gap 4 · text/button-sm (13/500/19 letter 0.2)
65
+ &[size#{$infix}="sm"],
66
+ &[size#{$infix}="tiny"] {
67
+ padding: 0 var(--matcha-space-100, 8px);
68
+ font-size: var(--matcha-text-button-sm, 13px);
69
+ font-weight: var(--matcha-weight-medium, 500);
70
+ line-height: var(--matcha-leading-button-sm, 19px);
71
+ height: 32px;
72
+ gap: var(--matcha-space-050, 4px);
73
+ }
74
+
75
+ // MD — 40px. Figma: pad 16 · gap 8 · text/button-md (14/500/20)
76
+ &[size#{$infix}="md"],
77
+ &[size#{$infix}="small"] {
78
+ padding: 0 var(--matcha-space-200, 16px);
79
+ font-size: var(--matcha-text-md, 14px);
80
+ font-weight: var(--matcha-weight-medium, 500);
81
+ line-height: var(--matcha-leading-md, 20px);
82
+ height: 40px;
83
+ gap: var(--matcha-space-100, 8px);
84
+ }
85
+
86
+ // LG — 48px. Figma: pad 24 · gap 8
87
+ &[size#{$infix}="lg"],
88
+ &[size#{$infix}="medium"] {
89
+ padding: 0 var(--matcha-space-300, 24px);
90
+ font-size: var(--matcha-text-lg, 16px);
91
+ font-weight: var(--matcha-weight-semibold, 600);
92
+ line-height: var(--matcha-leading-button-lg, 22px);
93
+ height: 48px;
94
+ gap: var(--matcha-space-100, 8px);
95
+ }
96
+
97
+ // XL — 56px. Figma: pad 32 · gap 8
98
+ &[size#{$infix}="xl"],
99
+ &[size#{$infix}="large"],
100
+ &[size#{$infix}="huge"] {
101
+ padding: 0 var(--matcha-space-400, 32px);
102
+ font-size: var(--matcha-text-lg, 16px);
103
+ font-weight: var(--matcha-weight-semibold, 600);
104
+ line-height: var(--matcha-leading-button-lg, 22px);
105
+ height: 56px;
106
+ gap: var(--matcha-space-100, 8px);
107
+ }
108
+ }
109
+ }
110
+ }
111
+
112
+ // ── Structural ──────────────────────────────────────────────────────────────
113
+
114
+ button[matcha-button],
115
+ a[matcha-button],
116
+ button[matcha-icon-button],
117
+ a[matcha-icon-button],
118
+ button[matcha-link],
119
+ a[matcha-link] {
120
+ overflow: hidden;
121
+ position: relative;
122
+ font-size: var(--matcha-text-md, 14px);
123
+ font-weight: var(--matcha-weight-medium, 500);
124
+ font-family: inherit;
125
+ height: px-to-rem(40px); // default MD; overridden by size attribute selectors
126
+ appearance: auto;
127
+ text-rendering: auto;
128
+ letter-spacing: var(--matcha-letter-spacing-button, 0.2px);
129
+ word-spacing: normal;
130
+ line-height: normal;
131
+ text-transform: none;
132
+ text-indent: 0px;
133
+ text-shadow: none;
134
+ text-align: center;
135
+ text-wrap: nowrap;
136
+ display: flex;
137
+ justify-content: center;
138
+ align-items: center;
139
+ cursor: pointer;
140
+ box-sizing: border-box;
141
+ border: none;
142
+ border-radius: var(--matcha-radius-lg, 8px);
143
+
144
+ * { pointer-events: none; }
145
+
146
+ // Figma spec: ícones dentro de button herdam a foreground color do botão
147
+ // (matcha-icon tem color-default próprio via tema — forçamos inherit com !important
148
+ // pra vencer o tema que aplica em [class^="i-matcha-"] globalmente)
149
+ matcha-icon,
150
+ [class^="i-matcha-"],
151
+ [class*=" i-matcha-"] {
152
+ color: inherit !important;
153
+ }
154
+
155
+ @include generate-matcha-button-size-classes($helper-breakpoints);
156
+
157
+ // Figma matcha/button usa DOIS feedbacks combinados:
158
+ // 1. Cor do bg muda (accent-default → accent-hover → accent-pressed)
159
+ // 2. State-layer overlay por cima (matcha/color/state-layer/fg)
160
+ // - Filled: opacity 0.15 hover / 0.30 active
161
+ // - Outline/Ghost: opacity 0.10 hover / 0.20 active
162
+ // ::before aplica o state-layer; :hover/:active ou .is-state-* ativam.
163
+ transition:
164
+ background-color 150ms cubic-bezier(0.4, 0, 0.2, 1),
165
+ box-shadow 150ms cubic-bezier(0.4, 0, 0.2, 1),
166
+ color 150ms cubic-bezier(0.4, 0, 0.2, 1);
167
+
168
+ &::before {
169
+ content: '';
170
+ position: absolute;
171
+ inset: 0;
172
+ background: var(--matcha-color-state-layer-fg, currentColor);
173
+ opacity: 0;
174
+ border-radius: inherit;
175
+ pointer-events: none;
176
+ transition: opacity 150ms cubic-bezier(0.4, 0, 0.2, 1);
177
+ }
178
+
179
+ // Filled (variant default) — state-layer forte
180
+ &:hover:not([disabled]):not([disabled="true"]):not([outline]):not([basic]):not([ghost]):not([link]):not([alpha]):not([matcha-link])::before,
181
+ &.is-state-hover:not([outline]):not([basic]):not([ghost]):not([alpha])::before {
182
+ opacity: 0.15;
183
+ }
184
+ &:active:not([disabled]):not([disabled="true"]):not([outline]):not([basic]):not([ghost]):not([link]):not([alpha]):not([matcha-link])::before,
185
+ &.is-state-active:not([outline]):not([basic]):not([ghost]):not([alpha])::before {
186
+ opacity: 0.30;
187
+ }
188
+
189
+ // Outline / Ghost — state-layer sutil
190
+ &[outline]:hover:not([disabled]):not([disabled="true"])::before,
191
+ &[basic]:hover:not([disabled]):not([disabled="true"])::before,
192
+ &[ghost]:hover:not([disabled]):not([disabled="true"])::before,
193
+ &[outline].is-state-hover::before,
194
+ &[basic].is-state-hover::before,
195
+ &[ghost].is-state-hover::before {
196
+ opacity: 0.10;
197
+ }
198
+ &[outline]:active:not([disabled]):not([disabled="true"])::before,
199
+ &[basic]:active:not([disabled]):not([disabled="true"])::before,
200
+ &[ghost]:active:not([disabled]):not([disabled="true"])::before,
201
+ &[outline].is-state-active::before,
202
+ &[basic].is-state-active::before,
203
+ &[ghost].is-state-active::before {
204
+ opacity: 0.20;
205
+ }
206
+
207
+ &[disabled] {
208
+ pointer-events: none;
209
+ cursor: default;
210
+ }
211
+
212
+ // ── Variant modifiers (estrutural — cores vêm do mixin de tema) ──
213
+ &[basic]:not([basic="false"]),
214
+ &[ghost]:not([ghost="false"]) {
215
+ background: transparent;
216
+ }
217
+
218
+ &[outline]:not([outline="false"]) {
219
+ background: transparent;
220
+
221
+ &[link]:not([link="false"]) {
222
+ &[size="sm"], &[size="tiny"] { padding: 0 var(--matcha-space-100, 8px); gap: var(--matcha-space-050, 4px); }
223
+ &[size="md"], &[size="small"] { padding: 0 var(--matcha-space-150, 12px); gap: var(--matcha-space-100, 8px); }
224
+ &[size="lg"], &[size="medium"] { padding: 0 var(--matcha-space-200, 16px); gap: var(--matcha-space-150, 12px); }
225
+ &[size="xl"], &[size="large"], &[size="huge"] { padding: 0 var(--matcha-space-200, 16px); gap: var(--matcha-space-150, 12px); }
226
+ }
227
+ }
228
+
229
+ &[pill]:not([pill="false"]) {
230
+ border-radius: var(--matcha-radius-pill, 9999px);
231
+ }
232
+
233
+ &[link]:not([link="false"]) {
234
+ text-transform: initial;
235
+ letter-spacing: 0;
236
+ text-decoration: none;
237
+ padding: 0;
238
+ background: transparent;
239
+ }
240
+
241
+ // ── matcha-link specific (Figma spec 16914:500) ──
242
+ // SM=11/14 Regular letter 0.3 · MD=14/20 Medium · LG=16/22 SemiBold
243
+ // Hover/Active → underline automático. Underline=true → permanente.
244
+ // Disabled → opacity via disabled-fg color (no underline).
245
+ &[matcha-link] {
246
+ height: auto;
247
+ min-height: 0;
248
+ max-height: none;
249
+ padding: 0;
250
+ background: transparent;
251
+ border-radius: 0;
252
+ text-decoration: none; // reset do underline default do <a>; hover/class re-aplica
253
+
254
+ &[size="sm"], &[size="tiny"] {
255
+ font-size: var(--matcha-text-caption, 11px);
256
+ line-height: var(--matcha-leading-caption, 14px);
257
+ font-weight: var(--matcha-weight-regular, 400);
258
+ letter-spacing: var(--matcha-letter-spacing-caption, 0.3px);
259
+ height: auto;
260
+ max-height: none;
261
+ }
262
+ &[size="md"], &[size="small"] {
263
+ font-size: var(--matcha-text-md, 14px);
264
+ line-height: var(--matcha-leading-md, 20px);
265
+ font-weight: var(--matcha-weight-medium, 500);
266
+ letter-spacing: var(--matcha-letter-spacing-button, 0.2px);
267
+ height: auto;
268
+ max-height: none;
269
+ }
270
+ &[size="lg"], &[size="medium"] {
271
+ font-size: var(--matcha-text-lg, 16px);
272
+ line-height: var(--matcha-leading-button-lg, 22px);
273
+ font-weight: var(--matcha-weight-semibold, 600);
274
+ letter-spacing: var(--matcha-letter-spacing-button, 0.2px);
275
+ height: auto;
276
+ max-height: none;
277
+ }
278
+
279
+ // State layer fica off (link não tem overlay/bg)
280
+ &::before { display: none; }
281
+ // Press scale também off — link é texto
282
+ transition: none;
283
+ &:active:not([disabled]):not([disabled="true"]) { transform: none; }
284
+
285
+ // Hover e active: underline (Figma spec)
286
+ &:hover:not([disabled]):not([disabled="true"]),
287
+ &:active:not([disabled]):not([disabled="true"]) {
288
+ text-decoration: underline;
289
+ }
290
+
291
+ // Underline permanente via property (classe do HostBinding no component)
292
+ &.matcha-link--underline {
293
+ text-decoration: underline;
294
+ }
295
+ }
296
+
297
+ &[icon]:not([icon="false"]) {
298
+ aspect-ratio: 1;
299
+ display: flex;
300
+ align-items: center;
301
+ justify-content: center;
302
+
303
+ // Icon-button padding per Figma spec matcha/icon-button (all-direction):
304
+ // XS=6 · SM=6 · MD=8 · LG=12 · XL=16 (padding igual em todos os lados)
305
+ &[size="xs"] {
306
+ padding: var(--matcha-space-075, 6px) !important;
307
+ }
308
+ &[size="sm"], &[size="tiny"] {
309
+ padding: var(--matcha-space-075, 6px) !important;
310
+ }
311
+ &[size="md"], &[size="small"] {
312
+ padding: var(--matcha-space-100, 8px) !important;
313
+ }
314
+ &[size="lg"], &[size="medium"] {
315
+ padding: var(--matcha-space-150, 12px) !important;
316
+ }
317
+ &[size="xl"], &[size="large"], &[size="huge"] {
318
+ padding: var(--matcha-space-200, 16px) !important;
319
+ }
320
+
321
+ // Auto-size inner matcha-icon conforme Figma matcha/icon-button spec:
322
+ // XS→16 · SM→20 · MD→24 · LG→24 · XL→24
323
+ &[size="xs"] [class^="i-matcha-"],
324
+ &[size="xs"] [class*=" i-matcha-"] {
325
+ font-size: var(--matcha-icon-size-sm, 16px);
326
+ width: var(--matcha-icon-size-sm, 16px);
327
+ height: var(--matcha-icon-size-sm, 16px);
328
+ line-height: var(--matcha-icon-size-sm, 16px);
329
+ }
330
+ &[size="sm"] [class^="i-matcha-"],
331
+ &[size="sm"] [class*=" i-matcha-"],
332
+ &[size="tiny"] [class^="i-matcha-"],
333
+ &[size="tiny"] [class*=" i-matcha-"] {
334
+ font-size: 20px;
335
+ width: 20px;
336
+ height: 20px;
337
+ line-height: 20px;
338
+ }
339
+ &[size="md"] [class^="i-matcha-"],
340
+ &[size="md"] [class*=" i-matcha-"],
341
+ &[size="small"] [class^="i-matcha-"],
342
+ &[size="small"] [class*=" i-matcha-"],
343
+ &[size="lg"] [class^="i-matcha-"],
344
+ &[size="lg"] [class*=" i-matcha-"],
345
+ &[size="medium"] [class^="i-matcha-"],
346
+ &[size="medium"] [class*=" i-matcha-"],
347
+ &[size="xl"] [class^="i-matcha-"],
348
+ &[size="xl"] [class*=" i-matcha-"],
349
+ &[size="large"] [class^="i-matcha-"],
350
+ &[size="large"] [class*=" i-matcha-"],
351
+ &[size="huge"] [class^="i-matcha-"],
352
+ &[size="huge"] [class*=" i-matcha-"] {
353
+ font-size: var(--matcha-icon-size-md, 24px);
354
+ width: var(--matcha-icon-size-md, 24px);
355
+ height: var(--matcha-icon-size-md, 24px);
356
+ line-height: var(--matcha-icon-size-md, 24px);
357
+ }
358
+ }
359
+
360
+ // ── Badge ──
361
+ &[badge]:not([badge="false"]) {
362
+ overflow: visible;
363
+ position: relative;
364
+
365
+ &::after {
366
+ content: "";
367
+ position: absolute;
368
+ top: -0.25rem;
369
+ right: -0.25rem;
370
+ width: 1.32rem;
371
+ height: 1.32rem;
372
+ border-radius: var(--matcha-radius-pill, 9999px);
373
+ z-index: 2;
374
+ }
375
+
376
+ &[size="sm"]::after, &[size="tiny"]::after { width: 0.75rem; height: 0.75rem; top: -0.15rem; right: -0.15rem; }
377
+ &[size="md"]::after, &[size="small"]::after { width: 1rem; height: 1rem; top: -0.2rem; right: -0.2rem; }
378
+ &[size="xl"]::after, &[size="large"]::after, &[size="huge"]::after { width: 1.5rem; height: 1.5rem; top: -0.3rem; right: -0.3rem; }
379
+ }
380
+
381
+ // ── Focus ring ──
382
+ &:focus-visible:not([disabled]) {
383
+ outline: var(--matcha-state-focus-ring-width, 2px) solid var(--matcha-color-accent, #6200ee);
384
+ outline-offset: var(--matcha-state-focus-ring-offset, 2px);
385
+ }
386
+
387
+ @media (prefers-reduced-motion: reduce) {
388
+ &::before { transition: none; }
389
+ &, &:active:not([disabled]):not([disabled="true"]) { transition: none; transform: none; }
390
+ }
391
+
392
+ // ── Loading state ──
393
+ // Spinner inline do lado direito do conteúdo + content dims pra 60%
394
+ // Preserva width (não shift) e bloqueia cliques com pointer-events.
395
+ &.matcha-button--loading {
396
+ pointer-events: none;
397
+ cursor: progress;
398
+
399
+ // Dim no content interior (tudo exceto o spinner)
400
+ > :not(.matcha-button__spinner) {
401
+ opacity: 0.6;
402
+ }
403
+ }
404
+
405
+ .matcha-button__spinner {
406
+ display: inline-flex;
407
+ align-items: center;
408
+ justify-content: center;
409
+ margin-left: var(--matcha-space-100, 8px);
410
+ flex: none;
411
+ line-height: 0;
412
+
413
+ svg {
414
+ display: block;
415
+ }
416
+
417
+ @media (prefers-reduced-motion: reduce) {
418
+ svg circle animateTransform {
419
+ // Retarda mas não remove (ainda sinaliza loading)
420
+ dur: 2s !important;
421
+ }
422
+ }
423
+ }
424
+
425
+ // Visually hidden span pra screen readers (loading announcement)
426
+ .matcha-button__sr-only {
427
+ position: absolute !important;
428
+ width: 1px !important;
429
+ height: 1px !important;
430
+ padding: 0 !important;
431
+ margin: -1px !important;
432
+ overflow: hidden !important;
433
+ clip: rect(0, 0, 0, 0) !important;
434
+ white-space: nowrap !important;
435
+ border: 0 !important;
436
+ }
437
+
438
+ // ── Touch targets (WCAG 2.5.5: 44x44 mínimo em coarse pointers) ──
439
+ // XS (28), SM (32), MD (40) ficam abaixo de 44px — expande hit area invisível.
440
+ @media (pointer: coarse) {
441
+ &[size="xs"],
442
+ &[size="sm"], &[size="tiny"],
443
+ &[size="md"], &[size="small"] {
444
+ position: relative;
445
+
446
+ &::after {
447
+ content: '';
448
+ position: absolute;
449
+ inset: -8px; // expande ~16px em cada eixo → 28+16=44, 32+16=48, 40+16=56 ✓
450
+ z-index: 0;
451
+ pointer-events: auto; // captura cliques aqui
452
+ }
453
+
454
+ // ::before já é usado pro state layer, então nosso overlay vai no ::after
455
+ // State layer (::before) fica colado ao botão visual, overlay (::after) expande hit.
456
+ }
457
+ }
458
+ }
459
+
460
+ // ── Theme mixin ─────────────────────────────────────────────────────────────
461
+
462
+ @mixin matcha-button-theme($theme) {
463
+ // ═════════════════════════════════════════════════════════════════════════
464
+ // CSS var-based theming (regra DS-ARCHITECTURE #7: Tokens over hardcode)
465
+ //
466
+ // Todo botão usa --matcha-button-color como token interno.
467
+ // `[color="X"]` apenas mapeia pra esses tokens — as variantes
468
+ // (filled/outline/ghost/alpha/link) interpretam um único set de vars.
469
+ //
470
+ // Consumidor pode override QUALQUER cor via style:
471
+ // <button matcha-button style="--matcha-button-color: #ff00ff">Custom</button>
472
+ //
473
+ // Adicionar cor nova = adicionar 1 mapping (3 linhas).
474
+ // ═════════════════════════════════════════════════════════════════════════
475
+
476
+ button[matcha-button],
477
+ a[matcha-button],
478
+ button[matcha-icon-button],
479
+ a[matcha-icon-button],
480
+ button[matcha-link],
481
+ a[matcha-link] {
482
+ // Tokens internos (Figma matcha/button 13913:1088):
483
+ // --matcha-button-color = bg do filled (Default)
484
+ // --matcha-button-color-hover = bg filled / stroke outline (Hover)
485
+ // --matcha-button-color-pressed = bg filled / stroke+text (Active)
486
+ // --matcha-button-color-text-on = texto do filled (accent/text-on etc.)
487
+ // --matcha-button-color-alpha = alpha modifier / ripple
488
+ // --matcha-button-color-edge = stroke do outline (Default)
489
+ --matcha-button-color: var(--matcha-color-neutral);
490
+ --matcha-button-color-hover: var(--matcha-color-neutral-hover);
491
+ --matcha-button-color-pressed: var(--matcha-color-neutral-hover);
492
+ --matcha-button-color-text-on: var(--matcha-color-neutral-contrast);
493
+ --matcha-button-color-alpha: var(--matcha-color-neutral-alpha);
494
+ --matcha-button-color-edge: var(--matcha-color-fg, #{getForeground($theme)});
495
+
496
+ // ── Color mapping ────────────────────────────────────────────────────────────────
497
+ &[color="basic"] {
498
+ --matcha-button-color: var(--matcha-color-neutral);
499
+ --matcha-button-color-hover: var(--matcha-color-neutral-hover);
500
+ --matcha-button-color-pressed: var(--matcha-color-neutral-hover);
501
+ --matcha-button-color-text-on: var(--matcha-color-neutral-contrast);
502
+ --matcha-button-color-alpha: var(--matcha-color-neutral-alpha);
503
+ --matcha-button-color-edge: var(--matcha-color-fg, #{getForeground($theme)});
504
+ }
505
+ &[color="primary"] {
506
+ --matcha-button-color: var(--matcha-color-primary, #{getPrimary($theme)});
507
+ --matcha-button-color-hover: var(--matcha-color-primary-hover);
508
+ --matcha-button-color-pressed: var(--matcha-color-primary-pressed);
509
+ --matcha-button-color-text-on: var(--matcha-color-primary-contrast, #{getPrimaryContrast($theme)});
510
+ --matcha-button-color-alpha: var(--matcha-color-primary-alpha, #{getPrimaryAlpha($theme)});
511
+ --matcha-button-color-edge: var(--matcha-color-primary, #{getPrimary($theme)});
512
+ }
513
+ &[color="accent"] {
514
+ --matcha-button-color: var(--matcha-color-accent, #{getAccent($theme)});
515
+ --matcha-button-color-hover: var(--matcha-color-accent-hover);
516
+ --matcha-button-color-pressed: var(--matcha-color-accent-pressed);
517
+ --matcha-button-color-text-on: var(--matcha-color-accent-text-on);
518
+ --matcha-button-color-alpha: var(--matcha-color-accent-alpha, #{getAccentAlpha($theme)});
519
+ --matcha-button-color-edge: var(--matcha-color-accent, #{getAccent($theme)});
520
+ }
521
+ &[color="success"] {
522
+ --matcha-button-color: var(--matcha-color-success, #{getSuccess($theme)});
523
+ --matcha-button-color-hover: var(--matcha-color-success-hover);
524
+ --matcha-button-color-pressed: var(--matcha-color-success-pressed);
525
+ --matcha-button-color-text-on: var(--matcha-color-success-contrast, #{getSuccessContrast($theme)});
526
+ --matcha-button-color-alpha: var(--matcha-color-success-alpha, #{getSuccessAlpha($theme)});
527
+ --matcha-button-color-edge: var(--matcha-color-success, #{getSuccess($theme)});
528
+ }
529
+ &[color="warn"] {
530
+ --matcha-button-color: var(--matcha-color-warn, #{getWarn($theme)});
531
+ --matcha-button-color-hover: var(--matcha-color-warn-hover);
532
+ --matcha-button-color-pressed: var(--matcha-color-warn-pressed);
533
+ --matcha-button-color-text-on: var(--matcha-color-warn-contrast, #{getWarnContrast($theme)});
534
+ --matcha-button-color-alpha: var(--matcha-color-warn-alpha, #{getWarnAlpha($theme)});
535
+ --matcha-button-color-edge: var(--matcha-color-warn, #{getWarn($theme)});
536
+ }
537
+ &[color="danger"] {
538
+ --matcha-button-color: var(--matcha-color-danger, #{getDanger($theme)});
539
+ --matcha-button-color-hover: var(--matcha-color-danger-hover);
540
+ --matcha-button-color-pressed: var(--matcha-color-danger-pressed);
541
+ --matcha-button-color-text-on: var(--matcha-color-danger-contrast, #{getDangerContrast($theme)});
542
+ --matcha-button-color-alpha: var(--matcha-color-danger-alpha, #{getDangerAlpha($theme)});
543
+ --matcha-button-color-edge: var(--matcha-color-danger, #{getDanger($theme)});
544
+ }
545
+ &[color="info"] {
546
+ --matcha-button-color: var(--matcha-color-info, #{getInfo($theme)});
547
+ --matcha-button-color-hover: var(--matcha-color-info-hover);
548
+ --matcha-button-color-pressed: var(--matcha-color-info-pressed);
549
+ --matcha-button-color-text-on: var(--matcha-color-info-contrast, #{getInfoContrast($theme)});
550
+ --matcha-button-color-alpha: var(--matcha-color-info-alpha, #{getInfoAlpha($theme)});
551
+ --matcha-button-color-edge: var(--matcha-color-info, #{getInfo($theme)});
552
+ }
553
+
554
+ // ── Filled (default variant) ──────────────────────────────────────────────────────
555
+ // Figma: Default=accent · Hover=accent-hover · Active=accent-pressed
556
+ background: var(--matcha-button-color);
557
+ color: var(--matcha-button-color-text-on);
558
+
559
+ &:hover:not([disabled]):not([disabled="true"]):not([outline]):not([basic]):not([ghost]):not([link]):not([alpha]):not([matcha-link]) {
560
+ background: var(--matcha-button-color-hover);
561
+ }
562
+ &:active:not([disabled]):not([disabled="true"]):not([outline]):not([basic]):not([ghost]):not([link]):not([alpha]):not([matcha-link]) {
563
+ background: var(--matcha-button-color-pressed);
564
+ }
565
+
566
+ // ── Variant: outline ────────────────────────────────────────────────────────────────
567
+ // Figma matcha/button (13913:1088) vs matcha/icon-button (13914:482):
568
+ // BUTTON outline: texto=text-primary · ícones=edge (accent)
569
+ // ICON-BUTTON outline: host color=edge (ícone herda via inherit !important)
570
+ // Hover: icons/host = accent-hover (texto button mantém primary)
571
+ // Active: tudo = accent-pressed
572
+ &[outline]:not([outline="false"]),
573
+ &[variant="outline"] {
574
+ background: transparent;
575
+ box-shadow: inset 0 0 0 var(--matcha-border-thin, 2px) var(--matcha-button-color-edge);
576
+ color: var(--matcha-color-text-primary);
577
+
578
+ &:hover:not([disabled]):not([disabled="true"]) {
579
+ box-shadow: inset 0 0 0 var(--matcha-border-thin, 2px) var(--matcha-button-color-hover);
580
+ }
581
+ &:active:not([disabled]):not([disabled="true"]) {
582
+ box-shadow: inset 0 0 0 var(--matcha-border-thin, 2px) var(--matcha-button-color-pressed);
583
+ color: var(--matcha-button-color-pressed);
584
+ }
585
+ }
586
+
587
+ // Icon-button outline: host color = edge (ícone é o único conteúdo semântico)
588
+ &[matcha-icon-button][outline]:not([outline="false"]),
589
+ &[matcha-icon-button][variant="outline"] {
590
+ color: var(--matcha-button-color-edge);
591
+
592
+ &:hover:not([disabled]):not([disabled="true"]) {
593
+ color: var(--matcha-button-color-hover);
594
+ }
595
+ &:active:not([disabled]):not([disabled="true"]) {
596
+ color: var(--matcha-button-color-pressed);
597
+ }
598
+ }
599
+
600
+ // Button outline: ícones (Left/Right) acompanham edge — texto mantém primary
601
+ &[matcha-button][outline]:not([outline="false"]) matcha-icon,
602
+ &[matcha-button][outline]:not([outline="false"]) [class^="i-matcha-"],
603
+ &[matcha-button][outline]:not([outline="false"]) [class*=" i-matcha-"],
604
+ &[matcha-button][variant="outline"] matcha-icon,
605
+ &[matcha-button][variant="outline"] [class^="i-matcha-"],
606
+ &[matcha-button][variant="outline"] [class*=" i-matcha-"] {
607
+ color: var(--matcha-button-color-edge) !important;
608
+ }
609
+ &[matcha-button][outline]:hover:not([disabled]):not([disabled="true"]) matcha-icon,
610
+ &[matcha-button][outline]:hover:not([disabled]):not([disabled="true"]) [class^="i-matcha-"],
611
+ &[matcha-button][outline].is-state-hover matcha-icon {
612
+ color: var(--matcha-button-color-hover) !important;
613
+ }
614
+ &[matcha-button][outline]:active:not([disabled]):not([disabled="true"]) matcha-icon,
615
+ &[matcha-button][outline]:active:not([disabled]):not([disabled="true"]) [class^="i-matcha-"],
616
+ &[matcha-button][outline].is-state-active matcha-icon {
617
+ color: var(--matcha-button-color-pressed) !important;
618
+ }
619
+
620
+ // ── Variant: ghost (basic = legacy alias) ────────────────────────────────────────
621
+ // Figma: Default/Hover=text-primary · Active=accent-pressed (texto + ícones)
622
+ // Ícones do button ghost acompanham edge quando a cor é semântica
623
+ &[basic]:not([basic="false"]),
624
+ &[ghost]:not([ghost="false"]),
625
+ &[variant="ghost"] {
626
+ background: transparent;
627
+ color: var(--matcha-color-text-primary);
628
+
629
+ &:active:not([disabled]):not([disabled="true"]) {
630
+ color: var(--matcha-button-color-pressed);
631
+ }
632
+ }
633
+
634
+ // Button ghost: ícones acompanham edge (accent) — texto mantém primary
635
+ &[matcha-button][basic]:not([basic="false"]) matcha-icon,
636
+ &[matcha-button][basic]:not([basic="false"]) [class^="i-matcha-"],
637
+ &[matcha-button][ghost]:not([ghost="false"]) matcha-icon,
638
+ &[matcha-button][ghost]:not([ghost="false"]) [class^="i-matcha-"],
639
+ &[matcha-button][variant="ghost"] matcha-icon,
640
+ &[matcha-button][variant="ghost"] [class^="i-matcha-"] {
641
+ color: var(--matcha-button-color-edge) !important;
642
+ }
643
+ &[matcha-button][ghost]:hover:not([disabled]):not([disabled="true"]) matcha-icon,
644
+ &[matcha-button][basic]:hover:not([disabled]):not([disabled="true"]) matcha-icon,
645
+ &[matcha-button][ghost].is-state-hover matcha-icon,
646
+ &[matcha-button][basic].is-state-hover matcha-icon {
647
+ color: var(--matcha-button-color-hover) !important;
648
+ }
649
+ &[matcha-button][ghost]:active:not([disabled]):not([disabled="true"]) matcha-icon,
650
+ &[matcha-button][basic]:active:not([disabled]):not([disabled="true"]) matcha-icon,
651
+ &[matcha-button][ghost].is-state-active matcha-icon,
652
+ &[matcha-button][basic].is-state-active matcha-icon {
653
+ color: var(--matcha-button-color-pressed) !important;
654
+ }
655
+
656
+ // ── Modifier: alpha ──────────────────────────────────────────────
657
+ &[alpha]:not([alpha="false"]) {
658
+ background: var(--matcha-button-color-alpha);
659
+ color: var(--matcha-button-color);
660
+ }
661
+
662
+ // ── Modifier: link (legacy, afeta button[link="true"]) ───────────
663
+ // matcha-link tem seu próprio bloco (&[matcha-link]) com regras
664
+ // próprias de underline (hover + .matcha-link--underline)
665
+ &[link]:not([link="false"]):not([matcha-link]) {
666
+ background: transparent;
667
+ color: var(--matcha-button-color);
668
+ text-decoration: underline;
669
+ }
670
+ // matcha-link: apenas cor do texto (o bloco estrutural [matcha-link]
671
+ // define text-decoration: none + hover/active + class underline)
672
+ &[matcha-link] {
673
+ color: var(--matcha-button-color);
674
+ }
675
+
676
+ // ── State: disabled ──────────────────────────────────────────────
677
+ // Figma (13913:1088) Disabled state:
678
+ // Filled: bg=interaction/disabled-bg · label+icons=accent/text-on (mesma cor do filled default)
679
+ // Outline: stroke=interaction/disabled-bg (NÃO disabled-border) · label+icons=disabled-fg
680
+ // Ghost: sem bg/stroke · label+icons=disabled-fg
681
+ // State-layer overlay DESLIGADO em todos disabled.
682
+ &[disabled]:not([disabled="false"]),
683
+ &[disabled="true"] {
684
+ pointer-events: none;
685
+ cursor: not-allowed;
686
+
687
+ // state-layer overlay desligado
688
+ &::before { opacity: 0 !important; }
689
+
690
+ // Filled — bg disabled + texto/ícones accent-text-on (Figma spec)
691
+ background: var(--matcha-color-interaction-disabled-bg);
692
+ color: var(--matcha-color-accent-text-on);
693
+ box-shadow: none;
694
+
695
+ // Outline — stroke usa mesma cor do filled-bg (Figma usa interaction/disabled-bg)
696
+ &[outline]:not([outline="false"]),
697
+ &[variant="outline"] {
698
+ background: transparent;
699
+ color: var(--matcha-color-interaction-disabled-fg);
700
+ box-shadow: inset 0 0 0 var(--matcha-border-thin, 2px) var(--matcha-color-interaction-disabled-bg);
701
+ }
702
+
703
+ // Ghost / basic / link — só texto dedicado
704
+ &[basic]:not([basic="false"]),
705
+ &[ghost]:not([ghost="false"]),
706
+ &[variant="ghost"],
707
+ &[link]:not([link="false"]) {
708
+ background: transparent;
709
+ color: var(--matcha-color-interaction-disabled-fg);
710
+ box-shadow: none;
711
+ }
712
+
713
+ // Alpha — bg alpha dedicado
714
+ &[alpha]:not([alpha="false"]) {
715
+ background: var(--matcha-color-interaction-disabled-bg-alpha);
716
+ color: var(--matcha-color-interaction-disabled-fg);
717
+ }
718
+
719
+ // Ícones do button (Left/Right) no disabled:
720
+ // Filled: herdam color do host (accent-text-on) ✓
721
+ // Outline/Ghost: forçam disabled-fg pra sobrescrever regra !important do edge
722
+ &[matcha-button][outline] matcha-icon,
723
+ &[matcha-button][outline] [class^="i-matcha-"],
724
+ &[matcha-button][outline] [class*=" i-matcha-"],
725
+ &[matcha-button][basic] matcha-icon,
726
+ &[matcha-button][basic] [class^="i-matcha-"],
727
+ &[matcha-button][ghost] matcha-icon,
728
+ &[matcha-button][ghost] [class^="i-matcha-"],
729
+ &[matcha-button][variant="outline"] matcha-icon,
730
+ &[matcha-button][variant="outline"] [class^="i-matcha-"],
731
+ &[matcha-button][variant="ghost"] matcha-icon,
732
+ &[matcha-button][variant="ghost"] [class^="i-matcha-"] {
733
+ color: var(--matcha-color-interaction-disabled-fg) !important;
734
+ }
735
+ }
736
+
737
+ // ── Badge indicator (always accent, pattern fixo) ────────────────
738
+ &[badge]:not([badge="false"])::after {
739
+ background: var(--matcha-color-accent, #{getAccent($theme)});
740
+ }
741
+
742
+ // ── Ripple overlay ───────────────────────────────────────────────
743
+ .ripple {
744
+ background: var(--matcha-button-color-alpha);
745
+ }
746
+ }
747
+ }
748
+
749
+ // ── matcha-icon-button: auto-size inner icons per Figma spec ────────────────
750
+ // XS button (28) → icon 16 · SM (32) → 20 · MD (40)/LG (48)/XL (56) → 24
751
+ button[matcha-icon-button],
752
+ a[matcha-icon-button] {
753
+ aspect-ratio: 1;
754
+
755
+ matcha-icon {
756
+ flex: none; // NÃO expandir com o button
757
+ }
758
+
759
+ &[size="xs"] matcha-icon,
760
+ &[size="tiny"] matcha-icon {
761
+ font-size: 16px !important;
762
+ width: 16px !important;
763
+ height: 16px !important;
764
+ line-height: 16px !important;
765
+ }
766
+ &[size="sm"] matcha-icon,
767
+ &[size="small"] matcha-icon {
768
+ font-size: 20px !important;
769
+ width: 20px !important;
770
+ height: 20px !important;
771
+ line-height: 20px !important;
772
+ }
773
+ &[size="md"] matcha-icon,
774
+ &[size="medium"] matcha-icon,
775
+ &[size="lg"] matcha-icon,
776
+ &[size="large"] matcha-icon,
777
+ &[size="xl"] matcha-icon,
778
+ &[size="huge"] matcha-icon {
779
+ font-size: 24px !important;
780
+ width: 24px !important;
781
+ height: 24px !important;
782
+ line-height: 24px !important;
783
+ }
784
+ }