@inchurch/matcha-theme 20.0.8 → 20.276.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.
Files changed (99) hide show
  1. package/abstracts/_colors.scss +404 -404
  2. package/abstracts/_elevation.scss +102 -102
  3. package/abstracts/_functions.scss +1212 -1212
  4. package/abstracts/_media-breakpoint.scss +23 -23
  5. package/abstracts/_typography.scss +127 -127
  6. package/base/_reset.scss +438 -438
  7. package/components/app-page-header.scss +260 -0
  8. package/components/matcha-accordion.scss +294 -157
  9. package/components/matcha-avatar.scss +171 -31
  10. package/components/matcha-badge.scss +4 -4
  11. package/components/matcha-breadcrumb.scss +232 -126
  12. package/components/matcha-button-toggle.scss +44 -0
  13. package/components/matcha-buttons.scss +908 -784
  14. package/components/matcha-calendar.scss +70 -2
  15. package/components/matcha-cards.scss +28 -2
  16. package/components/matcha-checkbox.scss +191 -490
  17. package/components/matcha-chip.scss +297 -212
  18. package/components/matcha-command-palette.scss +291 -63
  19. package/components/matcha-crop.scss +407 -172
  20. package/components/matcha-date.scss +81 -81
  21. package/components/matcha-divider.scss +86 -31
  22. package/components/matcha-drawer.scss +201 -50
  23. package/components/matcha-drop-image.scss +14 -0
  24. package/components/matcha-drop-list.scss +42 -1
  25. package/components/matcha-empty-state.scss +195 -83
  26. package/components/matcha-flag.scss +93 -52
  27. package/components/matcha-footer.scss +68 -164
  28. package/components/matcha-form-field.scss +52 -0
  29. package/components/matcha-form-section.scss +101 -101
  30. package/components/matcha-header.scss +135 -325
  31. package/components/matcha-highlight.scss +65 -197
  32. package/components/matcha-hint-text.scss +21 -0
  33. package/components/matcha-horizontal-tree.scss +317 -317
  34. package/components/matcha-icon.scss +17 -25
  35. package/components/matcha-list.scss +5 -5
  36. package/components/matcha-menu.scss +13 -0
  37. package/components/matcha-modal.scss +58 -84
  38. package/components/matcha-nav.scss +361 -230
  39. package/components/matcha-notification.scss +413 -197
  40. package/components/matcha-option.scss +79 -23
  41. package/components/matcha-paginator.scss +689 -235
  42. package/components/matcha-panel.scss +42 -26
  43. package/components/matcha-profile-card.scss +50 -50
  44. package/components/matcha-progress-bar.scss +257 -153
  45. package/components/matcha-radio.scss +244 -452
  46. package/components/matcha-scrollbox-shadow.scss +122 -122
  47. package/components/matcha-select.scss +3 -3
  48. package/components/matcha-skeleton.scss +18 -0
  49. package/components/matcha-slide-toggle.scss +47 -2
  50. package/components/matcha-slider.scss +172 -75
  51. package/components/matcha-snack-bar.scss +114 -121
  52. package/components/matcha-spinner.scss +76 -57
  53. package/components/matcha-status-pill.scss +82 -0
  54. package/components/matcha-stepper.scss +377 -177
  55. package/components/matcha-table.scss +569 -785
  56. package/components/matcha-tabs.scss +624 -469
  57. package/components/matcha-text-editor.scss +98 -144
  58. package/components/matcha-toolbar.scss +359 -206
  59. package/components/matcha-tooltip.scss +156 -62
  60. package/components/matcha-tree-view.scss +189 -0
  61. package/components/matcha-uploader.scss +240 -62
  62. package/fonts/manrope/manrope-latin-ext.woff2 +0 -0
  63. package/fonts/manrope/manrope-latin.woff2 +0 -0
  64. package/layout/matcha-page-layout.scss +776 -0
  65. package/main.scss +232 -261
  66. package/package.json +1 -1
  67. package/tokens/_animations-tokens.scss +37 -37
  68. package/tokens/_breakpoints-tokens.scss +35 -26
  69. package/tokens/_color-tokens.scss +1152 -1152
  70. package/tokens/_css-custom-properties.scss +650 -568
  71. package/tokens/_spacing-tokens.scss +94 -94
  72. package/vendors/angular-editor.scss +56 -56
  73. package/vendors/angular-material-fixes.scss +297 -297
  74. package/vendors/charts.scss +92 -92
  75. package/vendors/ng5-slider.scss +56 -56
  76. package/vendors/ngx-material-timepicker.scss +50 -50
  77. package/fonts/CircularStd-Black.eot +0 -0
  78. package/fonts/CircularStd-Black.svg +0 -3426
  79. package/fonts/CircularStd-Black.ttf +0 -0
  80. package/fonts/CircularStd-Black.woff +0 -0
  81. package/fonts/CircularStd-Black.woff2 +0 -0
  82. package/fonts/CircularStd-Bold.eot +0 -0
  83. package/fonts/CircularStd-Bold.otf +0 -0
  84. package/fonts/CircularStd-Bold.svg +0 -13532
  85. package/fonts/CircularStd-Bold.ttf +0 -0
  86. package/fonts/CircularStd-Bold.woff +0 -0
  87. package/fonts/CircularStd-Bold.woff2 +0 -0
  88. package/fonts/CircularStd-Medium.eot +0 -0
  89. package/fonts/CircularStd-Medium.otf +0 -0
  90. package/fonts/CircularStd-Medium.svg +0 -13511
  91. package/fonts/CircularStd-Medium.ttf +0 -0
  92. package/fonts/CircularStd-Medium.woff +0 -0
  93. package/fonts/CircularStd-Medium.woff2 +0 -0
  94. package/fonts/CircularStd-Regular.eot +0 -0
  95. package/fonts/CircularStd-Regular.otf +0 -0
  96. package/fonts/CircularStd-Regular.svg +0 -2378
  97. package/fonts/CircularStd-Regular.ttf +0 -0
  98. package/fonts/CircularStd-Regular.woff +0 -0
  99. package/fonts/CircularStd-Regular.woff2 +0 -0
