@inchurch/matcha-theme 22.39.0 → 22.40.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/abstracts/_colors.scss +291 -291
- package/abstracts/_elevation.scss +108 -108
- package/abstracts/_functions.scss +321 -321
- package/abstracts/_media-breakpoint.scss +26 -26
- package/abstracts/_theme-api.scss +224 -224
- package/abstracts/_typography.scss +128 -128
- package/base/_reset.scss +487 -487
- package/components/app-page-header.scss +260 -260
- package/components/matcha-accordion.scss +297 -297
- package/components/matcha-audio-player.scss +31 -31
- package/components/matcha-autocomplete.scss +145 -145
- package/components/matcha-avatar.scss +426 -426
- package/components/matcha-badge.scss +120 -120
- package/components/matcha-breadcrumb.scss +231 -231
- package/components/matcha-button-toggle.scss +484 -484
- package/components/matcha-buttons.scss +973 -973
- package/components/matcha-calendar.scss +253 -253
- package/components/matcha-cards.scss +212 -212
- package/components/matcha-chart-card.scss +53 -53
- package/components/matcha-checkbox.scss +266 -266
- package/components/matcha-chip.scss +311 -311
- package/components/matcha-color-pick.scss +34 -34
- package/components/matcha-command-palette.scss +316 -316
- package/components/matcha-crop.scss +419 -419
- package/components/matcha-date.scss +81 -81
- package/components/matcha-divider.scss +100 -100
- package/components/matcha-draggable.scss +23 -23
- package/components/matcha-drawer.scss +376 -376
- package/components/matcha-drop-image.scss +14 -14
- package/components/matcha-drop-list.scss +430 -430
- package/components/matcha-emoji.scss +69 -69
- package/components/matcha-empty-state.scss +230 -230
- package/components/matcha-file-uploader.scss +650 -650
- package/components/matcha-flag.scss +103 -103
- package/components/matcha-footer.scss +91 -91
- package/components/matcha-form-field.scss +883 -883
- package/components/matcha-form-section.scss +100 -100
- package/components/matcha-header.scss +135 -135
- package/components/matcha-highlight.scss +164 -164
- package/components/matcha-hint-text.scss +90 -90
- package/components/matcha-horizontal-tree.scss +247 -247
- package/components/matcha-icon.scss +111 -111
- package/components/matcha-image.scss +60 -60
- package/components/matcha-list.scss +211 -211
- package/components/matcha-menu.scss +99 -99
- package/components/matcha-modal.scss +210 -210
- package/components/matcha-nav.scss +770 -770
- package/components/matcha-notification.scss +417 -417
- package/components/matcha-option.scss +170 -170
- package/components/matcha-page-builder.scss +4196 -4196
- package/components/matcha-paginator.scss +699 -699
- package/components/matcha-panel.scss +216 -216
- package/components/matcha-period.scss +174 -174
- package/components/matcha-profile-card.scss +50 -50
- package/components/matcha-progress-bar.scss +355 -355
- package/components/matcha-radio.scss +325 -325
- package/components/matcha-ripple.scss +7 -7
- package/components/matcha-scrollbar.scss +33 -33
- package/components/matcha-scrollbox-shadow.scss +120 -120
- package/components/matcha-section.scss +102 -102
- package/components/matcha-select-multiple.scss +56 -56
- package/components/matcha-select.scss +643 -629
- package/components/matcha-skeleton.scss +182 -182
- package/components/matcha-slide-toggle.scss +369 -369
- package/components/matcha-slider.scss +285 -285
- package/components/matcha-snack-bar.scss +259 -259
- package/components/matcha-spin.scss +164 -164
- package/components/matcha-spinner.scss +97 -97
- package/components/matcha-stepper.scss +376 -376
- package/components/matcha-table-cell.scss +107 -107
- package/components/matcha-table.scss +722 -722
- package/components/matcha-tabs.scss +642 -642
- package/components/matcha-text-editor.scss +111 -111
- package/components/matcha-time.scss +33 -33
- package/components/matcha-timepicker.scss +13 -13
- package/components/matcha-toolbar.scss +366 -366
- package/components/matcha-tooltip.scss +235 -235
- package/components/matcha-tree-view.scss +658 -658
- package/layout/matcha-page-layout.scss +778 -778
- package/main.scss +334 -334
- package/package.json +1 -1
- package/tokens/_animations-tokens.scss +37 -37
- package/tokens/_breakpoints-tokens.scss +35 -35
- package/tokens/_color-tokens.scss +288 -288
- package/tokens/_elevation-tokens.scss +33 -33
- package/tokens/_emit-tokens.scss +329 -329
- package/tokens/_material-palette.scss +1149 -1149
- package/tokens/_primitives.scss +98 -98
- package/tokens/_semantic-aliases.scss +120 -120
- package/tokens/_spacing-tokens.scss +94 -94
- package/tokens/_static-tokens.scss +137 -137
- package/tokens/_typography-tokens.scss +65 -65
- package/vendors/charts.scss +90 -90
|
@@ -1,973 +1,973 @@
|
|
|
1
|
-
@use "../abstracts/media-breakpoint" as *;
|
|
2
|
-
@use "../abstracts/functions" as *;
|
|
3
|
-
@use "../tokens/breakpoints-tokens" as *;
|
|
4
|
-
// =============================================================================
|
|
5
|
-
// matcha-buttons.scss — Button & Icon Button (modernized)
|
|
6
|
-
// Aligned with Figma: matcha/button + matcha/icon-button
|
|
7
|
-
// Sizes: SM(32) MD(40) LG(48) XL(56) + legacy aliases (tiny/small/medium/large/huge)
|
|
8
|
-
// Variants: Filled(default) Outline Ghost(basic) Alpha Link
|
|
9
|
-
// State layer: ::before opacity pattern (consistent with all DS components)
|
|
10
|
-
// =============================================================================
|
|
11
|
-
|
|
12
|
-
// ── Disabled mixins ─────────────────────────────────────────────────────────
|
|
13
|
-
|
|
14
|
-
@mixin disabled-solid-button($theme) {
|
|
15
|
-
background: var(--matcha-color-disabled-bg);
|
|
16
|
-
color: var(--matcha-color-disabled-fg);
|
|
17
|
-
box-shadow: 0 0 0 0px inset;
|
|
18
|
-
pointer-events: none;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
@mixin disabled-basic-button($theme) {
|
|
22
|
-
background: var(--matcha-color-surface);
|
|
23
|
-
color: var(--matcha-color-disabled-bg);
|
|
24
|
-
box-shadow: 0 0 0 0px inset;
|
|
25
|
-
pointer-events: none;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
@mixin disabled-outline-button($theme) {
|
|
29
|
-
background: transparent;
|
|
30
|
-
color: var(--matcha-color-disabled-bg);
|
|
31
|
-
box-shadow: 0 0 0 var(--matcha-border-thin, 2px) inset;
|
|
32
|
-
pointer-events: none;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
@mixin disabled-alpha-button($theme) {
|
|
36
|
-
background: var(--matcha-color-disabled-bg-alpha, var(--matcha-color-interaction-disabled-bg-alpha));
|
|
37
|
-
color: var(--matcha-color-disabled-bg);
|
|
38
|
-
box-shadow: 0 0 0 0px inset;
|
|
39
|
-
pointer-events: none;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
@mixin disabled-link-button($theme) {
|
|
43
|
-
background: transparent;
|
|
44
|
-
color: var(--matcha-color-disabled-bg);
|
|
45
|
-
box-shadow: 0 0 0 0px inset;
|
|
46
|
-
pointer-events: none;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
// ── Size classes (responsive, aligned with Figma XS/SM/MD/LG/XL) ────────────
|
|
50
|
-
//
|
|
51
|
-
// Cada size define `min-width` igual à sua `height`: o botão nunca fica mais
|
|
52
|
-
// estreito que alto. Sem esse piso a largura é só `padding + conteúdo`, e um
|
|
53
|
-
// label curto ("OK", "X") vira um retângulo VERTICAL — no XS, 23×28. Com o
|
|
54
|
-
// piso o pior caso é um quadrado, com o conteúdo centrado pelo
|
|
55
|
-
// `justify-content: center` do bloco estrutural. Label longo nunca atinge o
|
|
56
|
-
// piso, então nada muda onde já estava certo.
|
|
57
|
-
//
|
|
58
|
-
// Efeito colateral desejado em flex container: o botão tem `overflow: hidden`,
|
|
59
|
-
// o que já anula o `min-width: auto` (a automatic minimum size do flexbox só
|
|
60
|
-
// vale para item com `overflow: visible`) — ou seja, hoje ele encolhe até ~0 e
|
|
61
|
-
// corta o label. O piso troca esse colapso por um mínimo quadrado.
|
|
62
|
-
|
|
63
|
-
@mixin generate-matcha-button-size-classes($helper-breakpoints) {
|
|
64
|
-
@each $breakpoint, $materialBreakpoint in $helper-breakpoints {
|
|
65
|
-
@include media-breakpoint($materialBreakpoint) {
|
|
66
|
-
$infix: if($materialBreakpoint == null, "", "-#{$breakpoint}");
|
|
67
|
-
|
|
68
|
-
// XS/Tiny — 28px. Figma matcha/button XS: pad 8 · gap 2 · text/caption (11/400/14, letter 0.3)
|
|
69
|
-
&[size#{$infix}="xs"],
|
|
70
|
-
&[size#{$infix}="tiny"] {
|
|
71
|
-
padding: 0 var(--matcha-space-100, 8px);
|
|
72
|
-
font-size: var(--matcha-text-p-tiny, 11px);
|
|
73
|
-
font-weight: var(--matcha-weight-regular, 400);
|
|
74
|
-
line-height: var(--matcha-leading-p-tiny, 14px);
|
|
75
|
-
letter-spacing: var(--matcha-letter-spacing-caption, 0.3px);
|
|
76
|
-
height: 28px;
|
|
77
|
-
min-width: 28px;
|
|
78
|
-
gap: var(--matcha-space-025, 2px);
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
// SM/Small — 32px. Figma: pad 8 · gap 4 · text/button-sm (13/500/19 letter 0.2)
|
|
82
|
-
&[size#{$infix}="sm"],
|
|
83
|
-
&[size#{$infix}="small"] {
|
|
84
|
-
padding: 0 var(--matcha-space-100, 8px);
|
|
85
|
-
font-size: var(--matcha-text-label-sm, 13px);
|
|
86
|
-
font-weight: var(--matcha-weight-medium, 500);
|
|
87
|
-
line-height: var(--matcha-leading-label-sm, 19px);
|
|
88
|
-
height: 32px;
|
|
89
|
-
min-width: 32px;
|
|
90
|
-
gap: var(--matcha-space-050, 4px);
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
// MD/Medium — 40px. Figma: pad 16 · gap 8 · text/button-md (14/500/20)
|
|
94
|
-
&[size#{$infix}="md"],
|
|
95
|
-
&[size#{$infix}="medium"] {
|
|
96
|
-
padding: 0 var(--matcha-space-200, 16px);
|
|
97
|
-
font-size: var(--matcha-text-md, 14px);
|
|
98
|
-
font-weight: var(--matcha-weight-medium, 500);
|
|
99
|
-
line-height: var(--matcha-leading-md, 20px);
|
|
100
|
-
height: 40px;
|
|
101
|
-
min-width: 40px;
|
|
102
|
-
gap: var(--matcha-space-100, 8px);
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
// LG/Large — 48px. Figma: pad 24 · gap 8
|
|
106
|
-
&[size#{$infix}="lg"],
|
|
107
|
-
&[size#{$infix}="large"] {
|
|
108
|
-
padding: 0 var(--matcha-space-300, 24px);
|
|
109
|
-
font-size: var(--matcha-text-lg, 16px);
|
|
110
|
-
font-weight: var(--matcha-weight-semibold, 600);
|
|
111
|
-
line-height: var(--matcha-leading-label-lg, 22px);
|
|
112
|
-
height: 48px;
|
|
113
|
-
min-width: 48px;
|
|
114
|
-
gap: var(--matcha-space-100, 8px);
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
// XL/Huge — 56px. Figma: pad 32 · gap 8
|
|
118
|
-
&[size#{$infix}="xl"],
|
|
119
|
-
&[size#{$infix}="huge"] {
|
|
120
|
-
padding: 0 var(--matcha-space-400, 32px);
|
|
121
|
-
font-size: var(--matcha-text-lg, 16px);
|
|
122
|
-
font-weight: var(--matcha-weight-semibold, 600);
|
|
123
|
-
line-height: var(--matcha-leading-label-lg, 22px);
|
|
124
|
-
height: 56px;
|
|
125
|
-
min-width: 56px;
|
|
126
|
-
gap: var(--matcha-space-100, 8px);
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
// ── Structural ──────────────────────────────────────────────────────────────
|
|
133
|
-
|
|
134
|
-
button[matcha-button],
|
|
135
|
-
a[matcha-button],
|
|
136
|
-
button[matcha-icon-button],
|
|
137
|
-
a[matcha-icon-button],
|
|
138
|
-
button[matcha-link],
|
|
139
|
-
a[matcha-link] {
|
|
140
|
-
overflow: hidden;
|
|
141
|
-
position: relative;
|
|
142
|
-
font-size: var(--matcha-text-md, 14px);
|
|
143
|
-
font-weight: var(--matcha-weight-medium, 500);
|
|
144
|
-
font-family: inherit;
|
|
145
|
-
height: px-to-rem(40px); // default MD; overridden by size attribute selectors
|
|
146
|
-
min-width: px-to-rem(40px); // piso quadrado do default MD; ver mixin de sizes
|
|
147
|
-
appearance: auto;
|
|
148
|
-
text-rendering: auto;
|
|
149
|
-
letter-spacing: var(--matcha-letter-spacing-button, 0.2px);
|
|
150
|
-
word-spacing: normal;
|
|
151
|
-
line-height: normal;
|
|
152
|
-
text-transform: none;
|
|
153
|
-
text-indent: 0px;
|
|
154
|
-
text-shadow: none;
|
|
155
|
-
text-align: center;
|
|
156
|
-
text-wrap: nowrap;
|
|
157
|
-
text-decoration: none; // reset do underline default quando o host é <a> (variant != link)
|
|
158
|
-
display: flex;
|
|
159
|
-
justify-content: center;
|
|
160
|
-
align-items: center;
|
|
161
|
-
cursor: pointer;
|
|
162
|
-
box-sizing: border-box;
|
|
163
|
-
border: none;
|
|
164
|
-
border-radius: var(--matcha-radius-lg, 8px);
|
|
165
|
-
|
|
166
|
-
// Figma matcha/button usa DOIS feedbacks combinados:
|
|
167
|
-
// 1. Cor do bg muda (accent-default → accent-hover → accent-pressed)
|
|
168
|
-
// 2. State-layer overlay por cima (matcha/color/state-layer/fg)
|
|
169
|
-
// - Filled: opacity 0.15 hover / 0.30 active
|
|
170
|
-
// - Outline/Ghost: opacity 0.10 hover / 0.20 active
|
|
171
|
-
// ::before aplica o state-layer; :hover/:active ou .is-state-* ativam.
|
|
172
|
-
// NOTA: declarada ANTES das regras aninhadas (evita a deprecação mixed-decls);
|
|
173
|
-
// é onde o hoisting do Sass já a colocava — output byte-idêntico.
|
|
174
|
-
transition:
|
|
175
|
-
background-color 150ms cubic-bezier(0.4, 0, 0.2, 1),
|
|
176
|
-
box-shadow 150ms cubic-bezier(0.4, 0, 0.2, 1),
|
|
177
|
-
color 150ms cubic-bezier(0.4, 0, 0.2, 1);
|
|
178
|
-
|
|
179
|
-
* { pointer-events: none; }
|
|
180
|
-
|
|
181
|
-
// Figma spec: ícones dentro de button herdam a foreground color do botão
|
|
182
|
-
// (matcha-icon tem color-default próprio via tema — forçamos inherit com !important
|
|
183
|
-
// pra vencer o tema que aplica em [class^="i-matcha-"] globalmente)
|
|
184
|
-
matcha-icon,
|
|
185
|
-
[class^="i-matcha-"],
|
|
186
|
-
[class*=" i-matcha-"] {
|
|
187
|
-
color: inherit !important;
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
@include generate-matcha-button-size-classes($helper-breakpoints);
|
|
191
|
-
|
|
192
|
-
&::before {
|
|
193
|
-
content: '';
|
|
194
|
-
position: absolute;
|
|
195
|
-
inset: 0;
|
|
196
|
-
background: var(--matcha-color-state-layer-fg, currentColor);
|
|
197
|
-
opacity: 0;
|
|
198
|
-
border-radius: inherit;
|
|
199
|
-
pointer-events: none;
|
|
200
|
-
transition: opacity 150ms cubic-bezier(0.4, 0, 0.2, 1);
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
// Filled (variant default) — state-layer forte
|
|
204
|
-
&:hover:not([disabled]):not([disabled="true"]):not([outline]):not([basic]):not([ghost]):not([link]):not([alpha]):not([matcha-link])::before,
|
|
205
|
-
&.is-state-hover:not([outline]):not([basic]):not([ghost]):not([alpha])::before {
|
|
206
|
-
opacity: 0.15;
|
|
207
|
-
}
|
|
208
|
-
&:active:not([disabled]):not([disabled="true"]):not([outline]):not([basic]):not([ghost]):not([link]):not([alpha]):not([matcha-link])::before,
|
|
209
|
-
&.is-state-active:not([outline]):not([basic]):not([ghost]):not([alpha])::before {
|
|
210
|
-
opacity: 0.30;
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
// Outline / Ghost — state-layer sutil
|
|
214
|
-
&[outline]:hover:not([disabled]):not([disabled="true"])::before,
|
|
215
|
-
&[basic]:hover:not([disabled]):not([disabled="true"])::before,
|
|
216
|
-
&[ghost]:hover:not([disabled]):not([disabled="true"])::before,
|
|
217
|
-
&[outline].is-state-hover::before,
|
|
218
|
-
&[basic].is-state-hover::before,
|
|
219
|
-
&[ghost].is-state-hover::before {
|
|
220
|
-
opacity: 0.10;
|
|
221
|
-
}
|
|
222
|
-
&[outline]:active:not([disabled]):not([disabled="true"])::before,
|
|
223
|
-
&[basic]:active:not([disabled]):not([disabled="true"])::before,
|
|
224
|
-
&[ghost]:active:not([disabled]):not([disabled="true"])::before,
|
|
225
|
-
&[outline].is-state-active::before,
|
|
226
|
-
&[basic].is-state-active::before,
|
|
227
|
-
&[ghost].is-state-active::before {
|
|
228
|
-
opacity: 0.20;
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
&[disabled] {
|
|
232
|
-
pointer-events: none;
|
|
233
|
-
cursor: default;
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
// ── Variant modifiers (estrutural — cores vêm do mixin de tema) ──
|
|
237
|
-
&[basic]:not([basic="false"]),
|
|
238
|
-
&[ghost]:not([ghost="false"]) {
|
|
239
|
-
background: transparent;
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
&[outline]:not([outline="false"]) {
|
|
243
|
-
background: transparent;
|
|
244
|
-
|
|
245
|
-
&[link]:not([link="false"]) {
|
|
246
|
-
&[size="xs"], &[size="tiny"] { padding: 0 var(--matcha-space-100, 8px); gap: var(--matcha-space-050, 4px); }
|
|
247
|
-
&[size="sm"], &[size="small"] { padding: 0 var(--matcha-space-100, 8px); gap: var(--matcha-space-050, 4px); }
|
|
248
|
-
&[size="md"], &[size="medium"] { padding: 0 var(--matcha-space-150, 12px); gap: var(--matcha-space-100, 8px); }
|
|
249
|
-
&[size="lg"], &[size="large"] { padding: 0 var(--matcha-space-200, 16px); gap: var(--matcha-space-150, 12px); }
|
|
250
|
-
&[size="xl"], &[size="huge"] { padding: 0 var(--matcha-space-200, 16px); gap: var(--matcha-space-150, 12px); }
|
|
251
|
-
}
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
&[pill]:not([pill="false"]) {
|
|
255
|
-
border-radius: var(--matcha-radius-pill, 9999px);
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
&[link]:not([link="false"]) {
|
|
259
|
-
text-transform: initial;
|
|
260
|
-
letter-spacing: 0;
|
|
261
|
-
text-decoration: none;
|
|
262
|
-
padding: 0;
|
|
263
|
-
background: transparent;
|
|
264
|
-
}
|
|
265
|
-
|
|
266
|
-
// Link legado é texto inline (padding 0) — o piso quadrado do size viraria
|
|
267
|
-
// espaço morto clicável em volta do label, então cai aqui.
|
|
268
|
-
// O `:not([outline])` é deliberado: o combo [outline][link] é um botão com
|
|
269
|
-
// borda e padding real (bloco acima), esse MANTÉM o piso.
|
|
270
|
-
&[link]:not([link="false"]):not([outline]) {
|
|
271
|
-
min-width: 0;
|
|
272
|
-
}
|
|
273
|
-
|
|
274
|
-
// ── matcha-link specific (Figma spec 16914:500) ──
|
|
275
|
-
// SM=11/14 Regular letter 0.3 · MD=14/20 Medium · LG=16/22 SemiBold
|
|
276
|
-
// Hover/Active → underline automático. Underline=true → permanente.
|
|
277
|
-
// Disabled → opacity via disabled-fg color (no underline).
|
|
278
|
-
&[matcha-link] {
|
|
279
|
-
height: auto;
|
|
280
|
-
min-height: 0;
|
|
281
|
-
max-height: none;
|
|
282
|
-
min-width: 0; // texto inline não tem piso quadrado (ver mixin de sizes)
|
|
283
|
-
padding: 0;
|
|
284
|
-
background: transparent;
|
|
285
|
-
border-radius: 0;
|
|
286
|
-
text-decoration: none; // reset do underline default do <a>; hover/class re-aplica
|
|
287
|
-
|
|
288
|
-
&[size="sm"], &[size="tiny"] {
|
|
289
|
-
font-size: var(--matcha-text-p-tiny, 11px);
|
|
290
|
-
line-height: var(--matcha-leading-p-tiny, 14px);
|
|
291
|
-
font-weight: var(--matcha-weight-regular, 400);
|
|
292
|
-
letter-spacing: var(--matcha-letter-spacing-caption, 0.3px);
|
|
293
|
-
height: auto;
|
|
294
|
-
max-height: none;
|
|
295
|
-
}
|
|
296
|
-
&[size="md"], &[size="small"] {
|
|
297
|
-
font-size: var(--matcha-text-md, 14px);
|
|
298
|
-
line-height: var(--matcha-leading-md, 20px);
|
|
299
|
-
font-weight: var(--matcha-weight-medium, 500);
|
|
300
|
-
letter-spacing: var(--matcha-letter-spacing-button, 0.2px);
|
|
301
|
-
height: auto;
|
|
302
|
-
max-height: none;
|
|
303
|
-
}
|
|
304
|
-
&[size="lg"], &[size="medium"] {
|
|
305
|
-
font-size: var(--matcha-text-lg, 16px);
|
|
306
|
-
line-height: var(--matcha-leading-label-lg, 22px);
|
|
307
|
-
font-weight: var(--matcha-weight-semibold, 600);
|
|
308
|
-
letter-spacing: var(--matcha-letter-spacing-button, 0.2px);
|
|
309
|
-
height: auto;
|
|
310
|
-
max-height: none;
|
|
311
|
-
}
|
|
312
|
-
|
|
313
|
-
// State layer fica off (link não tem overlay/bg)
|
|
314
|
-
&::before { display: none; }
|
|
315
|
-
// Press scale também off — link é texto
|
|
316
|
-
transition: none;
|
|
317
|
-
&:active:not([disabled]):not([disabled="true"]) { transform: none; }
|
|
318
|
-
|
|
319
|
-
// Hover e active: underline (Figma spec)
|
|
320
|
-
&:hover:not([disabled]):not([disabled="true"]),
|
|
321
|
-
&:active:not([disabled]):not([disabled="true"]) {
|
|
322
|
-
text-decoration: underline;
|
|
323
|
-
}
|
|
324
|
-
|
|
325
|
-
// Underline permanente via property (classe do HostBinding no component)
|
|
326
|
-
&.matcha-link--underline {
|
|
327
|
-
text-decoration: underline;
|
|
328
|
-
}
|
|
329
|
-
|
|
330
|
-
// ── Canonical extended size names (tiny|small|medium|large|huge) ────────
|
|
331
|
-
// matcha-link expõe a escala CANÔNICA por extenso, 1:1 com sm/md/lg
|
|
332
|
-
// (sm→small · md→medium · lg→large). O bloco acima pareia esses nomes com
|
|
333
|
-
// a escala LEGADA do matcha-button (small=md, medium=lg), então
|
|
334
|
-
// re-asseguramos aqui — scoped APENAS ao matcha-link — os mesmos pixels do
|
|
335
|
-
// tier abreviado correspondente (sem mudança visual). tiny→sm tier (menor
|
|
336
|
-
// disponível), huge→lg tier (maior disponível no link).
|
|
337
|
-
&[size="tiny"],
|
|
338
|
-
&[size="small"] {
|
|
339
|
-
font-size: var(--matcha-text-p-tiny, 11px);
|
|
340
|
-
line-height: var(--matcha-leading-p-tiny, 14px);
|
|
341
|
-
font-weight: var(--matcha-weight-regular, 400);
|
|
342
|
-
letter-spacing: var(--matcha-letter-spacing-caption, 0.3px);
|
|
343
|
-
height: auto;
|
|
344
|
-
max-height: none;
|
|
345
|
-
}
|
|
346
|
-
&[size="medium"] {
|
|
347
|
-
font-size: var(--matcha-text-md, 14px);
|
|
348
|
-
line-height: var(--matcha-leading-md, 20px);
|
|
349
|
-
font-weight: var(--matcha-weight-medium, 500);
|
|
350
|
-
letter-spacing: var(--matcha-letter-spacing-button, 0.2px);
|
|
351
|
-
height: auto;
|
|
352
|
-
max-height: none;
|
|
353
|
-
}
|
|
354
|
-
&[size="large"],
|
|
355
|
-
&[size="huge"] {
|
|
356
|
-
font-size: var(--matcha-text-lg, 16px);
|
|
357
|
-
line-height: var(--matcha-leading-label-lg, 22px);
|
|
358
|
-
font-weight: var(--matcha-weight-semibold, 600);
|
|
359
|
-
letter-spacing: var(--matcha-letter-spacing-button, 0.2px);
|
|
360
|
-
height: auto;
|
|
361
|
-
max-height: none;
|
|
362
|
-
}
|
|
363
|
-
}
|
|
364
|
-
|
|
365
|
-
&[icon]:not([icon="false"]) {
|
|
366
|
-
aspect-ratio: 1;
|
|
367
|
-
display: flex;
|
|
368
|
-
align-items: center;
|
|
369
|
-
justify-content: center;
|
|
370
|
-
|
|
371
|
-
// Icon-button padding per Figma spec matcha/icon-button (all-direction):
|
|
372
|
-
// XS=6 · SM=6 · MD=8 · LG=12 · XL=16 (padding igual em todos os lados)
|
|
373
|
-
&[size="xs"], &[size="tiny"] {
|
|
374
|
-
padding: var(--matcha-space-075, 6px) !important;
|
|
375
|
-
}
|
|
376
|
-
&[size="sm"], &[size="small"] {
|
|
377
|
-
padding: var(--matcha-space-075, 6px) !important;
|
|
378
|
-
}
|
|
379
|
-
&[size="md"], &[size="medium"] {
|
|
380
|
-
padding: var(--matcha-space-100, 8px) !important;
|
|
381
|
-
}
|
|
382
|
-
&[size="lg"], &[size="large"] {
|
|
383
|
-
padding: var(--matcha-space-150, 12px) !important;
|
|
384
|
-
}
|
|
385
|
-
&[size="xl"], &[size="huge"] {
|
|
386
|
-
padding: var(--matcha-space-200, 16px) !important;
|
|
387
|
-
}
|
|
388
|
-
|
|
389
|
-
// Auto-size inner matcha-icon conforme Figma matcha/icon-button spec:
|
|
390
|
-
// XS→16 · SM→20 · MD→24 · LG→24 · XL→24
|
|
391
|
-
&[size="xs"] [class^="i-matcha-"],
|
|
392
|
-
&[size="xs"] [class*=" i-matcha-"],
|
|
393
|
-
&[size="tiny"] [class^="i-matcha-"],
|
|
394
|
-
&[size="tiny"] [class*=" i-matcha-"] {
|
|
395
|
-
font-size: var(--matcha-icon-size-sm, 16px);
|
|
396
|
-
width: var(--matcha-icon-size-sm, 16px);
|
|
397
|
-
height: var(--matcha-icon-size-sm, 16px);
|
|
398
|
-
line-height: var(--matcha-icon-size-sm, 16px);
|
|
399
|
-
}
|
|
400
|
-
&[size="sm"] [class^="i-matcha-"],
|
|
401
|
-
&[size="sm"] [class*=" i-matcha-"],
|
|
402
|
-
&[size="small"] [class^="i-matcha-"],
|
|
403
|
-
&[size="small"] [class*=" i-matcha-"] {
|
|
404
|
-
font-size: 20px;
|
|
405
|
-
width: 20px;
|
|
406
|
-
height: 20px;
|
|
407
|
-
line-height: 20px;
|
|
408
|
-
}
|
|
409
|
-
&[size="md"] [class^="i-matcha-"],
|
|
410
|
-
&[size="md"] [class*=" i-matcha-"],
|
|
411
|
-
&[size="medium"] [class^="i-matcha-"],
|
|
412
|
-
&[size="medium"] [class*=" i-matcha-"],
|
|
413
|
-
&[size="lg"] [class^="i-matcha-"],
|
|
414
|
-
&[size="lg"] [class*=" i-matcha-"],
|
|
415
|
-
&[size="large"] [class^="i-matcha-"],
|
|
416
|
-
&[size="large"] [class*=" i-matcha-"],
|
|
417
|
-
&[size="xl"] [class^="i-matcha-"],
|
|
418
|
-
&[size="xl"] [class*=" i-matcha-"],
|
|
419
|
-
&[size="huge"] [class^="i-matcha-"],
|
|
420
|
-
&[size="huge"] [class*=" i-matcha-"] {
|
|
421
|
-
font-size: var(--matcha-icon-size-md, 24px);
|
|
422
|
-
width: var(--matcha-icon-size-md, 24px);
|
|
423
|
-
height: var(--matcha-icon-size-md, 24px);
|
|
424
|
-
line-height: var(--matcha-icon-size-md, 24px);
|
|
425
|
-
}
|
|
426
|
-
}
|
|
427
|
-
|
|
428
|
-
// ── Badge ──
|
|
429
|
-
&[badge]:not([badge="false"]) {
|
|
430
|
-
overflow: visible;
|
|
431
|
-
position: relative;
|
|
432
|
-
|
|
433
|
-
&::after {
|
|
434
|
-
content: "";
|
|
435
|
-
position: absolute;
|
|
436
|
-
top: -0.25rem;
|
|
437
|
-
right: -0.25rem;
|
|
438
|
-
width: 1.32rem;
|
|
439
|
-
height: 1.32rem;
|
|
440
|
-
border-radius: var(--matcha-radius-pill, 9999px);
|
|
441
|
-
z-index: 2;
|
|
442
|
-
}
|
|
443
|
-
|
|
444
|
-
&[size="sm"]::after, &[size="small"]::after { width: 0.75rem; height: 0.75rem; top: -0.15rem; right: -0.15rem; }
|
|
445
|
-
&[size="md"]::after, &[size="medium"]::after { width: 1rem; height: 1rem; top: -0.2rem; right: -0.2rem; }
|
|
446
|
-
&[size="xl"]::after, &[size="huge"]::after { width: 1.5rem; height: 1.5rem; top: -0.3rem; right: -0.3rem; }
|
|
447
|
-
}
|
|
448
|
-
|
|
449
|
-
// ── Focus ring ──
|
|
450
|
-
&:focus-visible:not([disabled]) {
|
|
451
|
-
outline: var(--matcha-state-focus-ring-width, 2px) solid var(--matcha-color-accent, #6200ee);
|
|
452
|
-
outline-offset: var(--matcha-state-focus-ring-offset, 2px);
|
|
453
|
-
}
|
|
454
|
-
|
|
455
|
-
@media (prefers-reduced-motion: reduce) {
|
|
456
|
-
&::before { transition: none; }
|
|
457
|
-
&, &:active:not([disabled]):not([disabled="true"]) { transition: none; transform: none; }
|
|
458
|
-
}
|
|
459
|
-
|
|
460
|
-
// ── Loading state ──
|
|
461
|
-
// Spinner inline do lado direito do conteúdo + content dims pra 60%
|
|
462
|
-
// Preserva width (não shift) e bloqueia cliques com pointer-events.
|
|
463
|
-
&.matcha-button--loading {
|
|
464
|
-
pointer-events: none;
|
|
465
|
-
cursor: progress;
|
|
466
|
-
|
|
467
|
-
// Dim no content interior (tudo exceto o spinner)
|
|
468
|
-
> :not(.matcha-button__spinner) {
|
|
469
|
-
opacity: 0.6;
|
|
470
|
-
}
|
|
471
|
-
}
|
|
472
|
-
|
|
473
|
-
.matcha-button__spinner {
|
|
474
|
-
display: inline-flex;
|
|
475
|
-
align-items: center;
|
|
476
|
-
justify-content: center;
|
|
477
|
-
margin-left: var(--matcha-space-100, 8px);
|
|
478
|
-
flex: none;
|
|
479
|
-
line-height: 0;
|
|
480
|
-
|
|
481
|
-
svg {
|
|
482
|
-
display: block;
|
|
483
|
-
}
|
|
484
|
-
|
|
485
|
-
@media (prefers-reduced-motion: reduce) {
|
|
486
|
-
svg circle animateTransform {
|
|
487
|
-
// Retarda mas não remove (ainda sinaliza loading)
|
|
488
|
-
dur: 2s !important;
|
|
489
|
-
}
|
|
490
|
-
}
|
|
491
|
-
}
|
|
492
|
-
|
|
493
|
-
// Visually hidden span pra screen readers (loading announcement)
|
|
494
|
-
.matcha-button__sr-only {
|
|
495
|
-
position: absolute !important;
|
|
496
|
-
width: 1px !important;
|
|
497
|
-
height: 1px !important;
|
|
498
|
-
padding: 0 !important;
|
|
499
|
-
margin: -1px !important;
|
|
500
|
-
overflow: hidden !important;
|
|
501
|
-
clip: rect(0, 0, 0, 0) !important;
|
|
502
|
-
white-space: nowrap !important;
|
|
503
|
-
border: 0 !important;
|
|
504
|
-
}
|
|
505
|
-
|
|
506
|
-
// ── Touch targets (WCAG 2.5.5: 44x44 mínimo em coarse pointers) ──
|
|
507
|
-
// XS (28), SM (32), MD (40) ficam abaixo de 44px — expande hit area invisível.
|
|
508
|
-
// NÃO re-declarar `position` aqui: o bloco estrutural acima já garante botão
|
|
509
|
-
// positioned (relative), e o ::after ancora em qualquer positioned. Re-assertar
|
|
510
|
-
// com [size] sobe a especificidade pra (0,2,1) e quebra consumidores que
|
|
511
|
-
// reposicionam o botão com absolute (close mobile do notification/banner).
|
|
512
|
-
@media (pointer: coarse) {
|
|
513
|
-
&[size="xs"],
|
|
514
|
-
&[size="sm"], &[size="tiny"],
|
|
515
|
-
&[size="md"], &[size="small"] {
|
|
516
|
-
&::after {
|
|
517
|
-
content: '';
|
|
518
|
-
position: absolute;
|
|
519
|
-
inset: -8px; // expande ~16px em cada eixo → 28+16=44, 32+16=48, 40+16=56 ✓
|
|
520
|
-
z-index: 0;
|
|
521
|
-
pointer-events: auto; // captura cliques aqui
|
|
522
|
-
}
|
|
523
|
-
|
|
524
|
-
// ::before já é usado pro state layer, então nosso overlay vai no ::after
|
|
525
|
-
// State layer (::before) fica colado ao botão visual, overlay (::after) expande hit.
|
|
526
|
-
}
|
|
527
|
-
}
|
|
528
|
-
}
|
|
529
|
-
|
|
530
|
-
// ── Theme mixin ─────────────────────────────────────────────────────────────
|
|
531
|
-
|
|
532
|
-
@mixin matcha-button-theme($theme) {
|
|
533
|
-
// ═════════════════════════════════════════════════════════════════════════
|
|
534
|
-
// CSS var-based theming (regra DS-ARCHITECTURE #7: Tokens over hardcode)
|
|
535
|
-
//
|
|
536
|
-
// Todo botão usa --matcha-button-color como token interno.
|
|
537
|
-
// `[color="X"]` apenas mapeia pra esses tokens — as variantes
|
|
538
|
-
// (filled/outline/ghost/alpha/link) interpretam um único set de vars.
|
|
539
|
-
//
|
|
540
|
-
// Consumidor pode override QUALQUER cor via style:
|
|
541
|
-
// <button matcha-button style="--matcha-button-color: #ff00ff">Custom</button>
|
|
542
|
-
//
|
|
543
|
-
// Adicionar cor nova = adicionar 1 mapping (3 linhas).
|
|
544
|
-
// ═════════════════════════════════════════════════════════════════════════
|
|
545
|
-
|
|
546
|
-
button[matcha-button],
|
|
547
|
-
a[matcha-button],
|
|
548
|
-
button[matcha-icon-button],
|
|
549
|
-
a[matcha-icon-button],
|
|
550
|
-
button[matcha-link],
|
|
551
|
-
a[matcha-link] {
|
|
552
|
-
// Tokens internos (Figma matcha/button 13913:1088):
|
|
553
|
-
// --matcha-button-color = bg do filled (Default)
|
|
554
|
-
// --matcha-button-color-hover = bg filled / stroke outline (Hover)
|
|
555
|
-
// --matcha-button-color-pressed = bg filled / stroke+text (Active)
|
|
556
|
-
// --matcha-button-color-text-on = texto do filled (accent/text-on etc.)
|
|
557
|
-
// --matcha-button-color-alpha = alpha modifier / ripple
|
|
558
|
-
// --matcha-button-color-edge = stroke do outline (Default)
|
|
559
|
-
--matcha-button-color: var(--matcha-color-neutral);
|
|
560
|
-
--matcha-button-color-hover: var(--matcha-color-neutral-hover);
|
|
561
|
-
--matcha-button-color-pressed: var(--matcha-color-neutral-hover);
|
|
562
|
-
--matcha-button-color-text-on: var(--matcha-color-neutral-contrast);
|
|
563
|
-
--matcha-button-color-alpha: var(--matcha-color-neutral-alpha);
|
|
564
|
-
--matcha-button-color-edge: var(--matcha-color-fg);
|
|
565
|
-
|
|
566
|
-
// Badge ring herda o bg do botão (filled) — outline/ghost override pra surface,
|
|
567
|
-
// pois o bg deles é transparente e o ring deve casar com a página atrás.
|
|
568
|
-
--matcha-color-badge-border: var(--matcha-button-color);
|
|
569
|
-
|
|
570
|
-
// ── Color mapping ────────────────────────────────────────────────────────────────
|
|
571
|
-
&[color="basic"] {
|
|
572
|
-
--matcha-button-color: var(--matcha-color-neutral);
|
|
573
|
-
--matcha-button-color-hover: var(--matcha-color-neutral-hover);
|
|
574
|
-
--matcha-button-color-pressed: var(--matcha-color-neutral-hover);
|
|
575
|
-
--matcha-button-color-text-on: var(--matcha-color-neutral-contrast);
|
|
576
|
-
--matcha-button-color-alpha: var(--matcha-color-neutral-alpha);
|
|
577
|
-
--matcha-button-color-edge: var(--matcha-color-fg);
|
|
578
|
-
}
|
|
579
|
-
&[color="primary"] {
|
|
580
|
-
--matcha-button-color: var(--matcha-color-primary);
|
|
581
|
-
--matcha-button-color-hover: var(--matcha-color-primary-hover);
|
|
582
|
-
--matcha-button-color-pressed: var(--matcha-color-primary-pressed);
|
|
583
|
-
--matcha-button-color-text-on: var(--matcha-color-primary-contrast);
|
|
584
|
-
--matcha-button-color-alpha: var(--matcha-color-primary-alpha);
|
|
585
|
-
--matcha-button-color-edge: var(--matcha-color-primary);
|
|
586
|
-
}
|
|
587
|
-
&[color="accent"] {
|
|
588
|
-
--matcha-button-color: var(--matcha-color-accent);
|
|
589
|
-
--matcha-button-color-hover: var(--matcha-color-accent-hover);
|
|
590
|
-
--matcha-button-color-pressed: var(--matcha-color-accent-pressed);
|
|
591
|
-
--matcha-button-color-text-on: var(--matcha-color-accent-text-on);
|
|
592
|
-
--matcha-button-color-alpha: var(--matcha-color-accent-alpha);
|
|
593
|
-
--matcha-button-color-edge: var(--matcha-color-accent);
|
|
594
|
-
}
|
|
595
|
-
&[color="success"] {
|
|
596
|
-
--matcha-button-color: var(--matcha-color-success);
|
|
597
|
-
--matcha-button-color-hover: var(--matcha-color-success-hover);
|
|
598
|
-
--matcha-button-color-pressed: var(--matcha-color-success-pressed);
|
|
599
|
-
--matcha-button-color-text-on: var(--matcha-color-success-contrast);
|
|
600
|
-
--matcha-button-color-alpha: var(--matcha-color-success-alpha);
|
|
601
|
-
--matcha-button-color-edge: var(--matcha-color-success);
|
|
602
|
-
}
|
|
603
|
-
&[color="warn"] {
|
|
604
|
-
--matcha-button-color: var(--matcha-color-warn);
|
|
605
|
-
--matcha-button-color-hover: var(--matcha-color-warn-hover);
|
|
606
|
-
--matcha-button-color-pressed: var(--matcha-color-warn-pressed);
|
|
607
|
-
--matcha-button-color-text-on: var(--matcha-color-warn-contrast);
|
|
608
|
-
--matcha-button-color-alpha: var(--matcha-color-warn-alpha);
|
|
609
|
-
--matcha-button-color-edge: var(--matcha-color-warn);
|
|
610
|
-
}
|
|
611
|
-
&[color="danger"] {
|
|
612
|
-
--matcha-button-color: var(--matcha-color-danger);
|
|
613
|
-
--matcha-button-color-hover: var(--matcha-color-danger-hover);
|
|
614
|
-
--matcha-button-color-pressed: var(--matcha-color-danger-pressed);
|
|
615
|
-
--matcha-button-color-text-on: var(--matcha-color-danger-contrast);
|
|
616
|
-
--matcha-button-color-alpha: var(--matcha-color-danger-alpha);
|
|
617
|
-
--matcha-button-color-edge: var(--matcha-color-danger);
|
|
618
|
-
}
|
|
619
|
-
&[color="info"] {
|
|
620
|
-
--matcha-button-color: var(--matcha-color-info);
|
|
621
|
-
--matcha-button-color-hover: var(--matcha-color-info-hover);
|
|
622
|
-
--matcha-button-color-pressed: var(--matcha-color-info-pressed);
|
|
623
|
-
--matcha-button-color-text-on: var(--matcha-color-info-contrast);
|
|
624
|
-
--matcha-button-color-alpha: var(--matcha-color-info-alpha);
|
|
625
|
-
--matcha-button-color-edge: var(--matcha-color-info);
|
|
626
|
-
}
|
|
627
|
-
|
|
628
|
-
// ── Filled (default variant) ──────────────────────────────────────────────────────
|
|
629
|
-
// Figma: Default=accent · Hover=accent-hover · Active=accent-pressed
|
|
630
|
-
background: var(--matcha-button-color);
|
|
631
|
-
color: var(--matcha-button-color-text-on);
|
|
632
|
-
|
|
633
|
-
&:hover:not([disabled]):not([disabled="true"]):not([outline]):not([basic]):not([ghost]):not([link]):not([alpha]):not([matcha-link]) {
|
|
634
|
-
background: var(--matcha-button-color-hover);
|
|
635
|
-
}
|
|
636
|
-
&:active:not([disabled]):not([disabled="true"]):not([outline]):not([basic]):not([ghost]):not([link]):not([alpha]):not([matcha-link]) {
|
|
637
|
-
background: var(--matcha-button-color-pressed);
|
|
638
|
-
}
|
|
639
|
-
|
|
640
|
-
// ── Variant: outline ────────────────────────────────────────────────────────────────
|
|
641
|
-
// Figma matcha/button (13913:1088) vs matcha/icon-button (13914:482):
|
|
642
|
-
// BUTTON outline: texto=text-primary · ícones=edge (accent)
|
|
643
|
-
// ICON-BUTTON outline: host color=edge (ícone herda via inherit !important)
|
|
644
|
-
// Hover: icons/host = accent-hover (texto button mantém primary)
|
|
645
|
-
// Active: tudo = accent-pressed
|
|
646
|
-
&[outline]:not([outline="false"]),
|
|
647
|
-
&[variant="outline"] {
|
|
648
|
-
background: transparent;
|
|
649
|
-
box-shadow: inset 0 0 0 var(--matcha-border-thin, 2px) var(--matcha-button-color-edge);
|
|
650
|
-
// Color slot: text segue --matcha-button-color-edge (border+text matching),
|
|
651
|
-
// com fallback pra text-primary quando consumer não setar a var.
|
|
652
|
-
// Antes era hardcoded text-primary → consumer tinha que duelar specificity.
|
|
653
|
-
color: var(--matcha-button-color-edge);
|
|
654
|
-
// Badge ring transparente — bg é transparente, qualquer cor fixa
|
|
655
|
-
// colide com o bg-do-pai-da-página (impossível detectar em CSS).
|
|
656
|
-
--matcha-color-badge-border: transparent;
|
|
657
|
-
|
|
658
|
-
&:hover:not([disabled]):not([disabled="true"]) {
|
|
659
|
-
box-shadow: inset 0 0 0 var(--matcha-border-thin, 2px) var(--matcha-button-color-hover);
|
|
660
|
-
}
|
|
661
|
-
&:active:not([disabled]):not([disabled="true"]) {
|
|
662
|
-
box-shadow: inset 0 0 0 var(--matcha-border-thin, 2px) var(--matcha-button-color-pressed);
|
|
663
|
-
color: var(--matcha-button-color-pressed);
|
|
664
|
-
}
|
|
665
|
-
}
|
|
666
|
-
|
|
667
|
-
// Icon-button outline: host color = edge (ícone é o único conteúdo semântico)
|
|
668
|
-
&[matcha-icon-button][outline]:not([outline="false"]),
|
|
669
|
-
&[matcha-icon-button][variant="outline"] {
|
|
670
|
-
color: var(--matcha-button-color-edge);
|
|
671
|
-
|
|
672
|
-
&:hover:not([disabled]):not([disabled="true"]) {
|
|
673
|
-
color: var(--matcha-button-color-hover);
|
|
674
|
-
}
|
|
675
|
-
&:active:not([disabled]):not([disabled="true"]) {
|
|
676
|
-
color: var(--matcha-button-color-pressed);
|
|
677
|
-
}
|
|
678
|
-
}
|
|
679
|
-
|
|
680
|
-
// Button outline: ícones (Left/Right) acompanham edge — texto mantém primary
|
|
681
|
-
&[matcha-button][outline]:not([outline="false"]) matcha-icon,
|
|
682
|
-
&[matcha-button][outline]:not([outline="false"]) [class^="i-matcha-"],
|
|
683
|
-
&[matcha-button][outline]:not([outline="false"]) [class*=" i-matcha-"],
|
|
684
|
-
&[matcha-button][variant="outline"] matcha-icon,
|
|
685
|
-
&[matcha-button][variant="outline"] [class^="i-matcha-"],
|
|
686
|
-
&[matcha-button][variant="outline"] [class*=" i-matcha-"] {
|
|
687
|
-
color: var(--matcha-button-color-edge) !important;
|
|
688
|
-
}
|
|
689
|
-
&[matcha-button][outline]:hover:not([disabled]):not([disabled="true"]) matcha-icon,
|
|
690
|
-
&[matcha-button][outline]:hover:not([disabled]):not([disabled="true"]) [class^="i-matcha-"],
|
|
691
|
-
&[matcha-button][outline].is-state-hover matcha-icon {
|
|
692
|
-
color: var(--matcha-button-color-hover) !important;
|
|
693
|
-
}
|
|
694
|
-
&[matcha-button][outline]:active:not([disabled]):not([disabled="true"]) matcha-icon,
|
|
695
|
-
&[matcha-button][outline]:active:not([disabled]):not([disabled="true"]) [class^="i-matcha-"],
|
|
696
|
-
&[matcha-button][outline].is-state-active matcha-icon {
|
|
697
|
-
color: var(--matcha-button-color-pressed) !important;
|
|
698
|
-
}
|
|
699
|
-
|
|
700
|
-
// ── Variant: ghost (basic = legacy alias) ────────────────────────────────────────
|
|
701
|
-
// Figma: Default/Hover=text-primary · Active=accent-pressed (texto + ícones)
|
|
702
|
-
// Slot --matcha-button-ghost-text com fallback text-primary (Figma intent
|
|
703
|
-
// preservado). Consumer override via parent: --matcha-button-ghost-text: X
|
|
704
|
-
&[basic]:not([basic="false"]),
|
|
705
|
-
&[ghost]:not([ghost="false"]),
|
|
706
|
-
&[variant="ghost"] {
|
|
707
|
-
background: transparent;
|
|
708
|
-
color: var(--matcha-button-ghost-text, var(--matcha-color-text-primary));
|
|
709
|
-
// Badge ring transparente — bg é transparente, qualquer cor fixa
|
|
710
|
-
// colide com o bg-do-pai-da-página (impossível detectar em CSS).
|
|
711
|
-
--matcha-color-badge-border: transparent;
|
|
712
|
-
|
|
713
|
-
&:active:not([disabled]):not([disabled="true"]) {
|
|
714
|
-
color: var(--matcha-button-color-pressed);
|
|
715
|
-
}
|
|
716
|
-
}
|
|
717
|
-
|
|
718
|
-
// Button ghost: ícones acompanham edge (accent) — texto mantém primary
|
|
719
|
-
&[matcha-button][basic]:not([basic="false"]) matcha-icon,
|
|
720
|
-
&[matcha-button][basic]:not([basic="false"]) [class^="i-matcha-"],
|
|
721
|
-
&[matcha-button][ghost]:not([ghost="false"]) matcha-icon,
|
|
722
|
-
&[matcha-button][ghost]:not([ghost="false"]) [class^="i-matcha-"],
|
|
723
|
-
&[matcha-button][variant="ghost"] matcha-icon,
|
|
724
|
-
&[matcha-button][variant="ghost"] [class^="i-matcha-"] {
|
|
725
|
-
color: var(--matcha-button-color-edge) !important;
|
|
726
|
-
}
|
|
727
|
-
// Hover: ícone mantém a cor de repouso (edge), igual ao texto (Figma:
|
|
728
|
-
// Default/Hover=text-primary). Antes usava --matcha-button-color-hover,
|
|
729
|
-
// um token pensado como cor de FUNDO de hover (ver comentário da linha
|
|
730
|
-
// ~526) sendo aplicado como cor de ÍCONE — funcionava por coincidência em
|
|
731
|
-
// botões soltos, mas junto de um --matcha-color-neutral-hover claro
|
|
732
|
-
// (#d8e1da) o contraste do ícone contra fundos escuros (ex.: matcha-panel)
|
|
733
|
-
// cai pra ~1.34:1, bem abaixo do mínimo WCAG de 3:1 pra ícones.
|
|
734
|
-
&[matcha-button][ghost]:active:not([disabled]):not([disabled="true"]) matcha-icon,
|
|
735
|
-
&[matcha-button][basic]:active:not([disabled]):not([disabled="true"]) matcha-icon,
|
|
736
|
-
&[matcha-button][ghost].is-state-active matcha-icon,
|
|
737
|
-
&[matcha-button][basic].is-state-active matcha-icon {
|
|
738
|
-
color: var(--matcha-button-color-pressed) !important;
|
|
739
|
-
}
|
|
740
|
-
|
|
741
|
-
// ── Icon-button neutral (basic/default) — Figma matcha/icon-button ──
|
|
742
|
-
// Outline/Ghost Default (13914:179 / 13914:332) vinculam o glyph — e a
|
|
743
|
-
// borda do Outline — a matcha/color/icon/default (#75767a light / #9aa0a6
|
|
744
|
-
// dark), o MESMO token do matcha-icon solto. O texto do botão usa fg/
|
|
745
|
-
// text-primary; o ícone do icon-button NÃO. Redireciona edge + ghost-text
|
|
746
|
-
// só pro icon-button neutro. Cores override (accent/danger/...) seguem a
|
|
747
|
-
// própria cor via os blocos &[color="..."] acima.
|
|
748
|
-
&[matcha-icon-button]:not([color]),
|
|
749
|
-
&[matcha-icon-button][color="basic"] {
|
|
750
|
-
--matcha-button-color-edge: var(--matcha-color-icon-default);
|
|
751
|
-
--matcha-button-ghost-text: var(--matcha-color-icon-default);
|
|
752
|
-
}
|
|
753
|
-
|
|
754
|
-
// ── Modifier: alpha ──────────────────────────────────────────────
|
|
755
|
-
&[alpha]:not([alpha="false"]) {
|
|
756
|
-
background: var(--matcha-button-color-alpha);
|
|
757
|
-
color: var(--matcha-button-color);
|
|
758
|
-
}
|
|
759
|
-
|
|
760
|
-
// ── Modifier: link (legacy, afeta button[link="true"]) ───────────
|
|
761
|
-
// matcha-link tem seu próprio bloco (&[matcha-link]) com regras
|
|
762
|
-
// próprias de underline (hover + .matcha-link--underline)
|
|
763
|
-
&[link]:not([link="false"]):not([matcha-link]) {
|
|
764
|
-
background: transparent;
|
|
765
|
-
color: var(--matcha-button-color);
|
|
766
|
-
text-decoration: underline;
|
|
767
|
-
}
|
|
768
|
-
// matcha-link: apenas cor do texto (o bloco estrutural [matcha-link]
|
|
769
|
-
// define text-decoration: none + hover/active + class underline)
|
|
770
|
-
&[matcha-link] {
|
|
771
|
-
color: var(--matcha-button-color);
|
|
772
|
-
}
|
|
773
|
-
|
|
774
|
-
// ── State: disabled ──────────────────────────────────────────────
|
|
775
|
-
// Figma (13913:1088) Disabled state:
|
|
776
|
-
// Filled: bg=interaction/disabled-bg · label+icons=accent/text-on (mesma cor do filled default)
|
|
777
|
-
// Outline: stroke=interaction/disabled-bg (NÃO disabled-border) · label+icons=disabled-fg
|
|
778
|
-
// Ghost: sem bg/stroke · label+icons=disabled-fg
|
|
779
|
-
// State-layer overlay DESLIGADO em todos disabled.
|
|
780
|
-
&[disabled]:not([disabled="false"]),
|
|
781
|
-
&[disabled="true"] {
|
|
782
|
-
pointer-events: none;
|
|
783
|
-
cursor: not-allowed;
|
|
784
|
-
|
|
785
|
-
// state-layer overlay desligado
|
|
786
|
-
&::before { opacity: 0 !important; }
|
|
787
|
-
|
|
788
|
-
// Filled — bg disabled + texto/ícones accent-text-on (Figma spec)
|
|
789
|
-
background: var(--matcha-color-interaction-disabled-bg);
|
|
790
|
-
color: var(--matcha-color-accent-text-on);
|
|
791
|
-
box-shadow: none;
|
|
792
|
-
|
|
793
|
-
// Outline — stroke usa mesma cor do filled-bg (Figma usa interaction/disabled-bg)
|
|
794
|
-
&[outline]:not([outline="false"]),
|
|
795
|
-
&[variant="outline"] {
|
|
796
|
-
background: transparent;
|
|
797
|
-
color: var(--matcha-color-interaction-disabled-fg);
|
|
798
|
-
box-shadow: inset 0 0 0 var(--matcha-border-thin, 2px) var(--matcha-color-interaction-disabled-bg);
|
|
799
|
-
}
|
|
800
|
-
|
|
801
|
-
// Ghost / basic / link — só texto dedicado
|
|
802
|
-
&[basic]:not([basic="false"]),
|
|
803
|
-
&[ghost]:not([ghost="false"]),
|
|
804
|
-
&[variant="ghost"],
|
|
805
|
-
&[link]:not([link="false"]) {
|
|
806
|
-
background: transparent;
|
|
807
|
-
color: var(--matcha-color-interaction-disabled-fg);
|
|
808
|
-
box-shadow: none;
|
|
809
|
-
}
|
|
810
|
-
|
|
811
|
-
// Alpha — bg alpha dedicado
|
|
812
|
-
&[alpha]:not([alpha="false"]) {
|
|
813
|
-
background: var(--matcha-color-interaction-disabled-bg-alpha);
|
|
814
|
-
color: var(--matcha-color-interaction-disabled-fg);
|
|
815
|
-
}
|
|
816
|
-
|
|
817
|
-
// Ícones do button (Left/Right) no disabled:
|
|
818
|
-
// Filled: herdam color do host (accent-text-on) ✓
|
|
819
|
-
// Outline/Ghost: forçam disabled-fg pra sobrescrever regra !important do edge
|
|
820
|
-
&[matcha-button][outline] matcha-icon,
|
|
821
|
-
&[matcha-button][outline] [class^="i-matcha-"],
|
|
822
|
-
&[matcha-button][outline] [class*=" i-matcha-"],
|
|
823
|
-
&[matcha-button][basic] matcha-icon,
|
|
824
|
-
&[matcha-button][basic] [class^="i-matcha-"],
|
|
825
|
-
&[matcha-button][ghost] matcha-icon,
|
|
826
|
-
&[matcha-button][ghost] [class^="i-matcha-"],
|
|
827
|
-
&[matcha-button][variant="outline"] matcha-icon,
|
|
828
|
-
&[matcha-button][variant="outline"] [class^="i-matcha-"],
|
|
829
|
-
&[matcha-button][variant="ghost"] matcha-icon,
|
|
830
|
-
&[matcha-button][variant="ghost"] [class^="i-matcha-"] {
|
|
831
|
-
color: var(--matcha-color-interaction-disabled-fg) !important;
|
|
832
|
-
}
|
|
833
|
-
}
|
|
834
|
-
|
|
835
|
-
// ── Badge indicator (always accent, pattern fixo) ────────────────
|
|
836
|
-
&[badge]:not([badge="false"])::after {
|
|
837
|
-
background: var(--matcha-color-accent);
|
|
838
|
-
}
|
|
839
|
-
|
|
840
|
-
// ── Ripple overlay ───────────────────────────────────────────────
|
|
841
|
-
.ripple {
|
|
842
|
-
background: var(--matcha-button-color-alpha);
|
|
843
|
-
}
|
|
844
|
-
}
|
|
845
|
-
}
|
|
846
|
-
|
|
847
|
-
// ── matcha-icon-button: auto-size inner icons per Figma spec ────────────────
|
|
848
|
-
// XS button (28) → icon 16 · SM (32) → 20 · MD (40)/LG (48)/XL (56) → 24
|
|
849
|
-
button[matcha-icon-button],
|
|
850
|
-
a[matcha-icon-button] {
|
|
851
|
-
aspect-ratio: 1;
|
|
852
|
-
|
|
853
|
-
matcha-icon {
|
|
854
|
-
flex: none; // NÃO expandir com o button
|
|
855
|
-
}
|
|
856
|
-
|
|
857
|
-
&[size="xs"] matcha-icon,
|
|
858
|
-
&[size="tiny"] matcha-icon {
|
|
859
|
-
font-size: 16px !important;
|
|
860
|
-
width: 16px !important;
|
|
861
|
-
height: 16px !important;
|
|
862
|
-
line-height: 16px !important;
|
|
863
|
-
}
|
|
864
|
-
&[size="sm"] matcha-icon,
|
|
865
|
-
&[size="small"] matcha-icon {
|
|
866
|
-
font-size: 20px !important;
|
|
867
|
-
width: 20px !important;
|
|
868
|
-
height: 20px !important;
|
|
869
|
-
line-height: 20px !important;
|
|
870
|
-
}
|
|
871
|
-
&[size="md"] matcha-icon,
|
|
872
|
-
&[size="medium"] matcha-icon,
|
|
873
|
-
&[size="lg"] matcha-icon,
|
|
874
|
-
&[size="large"] matcha-icon,
|
|
875
|
-
&[size="xl"] matcha-icon,
|
|
876
|
-
&[size="huge"] matcha-icon {
|
|
877
|
-
font-size: 24px !important;
|
|
878
|
-
width: 24px !important;
|
|
879
|
-
height: 24px !important;
|
|
880
|
-
line-height: 24px !important;
|
|
881
|
-
}
|
|
882
|
-
|
|
883
|
-
// Tamanho (height) e padding por size já vêm corretos do mixin compartilhado
|
|
884
|
-
// (generate-matcha-button-size-classes, aplicado via o seletor combinado no
|
|
885
|
-
// topo do arquivo) + do bloco &[icon] acima — ambos pareiam cada abreviação
|
|
886
|
-
// com seu extenso correto (sm↔small, md↔medium, lg↔large, xl↔huge). Este
|
|
887
|
-
// componente não precisa reafirmar nada aqui.
|
|
888
|
-
}
|
|
889
|
-
|
|
890
|
-
// ── matcha-button COM TEXTO: auto-size do matcha-icon projetado ──────────────
|
|
891
|
-
// O icon-button (acima) e o matcha-button[icon] (icon-only, no bloco &[icon]) já escalavam o
|
|
892
|
-
// ícone; o botão com texto não escalava nada, então o matcha-icon caía no próprio default
|
|
893
|
-
// (--matcha-icon-size-md, 24px) — proporcional só de MD (40px) pra cima. Num tiny (28px, texto
|
|
894
|
-
// 11/14) sobrava um ícone de 24px.
|
|
895
|
-
//
|
|
896
|
-
// Escala igual à do icon-button: XS/tiny → 16 · SM/small → 20 · MD+ → 24 (o default do
|
|
897
|
-
// matcha-icon já é 24, então MD/LG/XL não precisam de regra).
|
|
898
|
-
//
|
|
899
|
-
// Duas diferenças deliberadas em relação ao icon-button:
|
|
900
|
-
// 1. `matcha-icon:not([size])` — aqui o ícone divide o botão com o texto, e um `size`
|
|
901
|
-
// explícito do consumidor é escolha legítima que deve continuar valendo. O auto-size só
|
|
902
|
-
// age quando ninguém decidiu.
|
|
903
|
-
// 2. sem `!important`, consequência do item 1: como a regra nem casa quando há `size`, não há
|
|
904
|
-
// disputa de especificidade contra a classe `.i-size-*` que o componente emite.
|
|
905
|
-
//
|
|
906
|
-
// `:not([icon])` e `:not([matcha-icon-button])` preservam os dois casos que já tinham
|
|
907
|
-
// tratamento próprio. O bloco icon-only usa `[icon]:not([icon="false"])`, então em teoria
|
|
908
|
-
// `icon="false"` é botão com texto e deveria entrar aqui; não há um único uso dessa forma no
|
|
909
|
-
// showcase nem no painel, e um seletor extra só para ela seria ruído.
|
|
910
|
-
button[matcha-button]:not([matcha-icon-button]):not([icon]),
|
|
911
|
-
a[matcha-button]:not([matcha-icon-button]):not([icon]) {
|
|
912
|
-
&[size="xs"] matcha-icon:not([size]),
|
|
913
|
-
&[size="tiny"] matcha-icon:not([size]) {
|
|
914
|
-
font-size: var(--matcha-icon-size-sm, 16px);
|
|
915
|
-
width: var(--matcha-icon-size-sm, 16px);
|
|
916
|
-
height: var(--matcha-icon-size-sm, 16px);
|
|
917
|
-
line-height: var(--matcha-icon-size-sm, 16px);
|
|
918
|
-
}
|
|
919
|
-
|
|
920
|
-
// 20px não tem token (a escala de ícone vai 16/24/32) — mesmo literal que o icon-button usa.
|
|
921
|
-
&[size="sm"] matcha-icon:not([size]),
|
|
922
|
-
&[size="small"] matcha-icon:not([size]) {
|
|
923
|
-
font-size: 20px;
|
|
924
|
-
width: 20px;
|
|
925
|
-
height: 20px;
|
|
926
|
-
line-height: 20px;
|
|
927
|
-
}
|
|
928
|
-
}
|
|
929
|
-
|
|
930
|
-
// ── Forced colors (Windows High Contrast) ──
|
|
931
|
-
// Buttons precisam ser claramente acionáveis em high-contrast.
|
|
932
|
-
@media (forced-colors: active) {
|
|
933
|
-
button[matcha-button],
|
|
934
|
-
a[matcha-button],
|
|
935
|
-
button[matcha-icon-button],
|
|
936
|
-
a[matcha-icon-button] {
|
|
937
|
-
// Filled: usa botão de sistema (ButtonFace/ButtonText) — afford clicável.
|
|
938
|
-
background: ButtonFace !important;
|
|
939
|
-
color: ButtonText !important;
|
|
940
|
-
border: 1px solid ButtonText !important;
|
|
941
|
-
box-shadow: none !important;
|
|
942
|
-
|
|
943
|
-
// Outline/ghost/alpha/link — bg transparente, border CanvasText.
|
|
944
|
-
&[outline], &[basic], &[alpha], &[link] {
|
|
945
|
-
background: transparent !important;
|
|
946
|
-
border-color: CanvasText !important;
|
|
947
|
-
color: CanvasText !important;
|
|
948
|
-
}
|
|
949
|
-
|
|
950
|
-
// Disabled — GrayText system token.
|
|
951
|
-
&[disabled],
|
|
952
|
-
&.is-disabled {
|
|
953
|
-
color: GrayText !important;
|
|
954
|
-
border-color: GrayText !important;
|
|
955
|
-
}
|
|
956
|
-
|
|
957
|
-
&:focus-visible {
|
|
958
|
-
outline: 2px solid CanvasText !important;
|
|
959
|
-
outline-offset: 2px;
|
|
960
|
-
}
|
|
961
|
-
}
|
|
962
|
-
}
|
|
963
|
-
|
|
964
|
-
// ── Print ──
|
|
965
|
-
// Buttons hide (interativos, não fazem sentido em papel).
|
|
966
|
-
@media print {
|
|
967
|
-
button[matcha-button],
|
|
968
|
-
a[matcha-button],
|
|
969
|
-
button[matcha-icon-button],
|
|
970
|
-
a[matcha-icon-button] {
|
|
971
|
-
display: none !important;
|
|
972
|
-
}
|
|
973
|
-
}
|
|
1
|
+
@use "../abstracts/media-breakpoint" as *;
|
|
2
|
+
@use "../abstracts/functions" as *;
|
|
3
|
+
@use "../tokens/breakpoints-tokens" as *;
|
|
4
|
+
// =============================================================================
|
|
5
|
+
// matcha-buttons.scss — Button & Icon Button (modernized)
|
|
6
|
+
// Aligned with Figma: matcha/button + matcha/icon-button
|
|
7
|
+
// Sizes: SM(32) MD(40) LG(48) XL(56) + legacy aliases (tiny/small/medium/large/huge)
|
|
8
|
+
// Variants: Filled(default) Outline Ghost(basic) Alpha Link
|
|
9
|
+
// State layer: ::before opacity pattern (consistent with all DS components)
|
|
10
|
+
// =============================================================================
|
|
11
|
+
|
|
12
|
+
// ── Disabled mixins ─────────────────────────────────────────────────────────
|
|
13
|
+
|
|
14
|
+
@mixin disabled-solid-button($theme) {
|
|
15
|
+
background: var(--matcha-color-disabled-bg);
|
|
16
|
+
color: var(--matcha-color-disabled-fg);
|
|
17
|
+
box-shadow: 0 0 0 0px inset;
|
|
18
|
+
pointer-events: none;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
@mixin disabled-basic-button($theme) {
|
|
22
|
+
background: var(--matcha-color-surface);
|
|
23
|
+
color: var(--matcha-color-disabled-bg);
|
|
24
|
+
box-shadow: 0 0 0 0px inset;
|
|
25
|
+
pointer-events: none;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
@mixin disabled-outline-button($theme) {
|
|
29
|
+
background: transparent;
|
|
30
|
+
color: var(--matcha-color-disabled-bg);
|
|
31
|
+
box-shadow: 0 0 0 var(--matcha-border-thin, 2px) inset;
|
|
32
|
+
pointer-events: none;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
@mixin disabled-alpha-button($theme) {
|
|
36
|
+
background: var(--matcha-color-disabled-bg-alpha, var(--matcha-color-interaction-disabled-bg-alpha));
|
|
37
|
+
color: var(--matcha-color-disabled-bg);
|
|
38
|
+
box-shadow: 0 0 0 0px inset;
|
|
39
|
+
pointer-events: none;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
@mixin disabled-link-button($theme) {
|
|
43
|
+
background: transparent;
|
|
44
|
+
color: var(--matcha-color-disabled-bg);
|
|
45
|
+
box-shadow: 0 0 0 0px inset;
|
|
46
|
+
pointer-events: none;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// ── Size classes (responsive, aligned with Figma XS/SM/MD/LG/XL) ────────────
|
|
50
|
+
//
|
|
51
|
+
// Cada size define `min-width` igual à sua `height`: o botão nunca fica mais
|
|
52
|
+
// estreito que alto. Sem esse piso a largura é só `padding + conteúdo`, e um
|
|
53
|
+
// label curto ("OK", "X") vira um retângulo VERTICAL — no XS, 23×28. Com o
|
|
54
|
+
// piso o pior caso é um quadrado, com o conteúdo centrado pelo
|
|
55
|
+
// `justify-content: center` do bloco estrutural. Label longo nunca atinge o
|
|
56
|
+
// piso, então nada muda onde já estava certo.
|
|
57
|
+
//
|
|
58
|
+
// Efeito colateral desejado em flex container: o botão tem `overflow: hidden`,
|
|
59
|
+
// o que já anula o `min-width: auto` (a automatic minimum size do flexbox só
|
|
60
|
+
// vale para item com `overflow: visible`) — ou seja, hoje ele encolhe até ~0 e
|
|
61
|
+
// corta o label. O piso troca esse colapso por um mínimo quadrado.
|
|
62
|
+
|
|
63
|
+
@mixin generate-matcha-button-size-classes($helper-breakpoints) {
|
|
64
|
+
@each $breakpoint, $materialBreakpoint in $helper-breakpoints {
|
|
65
|
+
@include media-breakpoint($materialBreakpoint) {
|
|
66
|
+
$infix: if($materialBreakpoint == null, "", "-#{$breakpoint}");
|
|
67
|
+
|
|
68
|
+
// XS/Tiny — 28px. Figma matcha/button XS: pad 8 · gap 2 · text/caption (11/400/14, letter 0.3)
|
|
69
|
+
&[size#{$infix}="xs"],
|
|
70
|
+
&[size#{$infix}="tiny"] {
|
|
71
|
+
padding: 0 var(--matcha-space-100, 8px);
|
|
72
|
+
font-size: var(--matcha-text-p-tiny, 11px);
|
|
73
|
+
font-weight: var(--matcha-weight-regular, 400);
|
|
74
|
+
line-height: var(--matcha-leading-p-tiny, 14px);
|
|
75
|
+
letter-spacing: var(--matcha-letter-spacing-caption, 0.3px);
|
|
76
|
+
height: 28px;
|
|
77
|
+
min-width: 28px;
|
|
78
|
+
gap: var(--matcha-space-025, 2px);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// SM/Small — 32px. Figma: pad 8 · gap 4 · text/button-sm (13/500/19 letter 0.2)
|
|
82
|
+
&[size#{$infix}="sm"],
|
|
83
|
+
&[size#{$infix}="small"] {
|
|
84
|
+
padding: 0 var(--matcha-space-100, 8px);
|
|
85
|
+
font-size: var(--matcha-text-label-sm, 13px);
|
|
86
|
+
font-weight: var(--matcha-weight-medium, 500);
|
|
87
|
+
line-height: var(--matcha-leading-label-sm, 19px);
|
|
88
|
+
height: 32px;
|
|
89
|
+
min-width: 32px;
|
|
90
|
+
gap: var(--matcha-space-050, 4px);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// MD/Medium — 40px. Figma: pad 16 · gap 8 · text/button-md (14/500/20)
|
|
94
|
+
&[size#{$infix}="md"],
|
|
95
|
+
&[size#{$infix}="medium"] {
|
|
96
|
+
padding: 0 var(--matcha-space-200, 16px);
|
|
97
|
+
font-size: var(--matcha-text-md, 14px);
|
|
98
|
+
font-weight: var(--matcha-weight-medium, 500);
|
|
99
|
+
line-height: var(--matcha-leading-md, 20px);
|
|
100
|
+
height: 40px;
|
|
101
|
+
min-width: 40px;
|
|
102
|
+
gap: var(--matcha-space-100, 8px);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// LG/Large — 48px. Figma: pad 24 · gap 8
|
|
106
|
+
&[size#{$infix}="lg"],
|
|
107
|
+
&[size#{$infix}="large"] {
|
|
108
|
+
padding: 0 var(--matcha-space-300, 24px);
|
|
109
|
+
font-size: var(--matcha-text-lg, 16px);
|
|
110
|
+
font-weight: var(--matcha-weight-semibold, 600);
|
|
111
|
+
line-height: var(--matcha-leading-label-lg, 22px);
|
|
112
|
+
height: 48px;
|
|
113
|
+
min-width: 48px;
|
|
114
|
+
gap: var(--matcha-space-100, 8px);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// XL/Huge — 56px. Figma: pad 32 · gap 8
|
|
118
|
+
&[size#{$infix}="xl"],
|
|
119
|
+
&[size#{$infix}="huge"] {
|
|
120
|
+
padding: 0 var(--matcha-space-400, 32px);
|
|
121
|
+
font-size: var(--matcha-text-lg, 16px);
|
|
122
|
+
font-weight: var(--matcha-weight-semibold, 600);
|
|
123
|
+
line-height: var(--matcha-leading-label-lg, 22px);
|
|
124
|
+
height: 56px;
|
|
125
|
+
min-width: 56px;
|
|
126
|
+
gap: var(--matcha-space-100, 8px);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// ── Structural ──────────────────────────────────────────────────────────────
|
|
133
|
+
|
|
134
|
+
button[matcha-button],
|
|
135
|
+
a[matcha-button],
|
|
136
|
+
button[matcha-icon-button],
|
|
137
|
+
a[matcha-icon-button],
|
|
138
|
+
button[matcha-link],
|
|
139
|
+
a[matcha-link] {
|
|
140
|
+
overflow: hidden;
|
|
141
|
+
position: relative;
|
|
142
|
+
font-size: var(--matcha-text-md, 14px);
|
|
143
|
+
font-weight: var(--matcha-weight-medium, 500);
|
|
144
|
+
font-family: inherit;
|
|
145
|
+
height: px-to-rem(40px); // default MD; overridden by size attribute selectors
|
|
146
|
+
min-width: px-to-rem(40px); // piso quadrado do default MD; ver mixin de sizes
|
|
147
|
+
appearance: auto;
|
|
148
|
+
text-rendering: auto;
|
|
149
|
+
letter-spacing: var(--matcha-letter-spacing-button, 0.2px);
|
|
150
|
+
word-spacing: normal;
|
|
151
|
+
line-height: normal;
|
|
152
|
+
text-transform: none;
|
|
153
|
+
text-indent: 0px;
|
|
154
|
+
text-shadow: none;
|
|
155
|
+
text-align: center;
|
|
156
|
+
text-wrap: nowrap;
|
|
157
|
+
text-decoration: none; // reset do underline default quando o host é <a> (variant != link)
|
|
158
|
+
display: flex;
|
|
159
|
+
justify-content: center;
|
|
160
|
+
align-items: center;
|
|
161
|
+
cursor: pointer;
|
|
162
|
+
box-sizing: border-box;
|
|
163
|
+
border: none;
|
|
164
|
+
border-radius: var(--matcha-radius-lg, 8px);
|
|
165
|
+
|
|
166
|
+
// Figma matcha/button usa DOIS feedbacks combinados:
|
|
167
|
+
// 1. Cor do bg muda (accent-default → accent-hover → accent-pressed)
|
|
168
|
+
// 2. State-layer overlay por cima (matcha/color/state-layer/fg)
|
|
169
|
+
// - Filled: opacity 0.15 hover / 0.30 active
|
|
170
|
+
// - Outline/Ghost: opacity 0.10 hover / 0.20 active
|
|
171
|
+
// ::before aplica o state-layer; :hover/:active ou .is-state-* ativam.
|
|
172
|
+
// NOTA: declarada ANTES das regras aninhadas (evita a deprecação mixed-decls);
|
|
173
|
+
// é onde o hoisting do Sass já a colocava — output byte-idêntico.
|
|
174
|
+
transition:
|
|
175
|
+
background-color 150ms cubic-bezier(0.4, 0, 0.2, 1),
|
|
176
|
+
box-shadow 150ms cubic-bezier(0.4, 0, 0.2, 1),
|
|
177
|
+
color 150ms cubic-bezier(0.4, 0, 0.2, 1);
|
|
178
|
+
|
|
179
|
+
* { pointer-events: none; }
|
|
180
|
+
|
|
181
|
+
// Figma spec: ícones dentro de button herdam a foreground color do botão
|
|
182
|
+
// (matcha-icon tem color-default próprio via tema — forçamos inherit com !important
|
|
183
|
+
// pra vencer o tema que aplica em [class^="i-matcha-"] globalmente)
|
|
184
|
+
matcha-icon,
|
|
185
|
+
[class^="i-matcha-"],
|
|
186
|
+
[class*=" i-matcha-"] {
|
|
187
|
+
color: inherit !important;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
@include generate-matcha-button-size-classes($helper-breakpoints);
|
|
191
|
+
|
|
192
|
+
&::before {
|
|
193
|
+
content: '';
|
|
194
|
+
position: absolute;
|
|
195
|
+
inset: 0;
|
|
196
|
+
background: var(--matcha-color-state-layer-fg, currentColor);
|
|
197
|
+
opacity: 0;
|
|
198
|
+
border-radius: inherit;
|
|
199
|
+
pointer-events: none;
|
|
200
|
+
transition: opacity 150ms cubic-bezier(0.4, 0, 0.2, 1);
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
// Filled (variant default) — state-layer forte
|
|
204
|
+
&:hover:not([disabled]):not([disabled="true"]):not([outline]):not([basic]):not([ghost]):not([link]):not([alpha]):not([matcha-link])::before,
|
|
205
|
+
&.is-state-hover:not([outline]):not([basic]):not([ghost]):not([alpha])::before {
|
|
206
|
+
opacity: 0.15;
|
|
207
|
+
}
|
|
208
|
+
&:active:not([disabled]):not([disabled="true"]):not([outline]):not([basic]):not([ghost]):not([link]):not([alpha]):not([matcha-link])::before,
|
|
209
|
+
&.is-state-active:not([outline]):not([basic]):not([ghost]):not([alpha])::before {
|
|
210
|
+
opacity: 0.30;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
// Outline / Ghost — state-layer sutil
|
|
214
|
+
&[outline]:hover:not([disabled]):not([disabled="true"])::before,
|
|
215
|
+
&[basic]:hover:not([disabled]):not([disabled="true"])::before,
|
|
216
|
+
&[ghost]:hover:not([disabled]):not([disabled="true"])::before,
|
|
217
|
+
&[outline].is-state-hover::before,
|
|
218
|
+
&[basic].is-state-hover::before,
|
|
219
|
+
&[ghost].is-state-hover::before {
|
|
220
|
+
opacity: 0.10;
|
|
221
|
+
}
|
|
222
|
+
&[outline]:active:not([disabled]):not([disabled="true"])::before,
|
|
223
|
+
&[basic]:active:not([disabled]):not([disabled="true"])::before,
|
|
224
|
+
&[ghost]:active:not([disabled]):not([disabled="true"])::before,
|
|
225
|
+
&[outline].is-state-active::before,
|
|
226
|
+
&[basic].is-state-active::before,
|
|
227
|
+
&[ghost].is-state-active::before {
|
|
228
|
+
opacity: 0.20;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
&[disabled] {
|
|
232
|
+
pointer-events: none;
|
|
233
|
+
cursor: default;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
// ── Variant modifiers (estrutural — cores vêm do mixin de tema) ──
|
|
237
|
+
&[basic]:not([basic="false"]),
|
|
238
|
+
&[ghost]:not([ghost="false"]) {
|
|
239
|
+
background: transparent;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
&[outline]:not([outline="false"]) {
|
|
243
|
+
background: transparent;
|
|
244
|
+
|
|
245
|
+
&[link]:not([link="false"]) {
|
|
246
|
+
&[size="xs"], &[size="tiny"] { padding: 0 var(--matcha-space-100, 8px); gap: var(--matcha-space-050, 4px); }
|
|
247
|
+
&[size="sm"], &[size="small"] { padding: 0 var(--matcha-space-100, 8px); gap: var(--matcha-space-050, 4px); }
|
|
248
|
+
&[size="md"], &[size="medium"] { padding: 0 var(--matcha-space-150, 12px); gap: var(--matcha-space-100, 8px); }
|
|
249
|
+
&[size="lg"], &[size="large"] { padding: 0 var(--matcha-space-200, 16px); gap: var(--matcha-space-150, 12px); }
|
|
250
|
+
&[size="xl"], &[size="huge"] { padding: 0 var(--matcha-space-200, 16px); gap: var(--matcha-space-150, 12px); }
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
&[pill]:not([pill="false"]) {
|
|
255
|
+
border-radius: var(--matcha-radius-pill, 9999px);
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
&[link]:not([link="false"]) {
|
|
259
|
+
text-transform: initial;
|
|
260
|
+
letter-spacing: 0;
|
|
261
|
+
text-decoration: none;
|
|
262
|
+
padding: 0;
|
|
263
|
+
background: transparent;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
// Link legado é texto inline (padding 0) — o piso quadrado do size viraria
|
|
267
|
+
// espaço morto clicável em volta do label, então cai aqui.
|
|
268
|
+
// O `:not([outline])` é deliberado: o combo [outline][link] é um botão com
|
|
269
|
+
// borda e padding real (bloco acima), esse MANTÉM o piso.
|
|
270
|
+
&[link]:not([link="false"]):not([outline]) {
|
|
271
|
+
min-width: 0;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
// ── matcha-link specific (Figma spec 16914:500) ──
|
|
275
|
+
// SM=11/14 Regular letter 0.3 · MD=14/20 Medium · LG=16/22 SemiBold
|
|
276
|
+
// Hover/Active → underline automático. Underline=true → permanente.
|
|
277
|
+
// Disabled → opacity via disabled-fg color (no underline).
|
|
278
|
+
&[matcha-link] {
|
|
279
|
+
height: auto;
|
|
280
|
+
min-height: 0;
|
|
281
|
+
max-height: none;
|
|
282
|
+
min-width: 0; // texto inline não tem piso quadrado (ver mixin de sizes)
|
|
283
|
+
padding: 0;
|
|
284
|
+
background: transparent;
|
|
285
|
+
border-radius: 0;
|
|
286
|
+
text-decoration: none; // reset do underline default do <a>; hover/class re-aplica
|
|
287
|
+
|
|
288
|
+
&[size="sm"], &[size="tiny"] {
|
|
289
|
+
font-size: var(--matcha-text-p-tiny, 11px);
|
|
290
|
+
line-height: var(--matcha-leading-p-tiny, 14px);
|
|
291
|
+
font-weight: var(--matcha-weight-regular, 400);
|
|
292
|
+
letter-spacing: var(--matcha-letter-spacing-caption, 0.3px);
|
|
293
|
+
height: auto;
|
|
294
|
+
max-height: none;
|
|
295
|
+
}
|
|
296
|
+
&[size="md"], &[size="small"] {
|
|
297
|
+
font-size: var(--matcha-text-md, 14px);
|
|
298
|
+
line-height: var(--matcha-leading-md, 20px);
|
|
299
|
+
font-weight: var(--matcha-weight-medium, 500);
|
|
300
|
+
letter-spacing: var(--matcha-letter-spacing-button, 0.2px);
|
|
301
|
+
height: auto;
|
|
302
|
+
max-height: none;
|
|
303
|
+
}
|
|
304
|
+
&[size="lg"], &[size="medium"] {
|
|
305
|
+
font-size: var(--matcha-text-lg, 16px);
|
|
306
|
+
line-height: var(--matcha-leading-label-lg, 22px);
|
|
307
|
+
font-weight: var(--matcha-weight-semibold, 600);
|
|
308
|
+
letter-spacing: var(--matcha-letter-spacing-button, 0.2px);
|
|
309
|
+
height: auto;
|
|
310
|
+
max-height: none;
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
// State layer fica off (link não tem overlay/bg)
|
|
314
|
+
&::before { display: none; }
|
|
315
|
+
// Press scale também off — link é texto
|
|
316
|
+
transition: none;
|
|
317
|
+
&:active:not([disabled]):not([disabled="true"]) { transform: none; }
|
|
318
|
+
|
|
319
|
+
// Hover e active: underline (Figma spec)
|
|
320
|
+
&:hover:not([disabled]):not([disabled="true"]),
|
|
321
|
+
&:active:not([disabled]):not([disabled="true"]) {
|
|
322
|
+
text-decoration: underline;
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
// Underline permanente via property (classe do HostBinding no component)
|
|
326
|
+
&.matcha-link--underline {
|
|
327
|
+
text-decoration: underline;
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
// ── Canonical extended size names (tiny|small|medium|large|huge) ────────
|
|
331
|
+
// matcha-link expõe a escala CANÔNICA por extenso, 1:1 com sm/md/lg
|
|
332
|
+
// (sm→small · md→medium · lg→large). O bloco acima pareia esses nomes com
|
|
333
|
+
// a escala LEGADA do matcha-button (small=md, medium=lg), então
|
|
334
|
+
// re-asseguramos aqui — scoped APENAS ao matcha-link — os mesmos pixels do
|
|
335
|
+
// tier abreviado correspondente (sem mudança visual). tiny→sm tier (menor
|
|
336
|
+
// disponível), huge→lg tier (maior disponível no link).
|
|
337
|
+
&[size="tiny"],
|
|
338
|
+
&[size="small"] {
|
|
339
|
+
font-size: var(--matcha-text-p-tiny, 11px);
|
|
340
|
+
line-height: var(--matcha-leading-p-tiny, 14px);
|
|
341
|
+
font-weight: var(--matcha-weight-regular, 400);
|
|
342
|
+
letter-spacing: var(--matcha-letter-spacing-caption, 0.3px);
|
|
343
|
+
height: auto;
|
|
344
|
+
max-height: none;
|
|
345
|
+
}
|
|
346
|
+
&[size="medium"] {
|
|
347
|
+
font-size: var(--matcha-text-md, 14px);
|
|
348
|
+
line-height: var(--matcha-leading-md, 20px);
|
|
349
|
+
font-weight: var(--matcha-weight-medium, 500);
|
|
350
|
+
letter-spacing: var(--matcha-letter-spacing-button, 0.2px);
|
|
351
|
+
height: auto;
|
|
352
|
+
max-height: none;
|
|
353
|
+
}
|
|
354
|
+
&[size="large"],
|
|
355
|
+
&[size="huge"] {
|
|
356
|
+
font-size: var(--matcha-text-lg, 16px);
|
|
357
|
+
line-height: var(--matcha-leading-label-lg, 22px);
|
|
358
|
+
font-weight: var(--matcha-weight-semibold, 600);
|
|
359
|
+
letter-spacing: var(--matcha-letter-spacing-button, 0.2px);
|
|
360
|
+
height: auto;
|
|
361
|
+
max-height: none;
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
&[icon]:not([icon="false"]) {
|
|
366
|
+
aspect-ratio: 1;
|
|
367
|
+
display: flex;
|
|
368
|
+
align-items: center;
|
|
369
|
+
justify-content: center;
|
|
370
|
+
|
|
371
|
+
// Icon-button padding per Figma spec matcha/icon-button (all-direction):
|
|
372
|
+
// XS=6 · SM=6 · MD=8 · LG=12 · XL=16 (padding igual em todos os lados)
|
|
373
|
+
&[size="xs"], &[size="tiny"] {
|
|
374
|
+
padding: var(--matcha-space-075, 6px) !important;
|
|
375
|
+
}
|
|
376
|
+
&[size="sm"], &[size="small"] {
|
|
377
|
+
padding: var(--matcha-space-075, 6px) !important;
|
|
378
|
+
}
|
|
379
|
+
&[size="md"], &[size="medium"] {
|
|
380
|
+
padding: var(--matcha-space-100, 8px) !important;
|
|
381
|
+
}
|
|
382
|
+
&[size="lg"], &[size="large"] {
|
|
383
|
+
padding: var(--matcha-space-150, 12px) !important;
|
|
384
|
+
}
|
|
385
|
+
&[size="xl"], &[size="huge"] {
|
|
386
|
+
padding: var(--matcha-space-200, 16px) !important;
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
// Auto-size inner matcha-icon conforme Figma matcha/icon-button spec:
|
|
390
|
+
// XS→16 · SM→20 · MD→24 · LG→24 · XL→24
|
|
391
|
+
&[size="xs"] [class^="i-matcha-"],
|
|
392
|
+
&[size="xs"] [class*=" i-matcha-"],
|
|
393
|
+
&[size="tiny"] [class^="i-matcha-"],
|
|
394
|
+
&[size="tiny"] [class*=" i-matcha-"] {
|
|
395
|
+
font-size: var(--matcha-icon-size-sm, 16px);
|
|
396
|
+
width: var(--matcha-icon-size-sm, 16px);
|
|
397
|
+
height: var(--matcha-icon-size-sm, 16px);
|
|
398
|
+
line-height: var(--matcha-icon-size-sm, 16px);
|
|
399
|
+
}
|
|
400
|
+
&[size="sm"] [class^="i-matcha-"],
|
|
401
|
+
&[size="sm"] [class*=" i-matcha-"],
|
|
402
|
+
&[size="small"] [class^="i-matcha-"],
|
|
403
|
+
&[size="small"] [class*=" i-matcha-"] {
|
|
404
|
+
font-size: 20px;
|
|
405
|
+
width: 20px;
|
|
406
|
+
height: 20px;
|
|
407
|
+
line-height: 20px;
|
|
408
|
+
}
|
|
409
|
+
&[size="md"] [class^="i-matcha-"],
|
|
410
|
+
&[size="md"] [class*=" i-matcha-"],
|
|
411
|
+
&[size="medium"] [class^="i-matcha-"],
|
|
412
|
+
&[size="medium"] [class*=" i-matcha-"],
|
|
413
|
+
&[size="lg"] [class^="i-matcha-"],
|
|
414
|
+
&[size="lg"] [class*=" i-matcha-"],
|
|
415
|
+
&[size="large"] [class^="i-matcha-"],
|
|
416
|
+
&[size="large"] [class*=" i-matcha-"],
|
|
417
|
+
&[size="xl"] [class^="i-matcha-"],
|
|
418
|
+
&[size="xl"] [class*=" i-matcha-"],
|
|
419
|
+
&[size="huge"] [class^="i-matcha-"],
|
|
420
|
+
&[size="huge"] [class*=" i-matcha-"] {
|
|
421
|
+
font-size: var(--matcha-icon-size-md, 24px);
|
|
422
|
+
width: var(--matcha-icon-size-md, 24px);
|
|
423
|
+
height: var(--matcha-icon-size-md, 24px);
|
|
424
|
+
line-height: var(--matcha-icon-size-md, 24px);
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
// ── Badge ──
|
|
429
|
+
&[badge]:not([badge="false"]) {
|
|
430
|
+
overflow: visible;
|
|
431
|
+
position: relative;
|
|
432
|
+
|
|
433
|
+
&::after {
|
|
434
|
+
content: "";
|
|
435
|
+
position: absolute;
|
|
436
|
+
top: -0.25rem;
|
|
437
|
+
right: -0.25rem;
|
|
438
|
+
width: 1.32rem;
|
|
439
|
+
height: 1.32rem;
|
|
440
|
+
border-radius: var(--matcha-radius-pill, 9999px);
|
|
441
|
+
z-index: 2;
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
&[size="sm"]::after, &[size="small"]::after { width: 0.75rem; height: 0.75rem; top: -0.15rem; right: -0.15rem; }
|
|
445
|
+
&[size="md"]::after, &[size="medium"]::after { width: 1rem; height: 1rem; top: -0.2rem; right: -0.2rem; }
|
|
446
|
+
&[size="xl"]::after, &[size="huge"]::after { width: 1.5rem; height: 1.5rem; top: -0.3rem; right: -0.3rem; }
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
// ── Focus ring ──
|
|
450
|
+
&:focus-visible:not([disabled]) {
|
|
451
|
+
outline: var(--matcha-state-focus-ring-width, 2px) solid var(--matcha-color-accent, #6200ee);
|
|
452
|
+
outline-offset: var(--matcha-state-focus-ring-offset, 2px);
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
@media (prefers-reduced-motion: reduce) {
|
|
456
|
+
&::before { transition: none; }
|
|
457
|
+
&, &:active:not([disabled]):not([disabled="true"]) { transition: none; transform: none; }
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
// ── Loading state ──
|
|
461
|
+
// Spinner inline do lado direito do conteúdo + content dims pra 60%
|
|
462
|
+
// Preserva width (não shift) e bloqueia cliques com pointer-events.
|
|
463
|
+
&.matcha-button--loading {
|
|
464
|
+
pointer-events: none;
|
|
465
|
+
cursor: progress;
|
|
466
|
+
|
|
467
|
+
// Dim no content interior (tudo exceto o spinner)
|
|
468
|
+
> :not(.matcha-button__spinner) {
|
|
469
|
+
opacity: 0.6;
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
.matcha-button__spinner {
|
|
474
|
+
display: inline-flex;
|
|
475
|
+
align-items: center;
|
|
476
|
+
justify-content: center;
|
|
477
|
+
margin-left: var(--matcha-space-100, 8px);
|
|
478
|
+
flex: none;
|
|
479
|
+
line-height: 0;
|
|
480
|
+
|
|
481
|
+
svg {
|
|
482
|
+
display: block;
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
@media (prefers-reduced-motion: reduce) {
|
|
486
|
+
svg circle animateTransform {
|
|
487
|
+
// Retarda mas não remove (ainda sinaliza loading)
|
|
488
|
+
dur: 2s !important;
|
|
489
|
+
}
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
// Visually hidden span pra screen readers (loading announcement)
|
|
494
|
+
.matcha-button__sr-only {
|
|
495
|
+
position: absolute !important;
|
|
496
|
+
width: 1px !important;
|
|
497
|
+
height: 1px !important;
|
|
498
|
+
padding: 0 !important;
|
|
499
|
+
margin: -1px !important;
|
|
500
|
+
overflow: hidden !important;
|
|
501
|
+
clip: rect(0, 0, 0, 0) !important;
|
|
502
|
+
white-space: nowrap !important;
|
|
503
|
+
border: 0 !important;
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
// ── Touch targets (WCAG 2.5.5: 44x44 mínimo em coarse pointers) ──
|
|
507
|
+
// XS (28), SM (32), MD (40) ficam abaixo de 44px — expande hit area invisível.
|
|
508
|
+
// NÃO re-declarar `position` aqui: o bloco estrutural acima já garante botão
|
|
509
|
+
// positioned (relative), e o ::after ancora em qualquer positioned. Re-assertar
|
|
510
|
+
// com [size] sobe a especificidade pra (0,2,1) e quebra consumidores que
|
|
511
|
+
// reposicionam o botão com absolute (close mobile do notification/banner).
|
|
512
|
+
@media (pointer: coarse) {
|
|
513
|
+
&[size="xs"],
|
|
514
|
+
&[size="sm"], &[size="tiny"],
|
|
515
|
+
&[size="md"], &[size="small"] {
|
|
516
|
+
&::after {
|
|
517
|
+
content: '';
|
|
518
|
+
position: absolute;
|
|
519
|
+
inset: -8px; // expande ~16px em cada eixo → 28+16=44, 32+16=48, 40+16=56 ✓
|
|
520
|
+
z-index: 0;
|
|
521
|
+
pointer-events: auto; // captura cliques aqui
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
// ::before já é usado pro state layer, então nosso overlay vai no ::after
|
|
525
|
+
// State layer (::before) fica colado ao botão visual, overlay (::after) expande hit.
|
|
526
|
+
}
|
|
527
|
+
}
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
// ── Theme mixin ─────────────────────────────────────────────────────────────
|
|
531
|
+
|
|
532
|
+
@mixin matcha-button-theme($theme) {
|
|
533
|
+
// ═════════════════════════════════════════════════════════════════════════
|
|
534
|
+
// CSS var-based theming (regra DS-ARCHITECTURE #7: Tokens over hardcode)
|
|
535
|
+
//
|
|
536
|
+
// Todo botão usa --matcha-button-color como token interno.
|
|
537
|
+
// `[color="X"]` apenas mapeia pra esses tokens — as variantes
|
|
538
|
+
// (filled/outline/ghost/alpha/link) interpretam um único set de vars.
|
|
539
|
+
//
|
|
540
|
+
// Consumidor pode override QUALQUER cor via style:
|
|
541
|
+
// <button matcha-button style="--matcha-button-color: #ff00ff">Custom</button>
|
|
542
|
+
//
|
|
543
|
+
// Adicionar cor nova = adicionar 1 mapping (3 linhas).
|
|
544
|
+
// ═════════════════════════════════════════════════════════════════════════
|
|
545
|
+
|
|
546
|
+
button[matcha-button],
|
|
547
|
+
a[matcha-button],
|
|
548
|
+
button[matcha-icon-button],
|
|
549
|
+
a[matcha-icon-button],
|
|
550
|
+
button[matcha-link],
|
|
551
|
+
a[matcha-link] {
|
|
552
|
+
// Tokens internos (Figma matcha/button 13913:1088):
|
|
553
|
+
// --matcha-button-color = bg do filled (Default)
|
|
554
|
+
// --matcha-button-color-hover = bg filled / stroke outline (Hover)
|
|
555
|
+
// --matcha-button-color-pressed = bg filled / stroke+text (Active)
|
|
556
|
+
// --matcha-button-color-text-on = texto do filled (accent/text-on etc.)
|
|
557
|
+
// --matcha-button-color-alpha = alpha modifier / ripple
|
|
558
|
+
// --matcha-button-color-edge = stroke do outline (Default)
|
|
559
|
+
--matcha-button-color: var(--matcha-color-neutral);
|
|
560
|
+
--matcha-button-color-hover: var(--matcha-color-neutral-hover);
|
|
561
|
+
--matcha-button-color-pressed: var(--matcha-color-neutral-hover);
|
|
562
|
+
--matcha-button-color-text-on: var(--matcha-color-neutral-contrast);
|
|
563
|
+
--matcha-button-color-alpha: var(--matcha-color-neutral-alpha);
|
|
564
|
+
--matcha-button-color-edge: var(--matcha-color-fg);
|
|
565
|
+
|
|
566
|
+
// Badge ring herda o bg do botão (filled) — outline/ghost override pra surface,
|
|
567
|
+
// pois o bg deles é transparente e o ring deve casar com a página atrás.
|
|
568
|
+
--matcha-color-badge-border: var(--matcha-button-color);
|
|
569
|
+
|
|
570
|
+
// ── Color mapping ────────────────────────────────────────────────────────────────
|
|
571
|
+
&[color="basic"] {
|
|
572
|
+
--matcha-button-color: var(--matcha-color-neutral);
|
|
573
|
+
--matcha-button-color-hover: var(--matcha-color-neutral-hover);
|
|
574
|
+
--matcha-button-color-pressed: var(--matcha-color-neutral-hover);
|
|
575
|
+
--matcha-button-color-text-on: var(--matcha-color-neutral-contrast);
|
|
576
|
+
--matcha-button-color-alpha: var(--matcha-color-neutral-alpha);
|
|
577
|
+
--matcha-button-color-edge: var(--matcha-color-fg);
|
|
578
|
+
}
|
|
579
|
+
&[color="primary"] {
|
|
580
|
+
--matcha-button-color: var(--matcha-color-primary);
|
|
581
|
+
--matcha-button-color-hover: var(--matcha-color-primary-hover);
|
|
582
|
+
--matcha-button-color-pressed: var(--matcha-color-primary-pressed);
|
|
583
|
+
--matcha-button-color-text-on: var(--matcha-color-primary-contrast);
|
|
584
|
+
--matcha-button-color-alpha: var(--matcha-color-primary-alpha);
|
|
585
|
+
--matcha-button-color-edge: var(--matcha-color-primary);
|
|
586
|
+
}
|
|
587
|
+
&[color="accent"] {
|
|
588
|
+
--matcha-button-color: var(--matcha-color-accent);
|
|
589
|
+
--matcha-button-color-hover: var(--matcha-color-accent-hover);
|
|
590
|
+
--matcha-button-color-pressed: var(--matcha-color-accent-pressed);
|
|
591
|
+
--matcha-button-color-text-on: var(--matcha-color-accent-text-on);
|
|
592
|
+
--matcha-button-color-alpha: var(--matcha-color-accent-alpha);
|
|
593
|
+
--matcha-button-color-edge: var(--matcha-color-accent);
|
|
594
|
+
}
|
|
595
|
+
&[color="success"] {
|
|
596
|
+
--matcha-button-color: var(--matcha-color-success);
|
|
597
|
+
--matcha-button-color-hover: var(--matcha-color-success-hover);
|
|
598
|
+
--matcha-button-color-pressed: var(--matcha-color-success-pressed);
|
|
599
|
+
--matcha-button-color-text-on: var(--matcha-color-success-contrast);
|
|
600
|
+
--matcha-button-color-alpha: var(--matcha-color-success-alpha);
|
|
601
|
+
--matcha-button-color-edge: var(--matcha-color-success);
|
|
602
|
+
}
|
|
603
|
+
&[color="warn"] {
|
|
604
|
+
--matcha-button-color: var(--matcha-color-warn);
|
|
605
|
+
--matcha-button-color-hover: var(--matcha-color-warn-hover);
|
|
606
|
+
--matcha-button-color-pressed: var(--matcha-color-warn-pressed);
|
|
607
|
+
--matcha-button-color-text-on: var(--matcha-color-warn-contrast);
|
|
608
|
+
--matcha-button-color-alpha: var(--matcha-color-warn-alpha);
|
|
609
|
+
--matcha-button-color-edge: var(--matcha-color-warn);
|
|
610
|
+
}
|
|
611
|
+
&[color="danger"] {
|
|
612
|
+
--matcha-button-color: var(--matcha-color-danger);
|
|
613
|
+
--matcha-button-color-hover: var(--matcha-color-danger-hover);
|
|
614
|
+
--matcha-button-color-pressed: var(--matcha-color-danger-pressed);
|
|
615
|
+
--matcha-button-color-text-on: var(--matcha-color-danger-contrast);
|
|
616
|
+
--matcha-button-color-alpha: var(--matcha-color-danger-alpha);
|
|
617
|
+
--matcha-button-color-edge: var(--matcha-color-danger);
|
|
618
|
+
}
|
|
619
|
+
&[color="info"] {
|
|
620
|
+
--matcha-button-color: var(--matcha-color-info);
|
|
621
|
+
--matcha-button-color-hover: var(--matcha-color-info-hover);
|
|
622
|
+
--matcha-button-color-pressed: var(--matcha-color-info-pressed);
|
|
623
|
+
--matcha-button-color-text-on: var(--matcha-color-info-contrast);
|
|
624
|
+
--matcha-button-color-alpha: var(--matcha-color-info-alpha);
|
|
625
|
+
--matcha-button-color-edge: var(--matcha-color-info);
|
|
626
|
+
}
|
|
627
|
+
|
|
628
|
+
// ── Filled (default variant) ──────────────────────────────────────────────────────
|
|
629
|
+
// Figma: Default=accent · Hover=accent-hover · Active=accent-pressed
|
|
630
|
+
background: var(--matcha-button-color);
|
|
631
|
+
color: var(--matcha-button-color-text-on);
|
|
632
|
+
|
|
633
|
+
&:hover:not([disabled]):not([disabled="true"]):not([outline]):not([basic]):not([ghost]):not([link]):not([alpha]):not([matcha-link]) {
|
|
634
|
+
background: var(--matcha-button-color-hover);
|
|
635
|
+
}
|
|
636
|
+
&:active:not([disabled]):not([disabled="true"]):not([outline]):not([basic]):not([ghost]):not([link]):not([alpha]):not([matcha-link]) {
|
|
637
|
+
background: var(--matcha-button-color-pressed);
|
|
638
|
+
}
|
|
639
|
+
|
|
640
|
+
// ── Variant: outline ────────────────────────────────────────────────────────────────
|
|
641
|
+
// Figma matcha/button (13913:1088) vs matcha/icon-button (13914:482):
|
|
642
|
+
// BUTTON outline: texto=text-primary · ícones=edge (accent)
|
|
643
|
+
// ICON-BUTTON outline: host color=edge (ícone herda via inherit !important)
|
|
644
|
+
// Hover: icons/host = accent-hover (texto button mantém primary)
|
|
645
|
+
// Active: tudo = accent-pressed
|
|
646
|
+
&[outline]:not([outline="false"]),
|
|
647
|
+
&[variant="outline"] {
|
|
648
|
+
background: transparent;
|
|
649
|
+
box-shadow: inset 0 0 0 var(--matcha-border-thin, 2px) var(--matcha-button-color-edge);
|
|
650
|
+
// Color slot: text segue --matcha-button-color-edge (border+text matching),
|
|
651
|
+
// com fallback pra text-primary quando consumer não setar a var.
|
|
652
|
+
// Antes era hardcoded text-primary → consumer tinha que duelar specificity.
|
|
653
|
+
color: var(--matcha-button-color-edge);
|
|
654
|
+
// Badge ring transparente — bg é transparente, qualquer cor fixa
|
|
655
|
+
// colide com o bg-do-pai-da-página (impossível detectar em CSS).
|
|
656
|
+
--matcha-color-badge-border: transparent;
|
|
657
|
+
|
|
658
|
+
&:hover:not([disabled]):not([disabled="true"]) {
|
|
659
|
+
box-shadow: inset 0 0 0 var(--matcha-border-thin, 2px) var(--matcha-button-color-hover);
|
|
660
|
+
}
|
|
661
|
+
&:active:not([disabled]):not([disabled="true"]) {
|
|
662
|
+
box-shadow: inset 0 0 0 var(--matcha-border-thin, 2px) var(--matcha-button-color-pressed);
|
|
663
|
+
color: var(--matcha-button-color-pressed);
|
|
664
|
+
}
|
|
665
|
+
}
|
|
666
|
+
|
|
667
|
+
// Icon-button outline: host color = edge (ícone é o único conteúdo semântico)
|
|
668
|
+
&[matcha-icon-button][outline]:not([outline="false"]),
|
|
669
|
+
&[matcha-icon-button][variant="outline"] {
|
|
670
|
+
color: var(--matcha-button-color-edge);
|
|
671
|
+
|
|
672
|
+
&:hover:not([disabled]):not([disabled="true"]) {
|
|
673
|
+
color: var(--matcha-button-color-hover);
|
|
674
|
+
}
|
|
675
|
+
&:active:not([disabled]):not([disabled="true"]) {
|
|
676
|
+
color: var(--matcha-button-color-pressed);
|
|
677
|
+
}
|
|
678
|
+
}
|
|
679
|
+
|
|
680
|
+
// Button outline: ícones (Left/Right) acompanham edge — texto mantém primary
|
|
681
|
+
&[matcha-button][outline]:not([outline="false"]) matcha-icon,
|
|
682
|
+
&[matcha-button][outline]:not([outline="false"]) [class^="i-matcha-"],
|
|
683
|
+
&[matcha-button][outline]:not([outline="false"]) [class*=" i-matcha-"],
|
|
684
|
+
&[matcha-button][variant="outline"] matcha-icon,
|
|
685
|
+
&[matcha-button][variant="outline"] [class^="i-matcha-"],
|
|
686
|
+
&[matcha-button][variant="outline"] [class*=" i-matcha-"] {
|
|
687
|
+
color: var(--matcha-button-color-edge) !important;
|
|
688
|
+
}
|
|
689
|
+
&[matcha-button][outline]:hover:not([disabled]):not([disabled="true"]) matcha-icon,
|
|
690
|
+
&[matcha-button][outline]:hover:not([disabled]):not([disabled="true"]) [class^="i-matcha-"],
|
|
691
|
+
&[matcha-button][outline].is-state-hover matcha-icon {
|
|
692
|
+
color: var(--matcha-button-color-hover) !important;
|
|
693
|
+
}
|
|
694
|
+
&[matcha-button][outline]:active:not([disabled]):not([disabled="true"]) matcha-icon,
|
|
695
|
+
&[matcha-button][outline]:active:not([disabled]):not([disabled="true"]) [class^="i-matcha-"],
|
|
696
|
+
&[matcha-button][outline].is-state-active matcha-icon {
|
|
697
|
+
color: var(--matcha-button-color-pressed) !important;
|
|
698
|
+
}
|
|
699
|
+
|
|
700
|
+
// ── Variant: ghost (basic = legacy alias) ────────────────────────────────────────
|
|
701
|
+
// Figma: Default/Hover=text-primary · Active=accent-pressed (texto + ícones)
|
|
702
|
+
// Slot --matcha-button-ghost-text com fallback text-primary (Figma intent
|
|
703
|
+
// preservado). Consumer override via parent: --matcha-button-ghost-text: X
|
|
704
|
+
&[basic]:not([basic="false"]),
|
|
705
|
+
&[ghost]:not([ghost="false"]),
|
|
706
|
+
&[variant="ghost"] {
|
|
707
|
+
background: transparent;
|
|
708
|
+
color: var(--matcha-button-ghost-text, var(--matcha-color-text-primary));
|
|
709
|
+
// Badge ring transparente — bg é transparente, qualquer cor fixa
|
|
710
|
+
// colide com o bg-do-pai-da-página (impossível detectar em CSS).
|
|
711
|
+
--matcha-color-badge-border: transparent;
|
|
712
|
+
|
|
713
|
+
&:active:not([disabled]):not([disabled="true"]) {
|
|
714
|
+
color: var(--matcha-button-color-pressed);
|
|
715
|
+
}
|
|
716
|
+
}
|
|
717
|
+
|
|
718
|
+
// Button ghost: ícones acompanham edge (accent) — texto mantém primary
|
|
719
|
+
&[matcha-button][basic]:not([basic="false"]) matcha-icon,
|
|
720
|
+
&[matcha-button][basic]:not([basic="false"]) [class^="i-matcha-"],
|
|
721
|
+
&[matcha-button][ghost]:not([ghost="false"]) matcha-icon,
|
|
722
|
+
&[matcha-button][ghost]:not([ghost="false"]) [class^="i-matcha-"],
|
|
723
|
+
&[matcha-button][variant="ghost"] matcha-icon,
|
|
724
|
+
&[matcha-button][variant="ghost"] [class^="i-matcha-"] {
|
|
725
|
+
color: var(--matcha-button-color-edge) !important;
|
|
726
|
+
}
|
|
727
|
+
// Hover: ícone mantém a cor de repouso (edge), igual ao texto (Figma:
|
|
728
|
+
// Default/Hover=text-primary). Antes usava --matcha-button-color-hover,
|
|
729
|
+
// um token pensado como cor de FUNDO de hover (ver comentário da linha
|
|
730
|
+
// ~526) sendo aplicado como cor de ÍCONE — funcionava por coincidência em
|
|
731
|
+
// botões soltos, mas junto de um --matcha-color-neutral-hover claro
|
|
732
|
+
// (#d8e1da) o contraste do ícone contra fundos escuros (ex.: matcha-panel)
|
|
733
|
+
// cai pra ~1.34:1, bem abaixo do mínimo WCAG de 3:1 pra ícones.
|
|
734
|
+
&[matcha-button][ghost]:active:not([disabled]):not([disabled="true"]) matcha-icon,
|
|
735
|
+
&[matcha-button][basic]:active:not([disabled]):not([disabled="true"]) matcha-icon,
|
|
736
|
+
&[matcha-button][ghost].is-state-active matcha-icon,
|
|
737
|
+
&[matcha-button][basic].is-state-active matcha-icon {
|
|
738
|
+
color: var(--matcha-button-color-pressed) !important;
|
|
739
|
+
}
|
|
740
|
+
|
|
741
|
+
// ── Icon-button neutral (basic/default) — Figma matcha/icon-button ──
|
|
742
|
+
// Outline/Ghost Default (13914:179 / 13914:332) vinculam o glyph — e a
|
|
743
|
+
// borda do Outline — a matcha/color/icon/default (#75767a light / #9aa0a6
|
|
744
|
+
// dark), o MESMO token do matcha-icon solto. O texto do botão usa fg/
|
|
745
|
+
// text-primary; o ícone do icon-button NÃO. Redireciona edge + ghost-text
|
|
746
|
+
// só pro icon-button neutro. Cores override (accent/danger/...) seguem a
|
|
747
|
+
// própria cor via os blocos &[color="..."] acima.
|
|
748
|
+
&[matcha-icon-button]:not([color]),
|
|
749
|
+
&[matcha-icon-button][color="basic"] {
|
|
750
|
+
--matcha-button-color-edge: var(--matcha-color-icon-default);
|
|
751
|
+
--matcha-button-ghost-text: var(--matcha-color-icon-default);
|
|
752
|
+
}
|
|
753
|
+
|
|
754
|
+
// ── Modifier: alpha ──────────────────────────────────────────────
|
|
755
|
+
&[alpha]:not([alpha="false"]) {
|
|
756
|
+
background: var(--matcha-button-color-alpha);
|
|
757
|
+
color: var(--matcha-button-color);
|
|
758
|
+
}
|
|
759
|
+
|
|
760
|
+
// ── Modifier: link (legacy, afeta button[link="true"]) ───────────
|
|
761
|
+
// matcha-link tem seu próprio bloco (&[matcha-link]) com regras
|
|
762
|
+
// próprias de underline (hover + .matcha-link--underline)
|
|
763
|
+
&[link]:not([link="false"]):not([matcha-link]) {
|
|
764
|
+
background: transparent;
|
|
765
|
+
color: var(--matcha-button-color);
|
|
766
|
+
text-decoration: underline;
|
|
767
|
+
}
|
|
768
|
+
// matcha-link: apenas cor do texto (o bloco estrutural [matcha-link]
|
|
769
|
+
// define text-decoration: none + hover/active + class underline)
|
|
770
|
+
&[matcha-link] {
|
|
771
|
+
color: var(--matcha-button-color);
|
|
772
|
+
}
|
|
773
|
+
|
|
774
|
+
// ── State: disabled ──────────────────────────────────────────────
|
|
775
|
+
// Figma (13913:1088) Disabled state:
|
|
776
|
+
// Filled: bg=interaction/disabled-bg · label+icons=accent/text-on (mesma cor do filled default)
|
|
777
|
+
// Outline: stroke=interaction/disabled-bg (NÃO disabled-border) · label+icons=disabled-fg
|
|
778
|
+
// Ghost: sem bg/stroke · label+icons=disabled-fg
|
|
779
|
+
// State-layer overlay DESLIGADO em todos disabled.
|
|
780
|
+
&[disabled]:not([disabled="false"]),
|
|
781
|
+
&[disabled="true"] {
|
|
782
|
+
pointer-events: none;
|
|
783
|
+
cursor: not-allowed;
|
|
784
|
+
|
|
785
|
+
// state-layer overlay desligado
|
|
786
|
+
&::before { opacity: 0 !important; }
|
|
787
|
+
|
|
788
|
+
// Filled — bg disabled + texto/ícones accent-text-on (Figma spec)
|
|
789
|
+
background: var(--matcha-color-interaction-disabled-bg);
|
|
790
|
+
color: var(--matcha-color-accent-text-on);
|
|
791
|
+
box-shadow: none;
|
|
792
|
+
|
|
793
|
+
// Outline — stroke usa mesma cor do filled-bg (Figma usa interaction/disabled-bg)
|
|
794
|
+
&[outline]:not([outline="false"]),
|
|
795
|
+
&[variant="outline"] {
|
|
796
|
+
background: transparent;
|
|
797
|
+
color: var(--matcha-color-interaction-disabled-fg);
|
|
798
|
+
box-shadow: inset 0 0 0 var(--matcha-border-thin, 2px) var(--matcha-color-interaction-disabled-bg);
|
|
799
|
+
}
|
|
800
|
+
|
|
801
|
+
// Ghost / basic / link — só texto dedicado
|
|
802
|
+
&[basic]:not([basic="false"]),
|
|
803
|
+
&[ghost]:not([ghost="false"]),
|
|
804
|
+
&[variant="ghost"],
|
|
805
|
+
&[link]:not([link="false"]) {
|
|
806
|
+
background: transparent;
|
|
807
|
+
color: var(--matcha-color-interaction-disabled-fg);
|
|
808
|
+
box-shadow: none;
|
|
809
|
+
}
|
|
810
|
+
|
|
811
|
+
// Alpha — bg alpha dedicado
|
|
812
|
+
&[alpha]:not([alpha="false"]) {
|
|
813
|
+
background: var(--matcha-color-interaction-disabled-bg-alpha);
|
|
814
|
+
color: var(--matcha-color-interaction-disabled-fg);
|
|
815
|
+
}
|
|
816
|
+
|
|
817
|
+
// Ícones do button (Left/Right) no disabled:
|
|
818
|
+
// Filled: herdam color do host (accent-text-on) ✓
|
|
819
|
+
// Outline/Ghost: forçam disabled-fg pra sobrescrever regra !important do edge
|
|
820
|
+
&[matcha-button][outline] matcha-icon,
|
|
821
|
+
&[matcha-button][outline] [class^="i-matcha-"],
|
|
822
|
+
&[matcha-button][outline] [class*=" i-matcha-"],
|
|
823
|
+
&[matcha-button][basic] matcha-icon,
|
|
824
|
+
&[matcha-button][basic] [class^="i-matcha-"],
|
|
825
|
+
&[matcha-button][ghost] matcha-icon,
|
|
826
|
+
&[matcha-button][ghost] [class^="i-matcha-"],
|
|
827
|
+
&[matcha-button][variant="outline"] matcha-icon,
|
|
828
|
+
&[matcha-button][variant="outline"] [class^="i-matcha-"],
|
|
829
|
+
&[matcha-button][variant="ghost"] matcha-icon,
|
|
830
|
+
&[matcha-button][variant="ghost"] [class^="i-matcha-"] {
|
|
831
|
+
color: var(--matcha-color-interaction-disabled-fg) !important;
|
|
832
|
+
}
|
|
833
|
+
}
|
|
834
|
+
|
|
835
|
+
// ── Badge indicator (always accent, pattern fixo) ────────────────
|
|
836
|
+
&[badge]:not([badge="false"])::after {
|
|
837
|
+
background: var(--matcha-color-accent);
|
|
838
|
+
}
|
|
839
|
+
|
|
840
|
+
// ── Ripple overlay ───────────────────────────────────────────────
|
|
841
|
+
.ripple {
|
|
842
|
+
background: var(--matcha-button-color-alpha);
|
|
843
|
+
}
|
|
844
|
+
}
|
|
845
|
+
}
|
|
846
|
+
|
|
847
|
+
// ── matcha-icon-button: auto-size inner icons per Figma spec ────────────────
|
|
848
|
+
// XS button (28) → icon 16 · SM (32) → 20 · MD (40)/LG (48)/XL (56) → 24
|
|
849
|
+
button[matcha-icon-button],
|
|
850
|
+
a[matcha-icon-button] {
|
|
851
|
+
aspect-ratio: 1;
|
|
852
|
+
|
|
853
|
+
matcha-icon {
|
|
854
|
+
flex: none; // NÃO expandir com o button
|
|
855
|
+
}
|
|
856
|
+
|
|
857
|
+
&[size="xs"] matcha-icon,
|
|
858
|
+
&[size="tiny"] matcha-icon {
|
|
859
|
+
font-size: 16px !important;
|
|
860
|
+
width: 16px !important;
|
|
861
|
+
height: 16px !important;
|
|
862
|
+
line-height: 16px !important;
|
|
863
|
+
}
|
|
864
|
+
&[size="sm"] matcha-icon,
|
|
865
|
+
&[size="small"] matcha-icon {
|
|
866
|
+
font-size: 20px !important;
|
|
867
|
+
width: 20px !important;
|
|
868
|
+
height: 20px !important;
|
|
869
|
+
line-height: 20px !important;
|
|
870
|
+
}
|
|
871
|
+
&[size="md"] matcha-icon,
|
|
872
|
+
&[size="medium"] matcha-icon,
|
|
873
|
+
&[size="lg"] matcha-icon,
|
|
874
|
+
&[size="large"] matcha-icon,
|
|
875
|
+
&[size="xl"] matcha-icon,
|
|
876
|
+
&[size="huge"] matcha-icon {
|
|
877
|
+
font-size: 24px !important;
|
|
878
|
+
width: 24px !important;
|
|
879
|
+
height: 24px !important;
|
|
880
|
+
line-height: 24px !important;
|
|
881
|
+
}
|
|
882
|
+
|
|
883
|
+
// Tamanho (height) e padding por size já vêm corretos do mixin compartilhado
|
|
884
|
+
// (generate-matcha-button-size-classes, aplicado via o seletor combinado no
|
|
885
|
+
// topo do arquivo) + do bloco &[icon] acima — ambos pareiam cada abreviação
|
|
886
|
+
// com seu extenso correto (sm↔small, md↔medium, lg↔large, xl↔huge). Este
|
|
887
|
+
// componente não precisa reafirmar nada aqui.
|
|
888
|
+
}
|
|
889
|
+
|
|
890
|
+
// ── matcha-button COM TEXTO: auto-size do matcha-icon projetado ──────────────
|
|
891
|
+
// O icon-button (acima) e o matcha-button[icon] (icon-only, no bloco &[icon]) já escalavam o
|
|
892
|
+
// ícone; o botão com texto não escalava nada, então o matcha-icon caía no próprio default
|
|
893
|
+
// (--matcha-icon-size-md, 24px) — proporcional só de MD (40px) pra cima. Num tiny (28px, texto
|
|
894
|
+
// 11/14) sobrava um ícone de 24px.
|
|
895
|
+
//
|
|
896
|
+
// Escala igual à do icon-button: XS/tiny → 16 · SM/small → 20 · MD+ → 24 (o default do
|
|
897
|
+
// matcha-icon já é 24, então MD/LG/XL não precisam de regra).
|
|
898
|
+
//
|
|
899
|
+
// Duas diferenças deliberadas em relação ao icon-button:
|
|
900
|
+
// 1. `matcha-icon:not([size])` — aqui o ícone divide o botão com o texto, e um `size`
|
|
901
|
+
// explícito do consumidor é escolha legítima que deve continuar valendo. O auto-size só
|
|
902
|
+
// age quando ninguém decidiu.
|
|
903
|
+
// 2. sem `!important`, consequência do item 1: como a regra nem casa quando há `size`, não há
|
|
904
|
+
// disputa de especificidade contra a classe `.i-size-*` que o componente emite.
|
|
905
|
+
//
|
|
906
|
+
// `:not([icon])` e `:not([matcha-icon-button])` preservam os dois casos que já tinham
|
|
907
|
+
// tratamento próprio. O bloco icon-only usa `[icon]:not([icon="false"])`, então em teoria
|
|
908
|
+
// `icon="false"` é botão com texto e deveria entrar aqui; não há um único uso dessa forma no
|
|
909
|
+
// showcase nem no painel, e um seletor extra só para ela seria ruído.
|
|
910
|
+
button[matcha-button]:not([matcha-icon-button]):not([icon]),
|
|
911
|
+
a[matcha-button]:not([matcha-icon-button]):not([icon]) {
|
|
912
|
+
&[size="xs"] matcha-icon:not([size]),
|
|
913
|
+
&[size="tiny"] matcha-icon:not([size]) {
|
|
914
|
+
font-size: var(--matcha-icon-size-sm, 16px);
|
|
915
|
+
width: var(--matcha-icon-size-sm, 16px);
|
|
916
|
+
height: var(--matcha-icon-size-sm, 16px);
|
|
917
|
+
line-height: var(--matcha-icon-size-sm, 16px);
|
|
918
|
+
}
|
|
919
|
+
|
|
920
|
+
// 20px não tem token (a escala de ícone vai 16/24/32) — mesmo literal que o icon-button usa.
|
|
921
|
+
&[size="sm"] matcha-icon:not([size]),
|
|
922
|
+
&[size="small"] matcha-icon:not([size]) {
|
|
923
|
+
font-size: 20px;
|
|
924
|
+
width: 20px;
|
|
925
|
+
height: 20px;
|
|
926
|
+
line-height: 20px;
|
|
927
|
+
}
|
|
928
|
+
}
|
|
929
|
+
|
|
930
|
+
// ── Forced colors (Windows High Contrast) ──
|
|
931
|
+
// Buttons precisam ser claramente acionáveis em high-contrast.
|
|
932
|
+
@media (forced-colors: active) {
|
|
933
|
+
button[matcha-button],
|
|
934
|
+
a[matcha-button],
|
|
935
|
+
button[matcha-icon-button],
|
|
936
|
+
a[matcha-icon-button] {
|
|
937
|
+
// Filled: usa botão de sistema (ButtonFace/ButtonText) — afford clicável.
|
|
938
|
+
background: ButtonFace !important;
|
|
939
|
+
color: ButtonText !important;
|
|
940
|
+
border: 1px solid ButtonText !important;
|
|
941
|
+
box-shadow: none !important;
|
|
942
|
+
|
|
943
|
+
// Outline/ghost/alpha/link — bg transparente, border CanvasText.
|
|
944
|
+
&[outline], &[basic], &[alpha], &[link] {
|
|
945
|
+
background: transparent !important;
|
|
946
|
+
border-color: CanvasText !important;
|
|
947
|
+
color: CanvasText !important;
|
|
948
|
+
}
|
|
949
|
+
|
|
950
|
+
// Disabled — GrayText system token.
|
|
951
|
+
&[disabled],
|
|
952
|
+
&.is-disabled {
|
|
953
|
+
color: GrayText !important;
|
|
954
|
+
border-color: GrayText !important;
|
|
955
|
+
}
|
|
956
|
+
|
|
957
|
+
&:focus-visible {
|
|
958
|
+
outline: 2px solid CanvasText !important;
|
|
959
|
+
outline-offset: 2px;
|
|
960
|
+
}
|
|
961
|
+
}
|
|
962
|
+
}
|
|
963
|
+
|
|
964
|
+
// ── Print ──
|
|
965
|
+
// Buttons hide (interativos, não fazem sentido em papel).
|
|
966
|
+
@media print {
|
|
967
|
+
button[matcha-button],
|
|
968
|
+
a[matcha-button],
|
|
969
|
+
button[matcha-icon-button],
|
|
970
|
+
a[matcha-icon-button] {
|
|
971
|
+
display: none !important;
|
|
972
|
+
}
|
|
973
|
+
}
|