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