@@ -1,528 +1,320 @@
1
1
  // =============================================================================
2
- // matcha-radio.scss — Migração Fase 3.1
2
+ // matcha-radio.scss — Figma DSV3 matcha/radio (14354:184)
3
3
  //
4
- // Mudanças em relação ao original:
5
- // [3.1-A] State layer em .matcha-radio-container (replaced element: input não suporta ::before)
6
- // Pattern: color: getXxx($theme) no container currentColor funciona no ::before
7
- // [3.1-B] .matcha-radio-container:hover background-color removido (substituído por state layer)
8
- // [3.1-C] Ripple de paleta: // ok: ripple palette. Semântico (accent/primary/…): CSS var com fallback
9
- // Semantic colors (primary/accent/success/warn/danger/info): usa CSS vars com fallback
10
- // [3.1-D] :focus removido (vazio); :focus-visible adicionado dentro do mixin ($theme disponível)
11
- // [3.1-E] Disabled: opacity:0.6 + cursor:not-allowed removidos; tokens semânticos usados
12
- // [3.1-F] transition: all → transition: border-color específico
13
- // [3.1-G] @media (prefers-reduced-motion: reduce) adicionado
14
- // [3.1-H] :not([disabled]) guards via seletor de contexto do pai
4
+ // Estrutura visual (1:1 com Figma):
5
+ // .matcha-radio-wrapper (label) flex row + gap 8px
6
+ // .matcha-radio-touch (span) 36×36 pillshape, state-layer, hover bg
7
+ // .matcha-radio-input (input radio) 18×18 native, dot 8×8 ::after
8
+ // .matcha-radio-text (span) coluna label + desc + hint
9
+ //
10
+ // Color system: accent (default) + 6 semânticas (primary/success/warn/danger/info).
11
+ // Paleta legacy Material 1 (red/pink/purple/blue/...) REMOVIDA DSV3 não suporta.
15
12
  // =============================================================================
16
13
 
17
- @mixin matcha-radio($theme) {
18
- matcha-radio {
19
-
20
- // ── Sem cor: usa accent ────────────────────────────────────────────
21
- &:not([color]) {
22
- // [3.1-A] color no container → currentColor para o state layer
23
- .matcha-radio-container {
24
- color: var(--matcha-color-accent, #{getAccent($theme)});
25
- }
26
-
27
- input[type="radio"] {
28
- border-color: var(--matcha-color-text-label, #{getBlueGrey($theme)});
29
-
30
- &:active {
31
- border-color: var(--matcha-color-accent, #{getAccent($theme)});
32
- }
33
-
34
- &:checked {
35
- border-color: var(--matcha-color-accent, #{getAccent($theme)});
36
-
37
- &::after {
38
- background-color: var(--matcha-color-accent, #{getAccent($theme)});
39
- }
40
- }
41
- }
42
-
43
- // [3.1-C] ripple — accent é semântico, usa CSS var com fallback
44
- .matcha-radio-container .ripple {
45
- background: var(--matcha-color-accent-contrast-alpha, #{getAccentContrastAlpha($theme)}) !important;
46
- }
47
- }
48
-
49
- // ── Com cor customizada ────────────────────────────────────────────
50
- &[color] {
51
- input[type="radio"] {
52
- border-color: var(--matcha-color-text-label, #{getBlueGrey($theme)});
53
- }
54
- }
55
-
56
- // ── Paleta: red ────────────────────────────────────────────────────
57
- &[color="red"] {
58
- .matcha-radio-container { color: getRed($theme); } // [3.1-A]
59
-
60
- input[type="radio"]:active { border-color: getRed($theme); }
61
- input[type="radio"]:checked { border-color: getRed($theme); }
62
- input[type="radio"]:checked::after { background-color: getRed($theme); }
63
-
64
- .matcha-radio-container .ripple {
65
- background: rgba(getRedContrast($theme), 0.1) !important; // ok: ripple palette
66
- }
67
- }
68
-
69
- // ── Paleta: pink ───────────────────────────────────────────────────
70
- &[color="pink"] {
71
- .matcha-radio-container { color: getPink($theme); } // [3.1-A]
72
-
73
- input[type="radio"]:active { border-color: getPink($theme); }
74
- input[type="radio"]:checked { border-color: getPink($theme); }
75
- input[type="radio"]:checked::after { background-color: getPink($theme); }
76
-
77
- .matcha-radio-container .ripple {
78
- background: rgba(getPinkContrast($theme), 0.1) !important; // ok: ripple palette
79
- }
80
- }
81
-
82
- // ── Paleta: purple ─────────────────────────────────────────────────
83
- &[color="purple"] {
84
- .matcha-radio-container { color: getPurple($theme); } // [3.1-A]
85
-
86
- input[type="radio"]:active { border-color: getPurple($theme); }
87
- input[type="radio"]:checked { border-color: getPurple($theme); }
88
- input[type="radio"]:checked::after { background-color: getPurple($theme); }
89
-
90
- .matcha-radio-container .ripple {
91
- background: rgba(getPurpleContrast($theme), 0.1) !important; // ok: ripple palette
92
- }
93
- }
94
-
95
- // ── Paleta: deep-purple ────────────────────────────────────────────
96
- &[color="deep-purple"] {
97
- .matcha-radio-container { color: getDeepPurple($theme); } // [3.1-A]
98
-
99
- input[type="radio"]:active { border-color: getDeepPurple($theme); }
100
- input[type="radio"]:checked { border-color: getDeepPurple($theme); }
101
- input[type="radio"]:checked::after { background-color: getDeepPurple($theme); }
102
-
103
- .matcha-radio-container .ripple {
104
- background: rgba(getDeepPurpleContrast($theme), 0.1) !important; // ok: ripple palette
105
- }
106
- }
107
-
108
- // ── Paleta: indigo ─────────────────────────────────────────────────
109
- &[color="indigo"] {
110
- .matcha-radio-container { color: getIndigo($theme); } // [3.1-A]
111
-
112
- input[type="radio"]:active { border-color: getIndigo($theme); }
113
- input[type="radio"]:checked { border-color: getIndigo($theme); }
114
- input[type="radio"]:checked::after { background-color: getIndigo($theme); }
115
-
116
- .matcha-radio-container .ripple {
117
- background: rgba(getIndigoContrast($theme), 0.1) !important; // ok: ripple palette
118
- }
119
- }
120
-
121
- // ── Paleta: blue ───────────────────────────────────────────────────
122
- &[color="blue"] {
123
- .matcha-radio-container { color: getBlue($theme); } // [3.1-A]
124
-
125
- input[type="radio"]:active { border-color: getBlue($theme); }
126
- input[type="radio"]:checked { border-color: getBlue($theme); }
127
- input[type="radio"]:checked::after { background-color: getBlue($theme); }
128
-
129
- .matcha-radio-container .ripple {
130
- background: rgba(getBlueContrast($theme), 0.1) !important; // ok: ripple palette
131
- }
132
- }
133
-
134
- // ── Paleta: light-blue ─────────────────────────────────────────────
135
- &[color="light-blue"] {
136
- .matcha-radio-container { color: getLightBlue($theme); } // [3.1-A]
137
-
138
- input[type="radio"]:active { border-color: getLightBlue($theme); }
139
- input[type="radio"]:checked { border-color: getLightBlue($theme); }
140
- input[type="radio"]:checked::after { background-color: getLightBlue($theme); }
141
-
142
- .matcha-radio-container .ripple {
143
- background: rgba(getLightBlueContrast($theme), 0.1) !important; // ok: ripple palette
144
- }
145
- }
146
-
147
- // ── Paleta: cyan ───────────────────────────────────────────────────
148
- &[color="cyan"] {
149
- .matcha-radio-container { color: getCyan($theme); } // [3.1-A]
150
-
151
- input[type="radio"]:active { border-color: getCyan($theme); }
152
- input[type="radio"]:checked { border-color: getCyan($theme); }
153
- input[type="radio"]:checked::after { background-color: getCyan($theme); }
154
-
155
- .matcha-radio-container .ripple {
156
- background: rgba(getCyanContrast($theme), 0.1) !important; // ok: ripple palette
157
- }
158
- }
159
-
160
- // ── Paleta: teal ───────────────────────────────────────────────────
161
- &[color="teal"] {
162
- .matcha-radio-container { color: getTeal($theme); } // [3.1-A]
163
-
164
- input[type="radio"]:active { border-color: getTeal($theme); }
165
- input[type="radio"]:checked { border-color: getTeal($theme); }
166
- input[type="radio"]:checked::after { background-color: getTeal($theme); }
167
-
168
- .matcha-radio-container .ripple {
169
- background: rgba(getTealContrast($theme), 0.1) !important; // ok: ripple palette
170
- }
171
- }
172
-
173
- // ── Paleta: green ──────────────────────────────────────────────────
174
- &[color="green"] {
175
- .matcha-radio-container { color: getGreen($theme); } // [3.1-A]
176
-
177
- input[type="radio"]:active { border-color: getGreen($theme); }
178
- input[type="radio"]:checked { border-color: getGreen($theme); }
179
- input[type="radio"]:checked::after { background-color: getGreen($theme); }
180
-
181
- .matcha-radio-container .ripple {
182
- background: rgba(getGreenContrast($theme), 0.1) !important; // ok: ripple palette
183
- }
184
- }
185
-
186
- // ── Paleta: light-green ────────────────────────────────────────────
187
- &[color="light-green"] {
188
- .matcha-radio-container { color: getLightGreen($theme); } // [3.1-A]
189
-
190
- input[type="radio"]:active { border-color: getLightGreen($theme); }
191
- input[type="radio"]:checked { border-color: getLightGreen($theme); }
192
- input[type="radio"]:checked::after { background-color: getLightGreen($theme); }
193
-
194
- .matcha-radio-container .ripple {
195
- background: rgba(getLightGreenContrast($theme), 0.1) !important; // ok: ripple palette
196
- }
197
- }
198
-
199
- // ── Paleta: lime ───────────────────────────────────────────────────
200
- &[color="lime"] {
201
- .matcha-radio-container { color: getLime($theme); } // [3.1-A]
202
-
203
- input[type="radio"]:active { border-color: getLime($theme); }
204
- input[type="radio"]:checked { border-color: getLime($theme); }
205
- input[type="radio"]:checked::after { background-color: getLime($theme); }
14
+ // ── Estrutural ─────────────────────────────────────────────────────────────
206
15
 
207
- .matcha-radio-container .ripple {
208
- background: rgba(getLimeContrast($theme), 0.1) !important; // ok: ripple palette
209
- }
210
- }
211
-
212
- // ── Paleta: yellow ─────────────────────────────────────────────────
213
- &[color="yellow"] {
214
- .matcha-radio-container { color: getYellow($theme); } // [3.1-A]
215
-
216
- input[type="radio"]:active { border-color: getYellow($theme); }
217
- input[type="radio"]:checked { border-color: getYellow($theme); }
218
- input[type="radio"]:checked::after { background-color: getYellow($theme); }
16
+ matcha-radio {
17
+ display: inline-flex;
18
+ align-items: center;
19
+ gap: var(--matcha-space-100, 8px);
20
+ cursor: pointer;
21
+ font-family: var(--matcha-font-family);
219
22
 
220
- .matcha-radio-container .ripple {
221
- background: rgba(getYellowContrast($theme), 0.1) !important; // ok: ripple palette
222
- }
223
- }
23
+ // Disabled — pointer/cursor only (cores via tokens semânticos no mixin)
24
+ &[disabled] {
25
+ pointer-events: none;
26
+ cursor: default;
224
27
 
225
- // ── Paleta: amber ──────────────────────────────────────────────────
226
- &[color="amber"] {
227
- .matcha-radio-container { color: getAmber($theme); } // [3.1-A]
28
+ .matcha-radio-wrapper { cursor: default; }
29
+ }
228
30
 
229
- input[type="radio"]:active { border-color: getAmber($theme); }
230
- input[type="radio"]:checked { border-color: getAmber($theme); }
231
- input[type="radio"]:checked::after { background-color: getAmber($theme); }
31
+ // Movimento reduzido (WCAG 2.3.3)
32
+ @media (prefers-reduced-motion: reduce) {
33
+ .matcha-radio-input,
34
+ .matcha-radio-touch::before { transition: none; }
35
+ }
36
+ }
232
37
 
233
- .matcha-radio-container .ripple {
234
- background: rgba(getAmberContrast($theme), 0.1) !important; // ok: ripple palette
235
- }
236
- }
38
+ .matcha-radio-wrapper {
39
+ display: inline-flex;
40
+ align-items: center;
41
+ gap: var(--matcha-space-100, 8px);
42
+ cursor: pointer;
43
+ user-select: none;
44
+ }
237
45
 
238
- // ── Paleta: orange ─────────────────────────────────────────────────
239
- &[color="orange"] {
240
- .matcha-radio-container { color: getOrange($theme); } // [3.1-A]
46
+ // Quando há descrição/hint (multi-linha), volta pra align-items: flex-start
47
+ // pra evitar que o glyph fique no meio do bloco texto.
48
+ matcha-radio:has(.matcha-radio-description),
49
+ matcha-radio:has(.matcha-radio-hint) {
50
+ .matcha-radio-wrapper { align-items: flex-start; }
51
+ }
241
52
 
242
- input[type="radio"]:active { border-color: getOrange($theme); }
243
- input[type="radio"]:checked { border-color: getOrange($theme); }
244
- input[type="radio"]:checked::after { background-color: getOrange($theme); }
53
+ // ── Touch target — 36×36 pillshape (Figma DSV3) ─────────────────────────────
54
+ // Container circular grande pra área clicável extendida (WCAG 2.5.5).
55
+ // Glyph visual continua 18×18 dentro, mas hover/click cobre 36×36.
56
+ .matcha-radio-touch {
57
+ position: relative;
58
+ display: inline-flex;
59
+ align-items: center;
60
+ justify-content: center;
61
+ width: var(--matcha-radio-touch-size, 36px);
62
+ height: var(--matcha-radio-touch-size, 36px);
63
+ flex-shrink: 0;
64
+ border-radius: var(--matcha-radius-pill, 9999px);
65
+ overflow: hidden;
66
+
67
+ // State layer — segue padrão DSV3 (currentColor + opacity tokenizada).
68
+ // currentColor herda do .matcha-radio-touch que recebe color por variante (mixin).
69
+ &::before {
70
+ content: '';
71
+ position: absolute;
72
+ inset: 0;
73
+ background: currentColor;
74
+ opacity: 0;
75
+ border-radius: inherit;
76
+ pointer-events: none;
77
+ transition: opacity var(--matcha-duration-instant, 80ms) linear;
78
+ }
79
+ }
245
80
 
246
- .matcha-radio-container .ripple {
247
- background: rgba(getOrangeContrast($theme), 0.1) !important; // ok: ripple palette
248
- }
249
- }
81
+ // Hover/active state-layer só quando NÃO disabled
82
+ matcha-radio:not([disabled]) .matcha-radio-touch:hover::before { opacity: var(--matcha-state-hover, 0.08); }
83
+ matcha-radio:not([disabled]) .matcha-radio-touch:active::before { opacity: var(--matcha-state-active, 0.12); }
84
+
85
+ // ── Input radio nativo — vector 18×18 ────────────────────────────────────
86
+ .matcha-radio-input {
87
+ appearance: none;
88
+ -webkit-appearance: none;
89
+ width: var(--matcha-radio-size, 18px);
90
+ height: var(--matcha-radio-size, 18px);
91
+ padding: 0;
92
+ margin: 0;
93
+ border-width: 2px;
94
+ border-style: solid;
95
+ border-radius: 50%;
96
+ cursor: pointer;
97
+ position: relative;
98
+ box-sizing: border-box;
99
+ transition: border-color var(--matcha-duration-fast, 200ms) var(--matcha-easing-standard, ease);
100
+
101
+ // Dot interno (checked) — 8×8 centralizado via inset
102
+ &:checked::after {
103
+ content: '';
104
+ position: absolute;
105
+ inset: 3px;
106
+ border-radius: 50%;
107
+ }
108
+ }
250
109
 
251
- // ── Paleta: deep-orange ────────────────────────────────────────────
252
- &[color="deep-orange"] {
253
- .matcha-radio-container { color: getDeepOrange($theme); } // [3.1-A]
110
+ // ── Coluna texto (label + description + hint) ────────────────────────────
111
+ .matcha-radio-text {
112
+ display: flex;
113
+ flex-direction: column;
114
+ gap: var(--matcha-space-025, 2px);
115
+ min-width: 0;
116
+ }
254
117
 
255
- input[type="radio"]:active { border-color: getDeepOrange($theme); }
256
- input[type="radio"]:checked { border-color: getDeepOrange($theme); }
257
- input[type="radio"]:checked::after { background-color: getDeepOrange($theme); }
118
+ // Em multi-linha (com desc/hint), aplica padding-top no text pra alinhar
119
+ // o label com o centro vertical do glyph (touch 36px, glyph centro em 18px;
120
+ // label-sm height 16px → padding-top 10px alinha label-center com glyph-center).
121
+ matcha-radio:has(.matcha-radio-description) .matcha-radio-text,
122
+ matcha-radio:has(.matcha-radio-hint) .matcha-radio-text {
123
+ padding-top: var(--matcha-space-150, 10px);
124
+ }
258
125
 
259
- .matcha-radio-container .ripple {
260
- background: rgba(getDeepOrangeContrast($theme), 0.1) !important; // ok: ripple palette
261
- }
262
- }
126
+ // Label — Figma matcha/text/label-sm (12/500/16) — não body-sm que é regular
127
+ .matcha-radio-label {
128
+ display: inline-flex;
129
+ align-items: center;
130
+ gap: var(--matcha-space-050, 4px);
131
+ font-family: var(--matcha-font-family);
132
+ font-size: var(--matcha-text-label-sm, 12px);
133
+ font-weight: var(--matcha-weight-medium, 500);
134
+ line-height: var(--matcha-leading-label-sm, 16px);
135
+ color: var(--matcha-radio-label-color, var(--matcha-color-text-primary));
136
+ cursor: pointer;
137
+ user-select: none;
138
+ }
263
139
 
264
- // ── Paleta: brown ──────────────────────────────────────────────────
265
- &[color="brown"] {
266
- .matcha-radio-container { color: getBrown($theme); } // [3.1-A]
140
+ // Asterisco required danger
141
+ .matcha-radio-required {
142
+ color: var(--matcha-color-danger);
143
+ font-weight: var(--matcha-weight-medium, 500);
144
+ }
267
145
 
268
- input[type="radio"]:active { border-color: getBrown($theme); }
269
- input[type="radio"]:checked { border-color: getBrown($theme); }
270
- input[type="radio"]:checked::after { background-color: getBrown($theme); }
146
+ // Description — caption 11/14 letter-spacing 0.3 (Figma DSV3)
147
+ .matcha-radio-description {
148
+ font-family: var(--matcha-font-family);
149
+ font-size: var(--matcha-text-p-tiny, 11px);
150
+ line-height: var(--matcha-leading-p-tiny, 14px);
151
+ letter-spacing: 0.3px;
152
+ color: var(--matcha-color-text-secondary);
153
+ }
271
154
 
272
- .matcha-radio-container .ripple {
273
- background: rgba(getBrownContrast($theme), 0.1) !important; // ok: ripple palette
274
- }
275
- }
155
+ // Hint (só em error) — danger
156
+ .matcha-radio-hint {
157
+ font-family: var(--matcha-font-family);
158
+ font-size: var(--matcha-text-p-tiny, 11px);
159
+ line-height: var(--matcha-leading-p-tiny, 14px);
160
+ letter-spacing: 0.3px;
161
+ color: var(--matcha-color-danger);
162
+ }
276
163
 
277
- // ── Paleta: grey ───────────────────────────────────────────────────
278
- &[color="grey"] {
279
- .matcha-radio-container { color: getGrey($theme); } // [3.1-A]
164
+ // =============================================================================
165
+ // Theme mixin — cores por variante (accent default + 6 semânticas DSV3)
166
+ // Paleta Material 1 (red/pink/purple/...) REMOVIDA não faz parte do DSV3.
167
+ // =============================================================================
280
168
 
281
- input[type="radio"]:active { border-color: getGrey($theme); }
282
- input[type="radio"]:checked { border-color: getGrey($theme); }
283
- input[type="radio"]:checked::after { background-color: getGrey($theme); }
169
+ @mixin matcha-radio($theme) {
170
+ matcha-radio {
284
171
 
285
- .matcha-radio-container .ripple {
286
- background: rgba(getGreyContrast($theme), 0.1) !important; // ok: ripple palette
172
+ // ── Default (sem [color]) e [color="accent"] = accent ─────────────────
173
+ &:not([color]),
174
+ &[color="accent"] {
175
+ .matcha-radio-touch {
176
+ color: var(--matcha-color-accent);
287
177
  }
288
- }
289
178
 
290
- // ── Paleta: blue-grey ──────────────────────────────────────────────
291
- &[color="blue-grey"] {
292
- .matcha-radio-container { color: getBlueGrey($theme); } // [3.1-A]
179
+ .matcha-radio-input {
180
+ border-color: var(--matcha-color-text-label, #{getBlueGrey($theme)});
293
181
 
294
- input[type="radio"]:active { border-color: getBlueGrey($theme); }
295
- input[type="radio"]:checked { border-color: getBlueGrey($theme); }
296
- input[type="radio"]:checked::after { background-color: getBlueGrey($theme); }
182
+ &:checked {
183
+ border-color: var(--matcha-color-accent);
297
184
 
298
- .matcha-radio-container .ripple {
299
- background: rgba(getBlueGreyContrast($theme), 0.1) !important; // ok: ripple palette
185
+ &::after {
186
+ background-color: var(--matcha-color-accent);
187
+ }
188
+ }
300
189
  }
301
190
  }
302
191
 
303
- // ── Semântica: primary ─────────────────────────────────────────────
192
+ // ── primary ────────────────────────────────────────────────────────
304
193
  &[color="primary"] {
305
- .matcha-radio-container { color: var(--matcha-color-primary, #{getPrimary($theme)}); } // [3.1-A]
306
-
307
- input[type="radio"]:active { border-color: var(--matcha-color-primary, #{getPrimary($theme)}); }
308
- input[type="radio"]:checked { border-color: var(--matcha-color-primary, #{getPrimary($theme)}); }
309
- input[type="radio"]:checked::after { background-color: var(--matcha-color-primary, #{getPrimary($theme)}); }
310
-
311
- // [3.1-C] semantic: CSS var com fallback SCSS
312
- .matcha-radio-container .ripple {
313
- background: var(--matcha-color-primary-contrast-alpha, #{getPrimaryContrastAlpha($theme)}) !important;
314
- }
315
- }
316
-
317
- // ── Semântica: accent ──────────────────────────────────────────────
318
- &[color="accent"] {
319
- .matcha-radio-container { color: var(--matcha-color-accent, #{getAccent($theme)}); } // [3.1-A]
320
-
321
- input[type="radio"]:active { border-color: var(--matcha-color-accent, #{getAccent($theme)}); }
322
- input[type="radio"]:checked { border-color: var(--matcha-color-accent, #{getAccent($theme)}); }
323
- input[type="radio"]:checked::after { background-color: var(--matcha-color-accent, #{getAccent($theme)}); }
324
-
325
- .matcha-radio-container .ripple {
326
- background: var(--matcha-color-accent-contrast-alpha, #{getAccentContrastAlpha($theme)}) !important;
194
+ .matcha-radio-touch { color: var(--matcha-color-primary); }
195
+ .matcha-radio-input {
196
+ border-color: var(--matcha-color-text-label, #{getBlueGrey($theme)});
197
+ &:checked {
198
+ border-color: var(--matcha-color-primary);
199
+ &::after { background-color: var(--matcha-color-primary); }
200
+ }
327
201
  }
328
202
  }
329
203
 
330
- // ── Semântica: success ─────────────────────────────────────────────
204
+ // ── success ────────────────────────────────────────────────────────
331
205
  &[color="success"] {
332
- .matcha-radio-container { color: getSuccess($theme); } // [3.1-A]
333
-
334
- input[type="radio"]:active { border-color: getSuccess($theme); }
335
- input[type="radio"]:checked { border-color: getSuccess($theme); }
336
- input[type="radio"]:checked::after { background-color: getSuccess($theme); }
337
-
338
- .matcha-radio-container .ripple {
339
- background: var(--matcha-color-success-contrast-alpha, #{getSuccessContrastAlpha($theme)}) !important;
206
+ .matcha-radio-touch { color: var(--matcha-color-success); }
207
+ .matcha-radio-input {
208
+ border-color: var(--matcha-color-text-label, #{getBlueGrey($theme)});
209
+ &:checked {
210
+ border-color: var(--matcha-color-success);
211
+ &::after { background-color: var(--matcha-color-success); }
212
+ }
340
213
  }
341
214
  }
342
215
 
343
- // ── Semântica: warn ────────────────────────────────────────────────
216
+ // ── warn ───────────────────────────────────────────────────────────
344
217
  &[color="warn"] {
345
- .matcha-radio-container { color: getWarn($theme); } // [3.1-A]
346
-
347
- input[type="radio"]:active { border-color: getWarn($theme); }
348
- input[type="radio"]:checked { border-color: getWarn($theme); }
349
- input[type="radio"]:checked::after { background-color: getWarn($theme); }
350
-
351
- .matcha-radio-container .ripple {
352
- background: var(--matcha-color-warn-contrast-alpha, #{getWarnContrastAlpha($theme)}) !important;
218
+ .matcha-radio-touch { color: var(--matcha-color-warn); }
219
+ .matcha-radio-input {
220
+ border-color: var(--matcha-color-text-label, #{getBlueGrey($theme)});
221
+ &:checked {
222
+ border-color: var(--matcha-color-warn);
223
+ &::after { background-color: var(--matcha-color-warn); }
224
+ }
353
225
  }
354
226
  }
355
227
 
356
- // ── Semântica: danger ──────────────────────────────────────────────
228
+ // ── danger ─────────────────────────────────────────────────────────
357
229
  &[color="danger"] {
358
- .matcha-radio-container { color: getDanger($theme); } // [3.1-A]
359
-
360
- input[type="radio"]:active { border-color: getDanger($theme); }
361
- input[type="radio"]:checked { border-color: getDanger($theme); }
362
- input[type="radio"]:checked::after { background-color: getDanger($theme); }
363
-
364
- .matcha-radio-container .ripple {
365
- background: var(--matcha-color-danger-contrast-alpha, #{getDangerContrastAlpha($theme)}) !important;
230
+ .matcha-radio-touch { color: var(--matcha-color-danger); }
231
+ .matcha-radio-input {
232
+ border-color: var(--matcha-color-text-label, #{getBlueGrey($theme)});
233
+ &:checked {
234
+ border-color: var(--matcha-color-danger);
235
+ &::after { background-color: var(--matcha-color-danger); }
236
+ }
366
237
  }
367
238
  }
368
239
 
369
- // ── Semântica: info ────────────────────────────────────────────────
240
+ // ── info ───────────────────────────────────────────────────────────
370
241
  &[color="info"] {
371
- .matcha-radio-container { color: getInfo($theme); } // [3.1-A]
372
-
373
- input[type="radio"]:active { border-color: getInfo($theme); }
374
- input[type="radio"]:checked { border-color: getInfo($theme); }
375
- input[type="radio"]:checked::after { background-color: getInfo($theme); }
376
-
377
- .matcha-radio-container .ripple {
378
- background: var(--matcha-color-info-contrast-alpha, #{getInfoContrastAlpha($theme)}) !important;
242
+ .matcha-radio-touch { color: var(--matcha-color-info); }
243
+ .matcha-radio-input {
244
+ border-color: var(--matcha-color-text-label, #{getBlueGrey($theme)});
245
+ &:checked {
246
+ border-color: var(--matcha-color-info);
247
+ &::after { background-color: var(--matcha-color-info); }
248
+ }
379
249
  }
380
250
  }
381
251
 
382
- // ── Error state (aligned with Figma State=Error) ──────────────────
252
+ // ── Error state (Figma DSV3 State=Error) — sobrescreve cor do glyph ──
383
253
  &.matcha-radio-error,
384
- &[error] {
385
- input[type="radio"] {
386
- border-color: var(--matcha-color-danger, #{getDanger($theme)});
387
-
388
- &:checked {
389
- border-color: var(--matcha-color-danger, #{getDanger($theme)});
254
+ &[error="true"] {
255
+ .matcha-radio-input {
256
+ border-color: var(--matcha-color-danger) !important;
390
257
 
391
- &::after {
392
- background-color: var(--matcha-color-danger, #{getDanger($theme)});
393
- }
258
+ &:checked::after {
259
+ background-color: var(--matcha-color-danger) !important;
394
260
  }
395
261
  }
396
262
  }
397
263
 
398
- // ── [3.1-D] Disabled tokens semânticos (sem opacity no host) ─────
264
+ // ── Disabled (Figma DSV3 opacity 0.5) ────────────────────────────────
399
265
  &[disabled] {
400
- input[type="radio"] {
401
- border-color: var(--matcha-color-disabled-bg, #{getDisabled($theme)});
402
- }
266
+ opacity: var(--matcha-opacity-option-disabled, 0.5);
403
267
 
404
- // Container recebe cor de disabled para que currentColor do state layer seja correto
405
- // (state layer já está bloqueado por pointer-events, mas garante visual consistente)
406
- .matcha-radio-container {
407
- color: var(--matcha-color-disabled-fg, #{getDisabledBgContrast($theme)});
268
+ .matcha-radio-input {
269
+ border-color: var(--matcha-color-interaction-disabled-fg);
408
270
  }
409
271
 
410
- .matcha-radio-label {
411
- color: var(--matcha-color-disabled-fg, #{getDisabledBgContrast($theme)});
272
+ .matcha-radio-label,
273
+ .matcha-radio-description,
274
+ .matcha-radio-hint {
275
+ color: var(--matcha-color-interaction-disabled-fg);
412
276
  }
413
277
  }
414
278
 
415
- // ── [3.1-D] :focus-visible DEVE ficar no mixin (precisa de #{getForeground($theme)}) ──
416
- // Aplica no container circular (o foco é visível ali, não no input oculto)
417
- .matcha-radio-container:focus-within {
418
- outline: var(--matcha-state-focus-ring-width, 2px) solid
419
- var(--matcha-color-primary, #{getPrimary($theme)});
420
- outline-offset: var(--matcha-state-focus-ring-offset, 2px);
279
+ // ── Focusedoutline 2px primary no touch (não desloca layout) ──────
280
+ .matcha-radio-input:focus-visible {
281
+ outline: none;
421
282
  }
422
-
423
- // Label padrão (preservado do original)
424
- .matcha-radio-label {
425
- color: getGrey($theme);
283
+ .matcha-radio-touch:has(.matcha-radio-input:focus-visible) {
284
+ outline: var(--matcha-state-focus-ring-width, 2px) solid var(--matcha-color-primary);
285
+ outline-offset: calc(-1 * var(--matcha-state-focus-ring-width, 2px));
426
286
  }
427
287
  }
428
288
  }
429
289
 
430
-
431
- // =============================================================================
432
- // Bloco estrutural — fora do mixin de tema
433
- // =============================================================================
434
-
435
- // [3.1-A] Container do radio recebe o state layer
436
- // input[type="radio"] é replaced element — ::before não renderiza nele
437
- // O container (.matcha-radio-container) é a área clicável circular
438
- .matcha-radio-container {
439
- position: relative;
440
- overflow: hidden;
441
- border-radius: 50%; // área de hover circular (Material Design radio pattern)
442
-
443
- // State layer — segue INTERACTION-SYSTEM.md template
444
- &::before {
445
- content: '';
446
- position: absolute;
447
- inset: 0;
448
- background: currentColor; // usa color: getXxx($theme) definido no mixin por variante
449
- opacity: 0;
450
- border-radius: inherit;
451
- pointer-events: none;
452
- transition: opacity var(--matcha-duration-instant, 80ms) linear;
453
- }
454
- }
455
-
456
- // [3.1-H] Hover/active: [disabled] está em matcha-radio (pai), não no container
457
- // Seletor de contexto do pai evita ativar o state layer quando desabilitado
458
- matcha-radio:not([disabled]) .matcha-radio-container:hover::before { opacity: var(--matcha-state-hover, 0.08); }
459
- matcha-radio:not([disabled]) .matcha-radio-container:active::before { opacity: var(--matcha-state-active, 0.12); }
460
-
461
- matcha-radio {
462
- display: inline-flex;
463
- align-items: center;
464
- gap: 8px;
465
- cursor: pointer;
466
-
467
- input[type="radio"] {
468
- appearance: none;
469
- -webkit-appearance: none;
470
- width: var(--matcha-radio-size, 18px);
471
- height: var(--matcha-radio-size, 18px);
472
- padding: 0;
473
- margin: 0;
474
- border-radius: 50%;
475
- border-width: 2px;
476
- border-style: solid;
477
- cursor: pointer;
478
- position: relative;
479
-
480
- // [3.1-F] transition específico (não 'all')
481
- transition: border-color 0.2s ease;
482
-
483
- // outline: none REMOVIDO — :focus-visible no mixin garante acessibilidade
484
- // &:focus {} REMOVIDO — estava vazio (WCAG 2.4.7)
485
-
486
- &:checked::after {
487
- content: '';
488
- position: absolute;
489
- left: 3px;
490
- top: 3px;
491
- width: 8px;
492
- height: 8px;
493
- border-radius: 50%;
290
+ // ── Forced colors ──
291
+ @media (forced-colors: active) {
292
+ matcha-radio {
293
+ .matcha-radio-circle {
294
+ border: 1px solid CanvasText !important;
295
+ background: Canvas !important;
494
296
  }
495
- }
496
-
497
- // Figma matcha/radio label: 12px Medium line 16 (weight 500, diferente do checkbox 400)
498
- .matcha-radio-label {
499
- font-size: var(--matcha-text-body-sm, 12px);
500
- font-weight: var(--matcha-weight-medium, 500);
501
- line-height: var(--matcha-leading-body-sm, 16px);
502
- user-select: none;
503
- cursor: pointer;
504
- }
505
297
 
506
- // [3.1-E] Disabled — sem opacity no host, sem cursor: not-allowed
507
- // pointer-events: none é suficiente para bloquear interação
508
- // Cores gerenciadas pelo mixin via tokens semânticos
509
- &[disabled] {
510
- pointer-events: none;
511
- cursor: default;
298
+ &.is-checked .matcha-radio-circle::after,
299
+ &[checked] .matcha-radio-circle::after {
300
+ background: Highlight !important;
301
+ }
512
302
 
513
- input[type="radio"] {
514
- // cursor: not-allowed REMOVIDO (pointer-events: none o torna ineficaz)
303
+ .matcha-radio-touch:has(.matcha-radio-input:focus-visible) {
304
+ outline: 2px solid CanvasText !important;
515
305
  }
516
306
 
517
- .matcha-radio-label {
518
- cursor: default;
307
+ &.is-disabled,
308
+ &[disabled] {
309
+ opacity: 0.5;
310
+ .matcha-radio-circle { border-color: GrayText !important; }
519
311
  }
520
312
  }
313
+ }
521
314
 
522
- // [3.1-G] Movimento reduzido — obrigatório (WCAG 2.3.3)
523
- @media (prefers-reduced-motion: reduce) {
524
- input[type="radio"] { transition: none; }
525
-
526
- .matcha-radio-container::before { transition: none; }
315
+ // ── Print ──
316
+ @media print {
317
+ matcha-radio .matcha-radio-circle {
318
+ border: 1px solid currentColor !important;
527
319
  }
528
320
  }