@inchurch/matcha-theme 22.40.1 → 22.40.2

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 (93) hide show
  1. package/abstracts/_colors.scss +291 -291
  2. package/abstracts/_elevation.scss +108 -108
  3. package/abstracts/_functions.scss +321 -321
  4. package/abstracts/_media-breakpoint.scss +26 -26
  5. package/abstracts/_theme-api.scss +224 -224
  6. package/abstracts/_typography.scss +128 -128
  7. package/base/_reset.scss +487 -487
  8. package/components/app-page-header.scss +260 -260
  9. package/components/matcha-accordion.scss +297 -297
  10. package/components/matcha-audio-player.scss +31 -31
  11. package/components/matcha-autocomplete.scss +145 -145
  12. package/components/matcha-avatar.scss +426 -426
  13. package/components/matcha-badge.scss +120 -120
  14. package/components/matcha-breadcrumb.scss +231 -231
  15. package/components/matcha-button-toggle.scss +484 -484
  16. package/components/matcha-buttons.scss +973 -973
  17. package/components/matcha-calendar.scss +253 -253
  18. package/components/matcha-cards.scss +212 -212
  19. package/components/matcha-chart-card.scss +53 -53
  20. package/components/matcha-checkbox.scss +266 -266
  21. package/components/matcha-chip.scss +311 -311
  22. package/components/matcha-color-pick.scss +34 -34
  23. package/components/matcha-command-palette.scss +316 -316
  24. package/components/matcha-crop.scss +419 -419
  25. package/components/matcha-date.scss +81 -81
  26. package/components/matcha-divider.scss +100 -100
  27. package/components/matcha-draggable.scss +23 -23
  28. package/components/matcha-drawer.scss +376 -376
  29. package/components/matcha-drop-image.scss +14 -14
  30. package/components/matcha-drop-list.scss +430 -430
  31. package/components/matcha-emoji.scss +69 -69
  32. package/components/matcha-empty-state.scss +230 -230
  33. package/components/matcha-file-uploader.scss +650 -650
  34. package/components/matcha-flag.scss +103 -103
  35. package/components/matcha-footer.scss +91 -91
  36. package/components/matcha-form-field.scss +883 -883
  37. package/components/matcha-form-section.scss +100 -100
  38. package/components/matcha-header.scss +135 -135
  39. package/components/matcha-highlight.scss +164 -164
  40. package/components/matcha-hint-text.scss +90 -90
  41. package/components/matcha-horizontal-tree.scss +247 -247
  42. package/components/matcha-icon.scss +111 -111
  43. package/components/matcha-image.scss +60 -60
  44. package/components/matcha-list.scss +211 -211
  45. package/components/matcha-menu.scss +99 -99
  46. package/components/matcha-modal.scss +210 -210
  47. package/components/matcha-nav.scss +770 -770
  48. package/components/matcha-notification.scss +417 -417
  49. package/components/matcha-option.scss +170 -170
  50. package/components/matcha-page-builder.scss +4196 -4196
  51. package/components/matcha-paginator.scss +699 -699
  52. package/components/matcha-panel.scss +216 -216
  53. package/components/matcha-period.scss +174 -174
  54. package/components/matcha-profile-card.scss +50 -50
  55. package/components/matcha-progress-bar.scss +355 -355
  56. package/components/matcha-radio.scss +325 -325
  57. package/components/matcha-ripple.scss +7 -7
  58. package/components/matcha-scrollbar.scss +33 -33
  59. package/components/matcha-scrollbox-shadow.scss +120 -120
  60. package/components/matcha-section.scss +102 -102
  61. package/components/matcha-select-multiple.scss +56 -56
  62. package/components/matcha-select.scss +643 -643
  63. package/components/matcha-skeleton.scss +182 -182
  64. package/components/matcha-slide-toggle.scss +369 -369
  65. package/components/matcha-slider.scss +285 -285
  66. package/components/matcha-snack-bar.scss +259 -259
  67. package/components/matcha-spin.scss +164 -164
  68. package/components/matcha-spinner.scss +97 -97
  69. package/components/matcha-stepper.scss +376 -376
  70. package/components/matcha-table-cell.scss +107 -107
  71. package/components/matcha-table.scss +722 -722
  72. package/components/matcha-tabs.scss +642 -642
  73. package/components/matcha-text-editor.scss +111 -111
  74. package/components/matcha-time.scss +33 -33
  75. package/components/matcha-timepicker.scss +13 -13
  76. package/components/matcha-toolbar.scss +366 -366
  77. package/components/matcha-tooltip.scss +235 -235
  78. package/components/matcha-tree-view.scss +658 -658
  79. package/layout/matcha-page-layout.scss +778 -778
  80. package/main.scss +334 -334
  81. package/package.json +1 -1
  82. package/tokens/_animations-tokens.scss +37 -37
  83. package/tokens/_breakpoints-tokens.scss +35 -35
  84. package/tokens/_color-tokens.scss +288 -288
  85. package/tokens/_elevation-tokens.scss +33 -33
  86. package/tokens/_emit-tokens.scss +329 -329
  87. package/tokens/_material-palette.scss +1149 -1149
  88. package/tokens/_primitives.scss +98 -98
  89. package/tokens/_semantic-aliases.scss +120 -120
  90. package/tokens/_spacing-tokens.scss +94 -94
  91. package/tokens/_static-tokens.scss +137 -137
  92. package/tokens/_typography-tokens.scss +65 -65
  93. package/vendors/charts.scss +90 -90
@@ -1,658 +1,658 @@
1
- // =============================================================================
2
- // matcha-tree-view.scss — árvore hierárquica do painel (Figma DSV3 matcha/tree-view)
3
- //
4
- // UMA anatomia de linha pra qualquer nó:
5
- // [grip 32 · disclosure 32 · identidade (dot|avatar + nome, linha secundária) · meta (cargo + contadores) · ações]
6
- // Nível NÃO é variante: é o recuo do bloco de filhos (32px) + uma guia vertical
7
- // alinhada ao centro da primeira coluna da linha do pai. O consumer compõe a
8
- // linha com as classes de slot abaixo; o componente não impõe conteúdo.
9
- // =============================================================================
10
-
11
- // ── Container ───────────────────────────────────────────────────────────────
12
- .matcha-tree-view {
13
- display: flex;
14
- flex-direction: column;
15
- // Sem tray e sem gap. A árvore vive na superfície da página: fundo próprio
16
- // + rows-card + respiro entre elas transformavam a hierarquia numa pilha de
17
- // chips, e o card opaco de cada row cobria a guia, que saía tracejada.
18
- gap: 0;
19
- padding: 0;
20
- background: transparent;
21
- border-radius: 0;
22
-
23
- container-type: inline-size;
24
- container-name: matcha-tree-view;
25
-
26
- .matcha-drop-list-container {
27
- display: flex;
28
- flex-direction: column;
29
- gap: 0;
30
- }
31
- }
32
-
33
- matcha-tree-branch,
34
- .matcha-tree-view__children {
35
- display: flex;
36
- flex-direction: column;
37
- gap: 0;
38
- }
39
-
40
- // ── Recuo (bloco de filhos) ────────────────────────────────────────────────
41
- // O recuo é do BLOCO, não de cada linha: o item dentro do container não recua
42
- // sozinho, e a guia vira UM traço por nível, contínuo por estrutura.
43
- .matcha-tree-view__children {
44
- position: relative;
45
- // Motion do Figma: filhos entram em 200ms, desacelerando.
46
- animation: matcha-tree-view-children-in var(--matcha-duration-fast, 200ms) var(--matcha-easing-decelerated, ease-out) both;
47
-
48
- // O padding mora no BRANCH, não no bloco: a faixa do recuo (onde passa a
49
- // guia) é da lista de filhos no hit-test do arraste. No bloco, o cursor
50
- // sobre a guia caía na lista de fora, e o destino mostrado era outro.
51
- > matcha-tree-branch {
52
- padding-inline-start: var(--matcha-tree-view-indent-step, 32px);
53
- }
54
- }
55
-
56
- @keyframes matcha-tree-view-children-in {
57
- from { opacity: 0; transform: translateY(-4px); }
58
- to { opacity: 1; transform: translateY(0); }
59
- }
60
-
61
- // O wrapper do nó é um .matcha-drag-item, e o drop-list desenha nele um state
62
- // layer (::before, currentColor a 8% no hover). Como o wrapper CONTÉM a
63
- // subárvore, passar o mouse num neto pintava a árvore inteira de cinza. Sem
64
- // state layer aqui: o hover é da ROW. Fica ANTES das regras da guia de
65
- // propósito — elas reutilizam o ::before com a mesma especificidade e vencem
66
- // por ordem.
67
- .matcha-tree-view .matcha-tree-view__node.matcha-drag-item::before {
68
- content: none;
69
- }
70
-
71
- // ── Guia de recuo ───────────────────────────────────────────────────────────
72
- // Vive no WRAPPER de cada nó filho, não no bloco: no bloco a vertical iria até
73
- // o fim dele, e quando o último filho tem subárvore a guia do pai desceria ao
74
- // lado dos netos sugerindo irmãos que não existem.
75
- //
76
- // X = centro da PRIMEIRA coluna da linha do pai (16px): o chevron quando a
77
- // árvore não arrasta, o gutter do grip quando arrasta. Medido a partir da
78
- // origem do wrapper do filho, isso é `meio controle - passo do recuo`,
79
- // negativo de propósito. A guia no centro do CHEVRON cairia em cima da coluna
80
- // do grip dos filhos, que é a mesma coluna deslocada um nível.
81
- .matcha-tree-view--guides .matcha-tree-view__node {
82
- position: relative;
83
- }
84
-
85
- .matcha-tree-view--guides .matcha-tree-view__children .matcha-tree-view__node::before {
86
- content: "";
87
- position: absolute;
88
- inset-block: 0;
89
- inset-inline-start: calc(
90
- var(--matcha-tree-view-control-size, 32px) / 2
91
- - var(--matcha-tree-view-indent-step, 32px)
92
- );
93
- width: var(--matcha-border-hairline, 1px);
94
- background: var(--matcha-tree-view-guide-color, currentColor);
95
- // Estrutura de leitura, não moldura: matcha/opacity/secondary (0.54) dá
96
- // ~2.9:1 no light e ~4.2:1 no dark, que num traço de 1px lê como fio.
97
- opacity: var(--matcha-opacity-secondary, 0.54);
98
- pointer-events: none;
99
- }
100
-
101
- // O state layer do drop-list (.matcha-drag-item:hover::before, opacidade 8%)
102
- // empata em especificidade com a regra acima e apagava a guia da linha sob o
103
- // mouse. Uma regra com :hover/:active vence e mantém a opacidade da guia.
104
- .matcha-tree-view--guides .matcha-tree-view__children .matcha-tree-view__node:hover::before,
105
- .matcha-tree-view--guides .matcha-tree-view__children .matcha-tree-view__node:active::before {
106
- opacity: var(--matcha-opacity-secondary, 0.54);
107
- }
108
-
109
- // Último irmão: a guia para no CENTRO da linha dele. Mora na row porque só ela
110
- // conhece a própria altura, então o pé fica no centro mesmo com linha secundária.
111
- .matcha-tree-view--guides .matcha-tree-view__children .matcha-tree-view__node.is-last::before {
112
- content: none;
113
- }
114
-
115
- .matcha-tree-view--guides .matcha-tree-view__children .matcha-tree-view__node.is-last
116
- .matcha-tree-view-item__row::before {
117
- content: "";
118
- position: absolute;
119
- inset-inline-start: calc(
120
- var(--matcha-tree-view-control-size, 32px) / 2
121
- - var(--matcha-tree-view-indent-step, 32px)
122
- );
123
- top: 0;
124
- height: 50%;
125
- width: var(--matcha-border-hairline, 1px);
126
- background: var(--matcha-tree-view-guide-color, currentColor);
127
- opacity: var(--matcha-opacity-secondary, 0.54);
128
- pointer-events: none;
129
- }
130
-
131
- // Recuo travado ([maxIndentLevel]): o bloco não recua nem desenha guia; a linha
132
- // fica no recuo do pai e o contexto entrega `clamped` pra ela sinalizar (L5+).
133
- .matcha-tree-view .matcha-tree-view__children.is-clamped > matcha-tree-branch {
134
- padding-inline-start: 0;
135
- }
136
-
137
- .matcha-tree-view--guides .matcha-tree-view__children.is-clamped > matcha-tree-branch > .matcha-tree-view__node::before,
138
- .matcha-tree-view--guides .matcha-tree-view__children.is-clamped > matcha-tree-branch > .matcha-tree-view__node.is-last
139
- .matcha-tree-view-item__row::before {
140
- content: none;
141
- }
142
-
143
- // Telas estreitas: metade do passo. Sem isso, 4 níveis comem metade da largura
144
- // e o nome do nó (a informação) fica sem espaço.
145
- @container matcha-tree-view (max-width: 480px) {
146
- .matcha-tree-view__children {
147
- --matcha-tree-view-indent-step: var(--matcha-space-200, 16px);
148
- }
149
- }
150
-
151
- // ── Wrapper do nó (o treeitem ARIA) ─────────────────────────────────────────
152
- .matcha-tree-view__node {
153
- display: block;
154
- outline: none;
155
- }
156
-
157
- // A row e a subárvore dela são IRMÃS dentro do wrapper, porque a recursão
158
- // (<matcha-tree-children>) mora no template da row. O wrapper também é o
159
- // .matcha-drag-item, que o drop-list declara `display: flex` em linha: sem
160
- // forçar coluna, os filhos renderizam à DIREITA da row.
161
- .matcha-tree-view .matcha-tree-view__node {
162
- display: flex;
163
- flex-direction: column;
164
- align-items: stretch;
165
- // Padding ZERO: o respiro é da row (48px de min-height). Somar aqui levava
166
- // o ritmo a 72px por linha e recuava TODOS os descendentes a cada nível.
167
- padding: 0;
168
- // E não pinta fundo: o wrapper CONTÉM a subárvore, e a parte que a row não
169
- // cobre virava uma faixa de tom diferente a cada nível.
170
- background: transparent;
171
- box-shadow: none;
172
- border-radius: 0;
173
- overflow: visible;
174
- }
175
-
176
- // Focus (teclado) na LINHA do nó focado — roving tabindex do container. O anel
177
- // do drop-list (no wrapper, com offset) contornaria a subárvore inteira.
178
- .matcha-tree-view .matcha-tree-view__node.matcha-drag-item:focus-visible {
179
- outline: none;
180
- }
181
-
182
- .matcha-tree-view .matcha-tree-view__node:focus-visible > matcha-tree-view-item .matcha-tree-view-item__row {
183
- outline: var(--matcha-border-thin, 2px) solid var(--matcha-color-accent);
184
- outline-offset: calc(-1 * var(--matcha-border-thin, 2px));
185
- }
186
-
187
- // "Não arrastável" num nó de árvore NÃO é "desabilitado". O drop-list marca a
188
- // row com .matcha-drag-disabled (pointer-events:none + cores de disabled), regra
189
- // pensada pra um card FOLHA. Aqui a row CONTÉM a própria subárvore e
190
- // pointer-events é herdado: apagaria os filhos do hit-test. Restaura.
191
- .matcha-tree-view .matcha-tree-view__node.matcha-drag-disabled {
192
- pointer-events: auto;
193
- color: inherit;
194
- background-color: transparent;
195
- }
196
-
197
- // ── Item host ───────────────────────────────────────────────────────────────
198
- matcha-tree-view-item {
199
- display: flex;
200
- flex-direction: row;
201
- align-items: stretch;
202
- width: 100%;
203
- box-sizing: border-box;
204
- outline: none;
205
-
206
- // Disabled por TOKEN, sem opacidade no wrapper (padrão do Matcha): texto e
207
- // ícones em disabled/fg, e a linha sai do hit-test.
208
- &[disabled] {
209
- color: var(--matcha-color-disabled-fg);
210
- --matcha-icon-color: var(--matcha-color-disabled-fg);
211
- pointer-events: none;
212
-
213
- .matcha-tree-view-item__name,
214
- .matcha-tree-view-item__counters strong { color: inherit; }
215
- }
216
-
217
- &[clickable]:not([disabled]) {
218
- cursor: pointer;
219
-
220
- &:focus-visible .matcha-tree-view-item__row {
221
- outline: var(--matcha-border-thin, 2px) solid var(--matcha-color-accent);
222
- outline-offset: calc(-1 * var(--matcha-border-thin, 2px));
223
- }
224
- }
225
-
226
- // Selected = barra de 2px accent à esquerda + tinta neutra. O preenchimento
227
- // cheio competia com o painel do nó-célula, que também é um fundo. Vale
228
- // pelo [selected] do item e pelo treeitem selecionado no container.
229
- &[selected] .matcha-tree-view-item__row,
230
- .matcha-tree-view__node.is-selected > & .matcha-tree-view-item__row {
231
- background: var(--matcha-color-surface-hover);
232
-
233
- &::after {
234
- content: "";
235
- position: absolute;
236
- inset-block: 0;
237
- inset-inline-start: 0;
238
- width: var(--matcha-border-thin, 2px);
239
- border-radius: var(--matcha-border-hairline, 1px);
240
- background: var(--matcha-color-accent);
241
- }
242
- }
243
- }
244
-
245
- // ── Indent liso (fora do container) — width inline = (level-1) × indentStep ──
246
- .matcha-tree-view-item__indent {
247
- flex: none;
248
- }
249
-
250
- // ── Row ─────────────────────────────────────────────────────────────────────
251
- .matcha-tree-view-item__row {
252
- position: relative; // contexto do pé da guia e da barra de seleção
253
- flex: 1;
254
- display: flex;
255
- flex-direction: row;
256
- align-items: center;
257
- gap: var(--matcha-space-100, 8px);
258
- min-height: 48px;
259
- // Sem padding à esquerda: a primeira coluna (grip ou disclosure) começa na
260
- // origem da linha, e é o centro dela (16px) que a guia do próximo nível usa.
261
- padding: var(--matcha-space-100, 8px) var(--matcha-space-150, 12px) var(--matcha-space-100, 8px) 0;
262
- background: transparent;
263
- border-radius: var(--matcha-radius-md, 4px);
264
- box-sizing: border-box;
265
- min-width: 0;
266
- transition: background-color var(--matcha-duration-instant, 80ms) ease;
267
- flex-wrap: var(--matcha-tree-view-item-wrap, nowrap);
268
- }
269
-
270
- // Sem primeira coluna (nem grip nem disclosure: o drill-down mobile, uma lista
271
- // achatada), a identidade colava na borda e o hover encostava no dot. A row
272
- // recupera o respiro lateral que a coluna de 32px dava de graça.
273
- .matcha-tree-view-item__row:not(:has(> .matcha-tree-view-item__grip, > .matcha-tree-view-item__disclosure)) {
274
- padding-inline-start: var(--matcha-space-150, 12px);
275
- }
276
-
277
- // Hover é o ÚNICO fundo que a row ganha fora de selected: transparente, a guia
278
- // passa por trás sem ser recortada a cada linha.
279
- matcha-tree-view-item:not([disabled]):hover .matcha-tree-view-item__row {
280
- background: var(--matcha-color-surface-hover);
281
- }
282
-
283
- // ── Prioridade de encolhimento — a identidade nunca cede primeiro ───────────
284
- .matcha-tree-view-item__row > * {
285
- min-width: 0; // permite truncar em vez de transbordar
286
- }
287
-
288
- // ── Slots da linha (classes que o consumer aplica no conteúdo projetado) ────
289
-
290
- // Grip: primeira coluna, 32px, NO FLUXO. Reserva o espaço só quando existe
291
- // (árvore arrastável) e revela o ícone em hover/focus. Em árvore arrastável,
292
- // projete o grip em TODAS as linhas, raiz inclusive, pra as colunas alinharem.
293
- .matcha-tree-view-item__grip {
294
- flex: none;
295
- display: inline-flex;
296
- align-items: center;
297
- justify-content: center;
298
- width: var(--matcha-tree-view-control-size, 32px);
299
- height: var(--matcha-tree-view-control-size, 32px);
300
- --matcha-icon-color: var(--matcha-color-text-muted);
301
- cursor: grab;
302
- opacity: 0;
303
- transition: opacity var(--matcha-duration-instant, 80ms) ease;
304
-
305
- &:active { cursor: grabbing; }
306
- }
307
-
308
- // Ações (kebab): slot reservado, ícone só em hover/focus. 11 kebabs sempre
309
- // visíveis eram uma coluna de ruído; o slot fica pra os contadores não pularem.
310
- .matcha-tree-view-item__actions {
311
- flex: none;
312
- display: flex;
313
- align-items: center;
314
- gap: var(--matcha-space-050, 4px);
315
- min-width: var(--matcha-tree-view-control-size, 32px);
316
- opacity: 0;
317
- transition: opacity var(--matcha-duration-instant, 80ms) ease;
318
- }
319
-
320
- matcha-tree-view-item:hover .matcha-tree-view-item__grip,
321
- matcha-tree-view-item:focus-within .matcha-tree-view-item__grip,
322
- .matcha-tree-view__node:focus-visible > matcha-tree-view-item .matcha-tree-view-item__grip,
323
- .matcha-drag-ghost .matcha-tree-view-item__grip,
324
- matcha-tree-view-item:hover .matcha-tree-view-item__actions,
325
- matcha-tree-view-item:focus-within .matcha-tree-view-item__actions,
326
- .matcha-tree-view__node:focus-visible > matcha-tree-view-item .matcha-tree-view-item__actions {
327
- opacity: 1;
328
- }
329
-
330
- // "Solte aqui para tornar filho" — o alvo de uma pasta ABERTA e VAZIA que aceita
331
- // o item (Figma: filhos · vazio). Aparece durante todo o arraste pra dar onde
332
- // mirar (IN-42506), mas só onde o drop é possível: nunca numa página, nunca na
333
- // outra árvore. É sempre neutro: quando o cursor chega nele (`.is-target`), o
334
- // destaque é o Recebendo na linha do PAI — um sinal só, como no Figma.
335
- .matcha-tree-view .matcha-drop-list-empty-placeholder {
336
- display: flex;
337
- align-items: center;
338
- justify-content: center;
339
- min-height: 48px;
340
- margin: var(--matcha-space-050, 4px) 0;
341
- padding: var(--matcha-space-100, 8px) var(--matcha-space-150, 12px);
342
- font-size: var(--matcha-text-body-sm, 12px);
343
- line-height: 16px;
344
- color: var(--matcha-color-text-muted);
345
- border: var(--matcha-border-hairline, 1px) dashed var(--matcha-color-surface-border);
346
- border-radius: var(--matcha-radius-md, 4px);
347
- background: transparent;
348
- box-sizing: border-box;
349
- pointer-events: auto;
350
- }
351
-
352
- // Em ponteiro grosso (toque) não existe hover: grip e ações ficam visíveis.
353
- @media (hover: none) {
354
- .matcha-tree-view-item__grip,
355
- .matcha-tree-view-item__actions { opacity: 1; }
356
- }
357
-
358
- // Navegar (›): o trailing do drill-down mobile. Sempre visível; substitui as
359
- // ações quando a linha inteira navega.
360
- .matcha-tree-view-item__navigate {
361
- flex: none;
362
- display: inline-flex;
363
- align-items: center;
364
- justify-content: center;
365
- width: var(--matcha-tree-view-control-size, 32px);
366
- height: var(--matcha-tree-view-control-size, 32px);
367
- --matcha-icon-color: var(--matcha-color-text-muted);
368
- }
369
-
370
- // Disclosure: 32px, reserva o slot mesmo na folha (use a classe num <span>
371
- // vazio) pra a identidade alinhar entre irmãos. Um único chevron-right que o
372
- // tema gira em 150ms quando o item está [expanded]; caption em repouso, texto
373
- // no hover/focus.
374
- matcha-tree-view-item .matcha-tree-view-item__disclosure {
375
- flex: none;
376
- display: inline-flex;
377
- align-items: center;
378
- justify-content: center;
379
- width: var(--matcha-tree-view-control-size, 32px);
380
- height: var(--matcha-tree-view-control-size, 32px);
381
- --matcha-icon-color: var(--matcha-color-text-muted);
382
-
383
- matcha-icon {
384
- transition: transform 150ms var(--matcha-easing-standard, ease);
385
- }
386
- }
387
-
388
- matcha-tree-view-item[expanded] .matcha-tree-view-item__disclosure matcha-icon {
389
- transform: rotate(90deg);
390
- }
391
-
392
- matcha-tree-view-item:hover .matcha-tree-view-item__disclosure,
393
- matcha-tree-view-item:focus-within .matcha-tree-view-item__disclosure,
394
- .matcha-tree-view__node:focus-visible > matcha-tree-view-item .matcha-tree-view-item__disclosure {
395
- --matcha-icon-color: var(--matcha-color-text-primary);
396
- }
397
-
398
- // Identidade (dot|avatar + textos). Fica com o espaço que sobra e é a ÚLTIMA a
399
- // ceder: sem isso o flex encolhe na ordem do DOM e, em tela estreita, o NOME
400
- // chegava a zero enquanto cargo e contador ficavam intactos.
401
- .matcha-tree-view-item__identity {
402
- flex: 1 1 auto;
403
- min-width: 4ch; // piso: sempre sobra o começo do nome
404
- display: flex;
405
- align-items: center;
406
- gap: var(--matcha-space-100, 8px);
407
- // SEM overflow:hidden. Quem trunca é o texto (min-width:0 + text-overflow
408
- // no __name/__secondary), e recortar aqui comia os 2px do anel de nível do
409
- // avatar — que ficava com as beiradas retas — e comeria também o anel de
410
- // foco de qualquer controle projetado na identidade.
411
- overflow: visible;
412
-
413
- > * { min-width: 0; }
414
- }
415
-
416
- // Cor de nível: no dot (6px + anel a 20%) ou no anel do avatar. O consumer
417
- // informa a cor em --matcha-tree-view-level-color; sem ela, herda o texto.
418
- .matcha-tree-view-item__dot {
419
- flex: none;
420
- width: 6px;
421
- height: 6px;
422
- margin: var(--matcha-border-thin, 2px);
423
- border-radius: var(--matcha-radius-pill, 9999px);
424
- background: var(--matcha-tree-view-level-color, currentColor);
425
- box-shadow: 0 0 0 var(--matcha-border-thin, 2px)
426
- color-mix(in srgb, var(--matcha-tree-view-level-color, currentColor) 20%, transparent);
427
- }
428
-
429
- .matcha-tree-view-item__avatar {
430
- flex: none;
431
- display: inline-flex;
432
-
433
- .matcha-avatar {
434
- border-radius: var(--matcha-radius-pill, 9999px);
435
- box-shadow: 0 0 0 var(--matcha-border-thin, 2px) var(--matcha-tree-view-level-color, transparent);
436
- }
437
- }
438
-
439
- // Textos: nome (label-medium) e linha secundária opcional (p-small, caption).
440
- // Com linha secundária a row cresce pra 64px sozinha.
441
- .matcha-tree-view-item__text {
442
- flex: 1 1 auto;
443
- min-width: 0;
444
- display: flex;
445
- flex-direction: column;
446
- gap: var(--matcha-border-thin, 2px);
447
- }
448
-
449
- .matcha-tree-view-item__name {
450
- display: block;
451
- min-width: 0;
452
- overflow: hidden;
453
- text-overflow: ellipsis;
454
- white-space: nowrap;
455
- font-size: var(--matcha-text-label-md, 14px);
456
- font-weight: var(--matcha-font-weight-medium, 500);
457
- line-height: 20px;
458
- color: var(--matcha-color-text-primary);
459
- }
460
-
461
- .matcha-tree-view-item__secondary {
462
- display: block;
463
- min-width: 0;
464
- overflow: hidden;
465
- text-overflow: ellipsis;
466
- white-space: nowrap;
467
- font-size: var(--matcha-text-body-sm, 12px);
468
- line-height: 16px;
469
- color: var(--matcha-color-text-muted);
470
- }
471
-
472
- // Meta (cargo + contadores). Cede ANTES do nome e, quando não cabe, sai de cena.
473
- .matcha-tree-view-item__meta {
474
- flex: 0 1 auto;
475
- min-width: 0;
476
- margin-inline-start: auto;
477
- display: flex;
478
- align-items: center;
479
- gap: var(--matcha-space-100, 8px);
480
- overflow: hidden;
481
- color: var(--matcha-color-text-muted);
482
- }
483
-
484
- // Cargo é TEXTO, não pílula: pílula em toda linha é peso repetido 30 vezes na
485
- // tela. Pílula (matcha-badge) fica pra ESTADO (Inativo, Pendente).
486
- .matcha-tree-view-item__cargo {
487
- flex: none;
488
- font-size: var(--matcha-text-label-sm, 12px);
489
- font-weight: var(--matcha-font-weight-medium, 500);
490
- line-height: 16px;
491
- color: var(--matcha-color-text-muted);
492
- white-space: nowrap;
493
- }
494
-
495
- // Contadores: números tabulares (alinham à direita sem parecer relatório) e
496
- // sem zero à esquerda — isso é do dado, não do CSS: "2 células", não "02".
497
- .matcha-tree-view-item__counters {
498
- flex: none;
499
- display: inline-flex;
500
- align-items: baseline;
501
- gap: var(--matcha-space-050, 4px);
502
- font-variant-numeric: tabular-nums;
503
- white-space: nowrap;
504
-
505
- strong {
506
- font-size: var(--matcha-text-body-sm, 12px);
507
- font-weight: var(--matcha-font-weight-medium, 500);
508
- color: var(--matcha-color-text-primary);
509
- }
510
-
511
- small {
512
- font-size: var(--matcha-text-p-tiny, 11px);
513
- letter-spacing: 0.3px;
514
- color: var(--matcha-color-text-muted);
515
- }
516
- }
517
-
518
- // Só some quando não há mesmo onde caber. Entre 360 e 480 o flex encolhe o
519
- // meta antes do nome.
520
- @container matcha-tree-view (max-width: 360px) {
521
- .matcha-tree-view-item__meta { display: none; }
522
- }
523
-
524
- @container matcha-tree-view (max-width: 480px) {
525
- .matcha-tree-view-item__indent {
526
- transform: scaleX(0.6);
527
- transform-origin: left center;
528
- }
529
-
530
- .matcha-tree-view-item__row {
531
- gap: var(--matcha-space-050, 4px);
532
- min-height: 44px; // alvo de toque WCAG 2.5.5 em mobile
533
- }
534
- }
535
-
536
- // ── Drag-and-drop (compõe com o motor do matcha-drop-list) ──────────────────
537
- // Um alvo por vez: a árvore resolve o destino sob o cursor e pinta UMA coisa —
538
- // Recebendo na pasta que vai receber, Recusado na linha que não aceita, ou a
539
- // linha do Figma entre irmãos. As classes vêm do branch (estado da árvore).
540
-
541
- // Dragging = o FANTASMA na origem, durante o arraste inteiro (Figma:
542
- // opacity/disabled). Esmaece o bloco todo: a subárvore vai junto com o nó.
543
- .matcha-tree-view .matcha-tree-view__node.is-dragging {
544
- opacity: var(--matcha-opacity-disabled, 0.38);
545
- }
546
-
547
- // Durante o arraste o hover das linhas sai de cena: um fundo de hover sob o
548
- // cursor parecia um segundo alvo ao lado do Recebendo, e o grip e o kebab
549
- // revelados na linha de destino eram ruído (ela é destino, não alvo de clique).
550
- .matcha-tree-view--dragging matcha-tree-view-item:not([disabled]):hover .matcha-tree-view-item__row {
551
- background: transparent;
552
- }
553
-
554
- .matcha-tree-view--dragging matcha-tree-view-item:hover .matcha-tree-view-item__grip,
555
- .matcha-tree-view--dragging matcha-tree-view-item:hover .matcha-tree-view-item__actions {
556
- opacity: 0;
557
- }
558
-
559
- // Recebendo = a pasta que vai receber o item como filho: tinta accent + hairline
560
- // accent. Mesma especificidade da regra acima e declarada depois: vence o hover
561
- // suprimido e o selected.
562
- .matcha-tree-view .matcha-tree-view__node.is-drop-into > matcha-tree-view-item .matcha-tree-view-item__row {
563
- background: var(--matcha-color-accent-surface-hover, var(--matcha-color-accent-alpha));
564
- box-shadow: inset 0 0 0 var(--matcha-border-hairline, 1px) var(--matcha-color-accent);
565
- }
566
-
567
- // Recusado = destino inválido (tipo ou profundidade), só na linha sob o cursor:
568
- // tracejado danger de 2px (Figma: border/thin).
569
- .matcha-tree-view .matcha-tree-view__node.is-drop-rejected > matcha-tree-view-item .matcha-tree-view-item__row {
570
- outline: var(--matcha-border-thin, 2px) dashed var(--matcha-color-danger);
571
- outline-offset: calc(-1 * var(--matcha-border-thin, 2px));
572
- }
573
-
574
- // Entre irmãos = a linha do Figma (matcha/tree-view/drop-indicator): 2px accent
575
- // com uma bolinha no começo, na borda do nó e no recuo do nível dele.
576
- .matcha-tree-view__drop-line {
577
- position: absolute;
578
- inset-inline: 0;
579
- top: calc(-1 * var(--matcha-border-thin, 2px) / 2);
580
- height: var(--matcha-border-thin, 2px);
581
- border-radius: var(--matcha-radius-pill, 9999px);
582
- background: var(--matcha-color-accent);
583
- pointer-events: none;
584
- z-index: 1;
585
-
586
- &::before {
587
- content: "";
588
- position: absolute;
589
- inset-inline-start: 0;
590
- top: 50%;
591
- width: var(--matcha-space-075, 6px);
592
- height: var(--matcha-space-075, 6px);
593
- border-radius: var(--matcha-radius-pill, 9999px);
594
- background: var(--matcha-color-accent);
595
- transform: translateY(-50%);
596
- }
597
-
598
- &--after {
599
- top: auto;
600
- bottom: calc(-1 * var(--matcha-border-thin, 2px) / 2);
601
- }
602
- }
603
-
604
- // Levantado = a cópia que acompanha o cursor: SÓ a linha, com superfície e
605
- // elevação level-2 — a sombra é da row, não da caixa do clone. Escopado no
606
- // clone de nó da árvore: o ghost das listas planas segue com a opacidade e a
607
- // sombra do drop-list.
608
- .matcha-drag-ghost:has(> .matcha-tree-view__node) {
609
- opacity: 1;
610
- box-shadow: none;
611
- border-radius: 0;
612
- }
613
-
614
- // O motor clona o wrapper inteiro (a subárvore junto); esconder os filhos no
615
- // clone deixa a cópia do tamanho de uma linha.
616
- .matcha-drag-ghost {
617
- .matcha-tree-view__children-host { display: none; }
618
-
619
- .matcha-tree-view-item__row {
620
- background: var(--matcha-color-surface);
621
- box-shadow: var(--matcha-shadow-2);
622
- border-radius: var(--matcha-radius-md, 4px);
623
- }
624
-
625
- .matcha-tree-view-item__grip { opacity: 1; }
626
- }
627
-
628
- // Região do aria-live: só pra leitor de tela.
629
- .matcha-tree-view__live {
630
- position: absolute;
631
- width: 1px;
632
- height: 1px;
633
- margin: -1px;
634
- padding: 0;
635
- overflow: hidden;
636
- clip: rect(0 0 0 0);
637
- white-space: nowrap;
638
- border: 0;
639
- }
640
-
641
- // Respeita preferência de redução de movimento
642
- @media (prefers-reduced-motion: reduce) {
643
- matcha-tree-view-item,
644
- matcha-tree-view-item:not(.matcha-drag-dragging),
645
- .matcha-tree-view__children,
646
- .matcha-tree-view-item__disclosure matcha-icon,
647
- .matcha-tree-view-item__row,
648
- .matcha-tree-view-item__grip,
649
- .matcha-tree-view-item__actions {
650
- animation: none !important;
651
- transition: none !important;
652
- }
653
- }
654
-
655
- // ── Theme mixin ─────────────────────────────────────────────────────────────
656
- @mixin matcha-tree-view-theme($theme) {
657
- // Tudo via CSS vars — sem theme-specific overrides.
658
- }
1
+ // =============================================================================
2
+ // matcha-tree-view.scss — árvore hierárquica do painel (Figma DSV3 matcha/tree-view)
3
+ //
4
+ // UMA anatomia de linha pra qualquer nó:
5
+ // [grip 32 · disclosure 32 · identidade (dot|avatar + nome, linha secundária) · meta (cargo + contadores) · ações]
6
+ // Nível NÃO é variante: é o recuo do bloco de filhos (32px) + uma guia vertical
7
+ // alinhada ao centro da primeira coluna da linha do pai. O consumer compõe a
8
+ // linha com as classes de slot abaixo; o componente não impõe conteúdo.
9
+ // =============================================================================
10
+
11
+ // ── Container ───────────────────────────────────────────────────────────────
12
+ .matcha-tree-view {
13
+ display: flex;
14
+ flex-direction: column;
15
+ // Sem tray e sem gap. A árvore vive na superfície da página: fundo próprio
16
+ // + rows-card + respiro entre elas transformavam a hierarquia numa pilha de
17
+ // chips, e o card opaco de cada row cobria a guia, que saía tracejada.
18
+ gap: 0;
19
+ padding: 0;
20
+ background: transparent;
21
+ border-radius: 0;
22
+
23
+ container-type: inline-size;
24
+ container-name: matcha-tree-view;
25
+
26
+ .matcha-drop-list-container {
27
+ display: flex;
28
+ flex-direction: column;
29
+ gap: 0;
30
+ }
31
+ }
32
+
33
+ matcha-tree-branch,
34
+ .matcha-tree-view__children {
35
+ display: flex;
36
+ flex-direction: column;
37
+ gap: 0;
38
+ }
39
+
40
+ // ── Recuo (bloco de filhos) ────────────────────────────────────────────────
41
+ // O recuo é do BLOCO, não de cada linha: o item dentro do container não recua
42
+ // sozinho, e a guia vira UM traço por nível, contínuo por estrutura.
43
+ .matcha-tree-view__children {
44
+ position: relative;
45
+ // Motion do Figma: filhos entram em 200ms, desacelerando.
46
+ animation: matcha-tree-view-children-in var(--matcha-duration-fast, 200ms) var(--matcha-easing-decelerated, ease-out) both;
47
+
48
+ // O padding mora no BRANCH, não no bloco: a faixa do recuo (onde passa a
49
+ // guia) é da lista de filhos no hit-test do arraste. No bloco, o cursor
50
+ // sobre a guia caía na lista de fora, e o destino mostrado era outro.
51
+ > matcha-tree-branch {
52
+ padding-inline-start: var(--matcha-tree-view-indent-step, 32px);
53
+ }
54
+ }
55
+
56
+ @keyframes matcha-tree-view-children-in {
57
+ from { opacity: 0; transform: translateY(-4px); }
58
+ to { opacity: 1; transform: translateY(0); }
59
+ }
60
+
61
+ // O wrapper do nó é um .matcha-drag-item, e o drop-list desenha nele um state
62
+ // layer (::before, currentColor a 8% no hover). Como o wrapper CONTÉM a
63
+ // subárvore, passar o mouse num neto pintava a árvore inteira de cinza. Sem
64
+ // state layer aqui: o hover é da ROW. Fica ANTES das regras da guia de
65
+ // propósito — elas reutilizam o ::before com a mesma especificidade e vencem
66
+ // por ordem.
67
+ .matcha-tree-view .matcha-tree-view__node.matcha-drag-item::before {
68
+ content: none;
69
+ }
70
+
71
+ // ── Guia de recuo ───────────────────────────────────────────────────────────
72
+ // Vive no WRAPPER de cada nó filho, não no bloco: no bloco a vertical iria até
73
+ // o fim dele, e quando o último filho tem subárvore a guia do pai desceria ao
74
+ // lado dos netos sugerindo irmãos que não existem.
75
+ //
76
+ // X = centro da PRIMEIRA coluna da linha do pai (16px): o chevron quando a
77
+ // árvore não arrasta, o gutter do grip quando arrasta. Medido a partir da
78
+ // origem do wrapper do filho, isso é `meio controle - passo do recuo`,
79
+ // negativo de propósito. A guia no centro do CHEVRON cairia em cima da coluna
80
+ // do grip dos filhos, que é a mesma coluna deslocada um nível.
81
+ .matcha-tree-view--guides .matcha-tree-view__node {
82
+ position: relative;
83
+ }
84
+
85
+ .matcha-tree-view--guides .matcha-tree-view__children .matcha-tree-view__node::before {
86
+ content: "";
87
+ position: absolute;
88
+ inset-block: 0;
89
+ inset-inline-start: calc(
90
+ var(--matcha-tree-view-control-size, 32px) / 2
91
+ - var(--matcha-tree-view-indent-step, 32px)
92
+ );
93
+ width: var(--matcha-border-hairline, 1px);
94
+ background: var(--matcha-tree-view-guide-color, currentColor);
95
+ // Estrutura de leitura, não moldura: matcha/opacity/secondary (0.54) dá
96
+ // ~2.9:1 no light e ~4.2:1 no dark, que num traço de 1px lê como fio.
97
+ opacity: var(--matcha-opacity-secondary, 0.54);
98
+ pointer-events: none;
99
+ }
100
+
101
+ // O state layer do drop-list (.matcha-drag-item:hover::before, opacidade 8%)
102
+ // empata em especificidade com a regra acima e apagava a guia da linha sob o
103
+ // mouse. Uma regra com :hover/:active vence e mantém a opacidade da guia.
104
+ .matcha-tree-view--guides .matcha-tree-view__children .matcha-tree-view__node:hover::before,
105
+ .matcha-tree-view--guides .matcha-tree-view__children .matcha-tree-view__node:active::before {
106
+ opacity: var(--matcha-opacity-secondary, 0.54);
107
+ }
108
+
109
+ // Último irmão: a guia para no CENTRO da linha dele. Mora na row porque só ela
110
+ // conhece a própria altura, então o pé fica no centro mesmo com linha secundária.
111
+ .matcha-tree-view--guides .matcha-tree-view__children .matcha-tree-view__node.is-last::before {
112
+ content: none;
113
+ }
114
+
115
+ .matcha-tree-view--guides .matcha-tree-view__children .matcha-tree-view__node.is-last
116
+ .matcha-tree-view-item__row::before {
117
+ content: "";
118
+ position: absolute;
119
+ inset-inline-start: calc(
120
+ var(--matcha-tree-view-control-size, 32px) / 2
121
+ - var(--matcha-tree-view-indent-step, 32px)
122
+ );
123
+ top: 0;
124
+ height: 50%;
125
+ width: var(--matcha-border-hairline, 1px);
126
+ background: var(--matcha-tree-view-guide-color, currentColor);
127
+ opacity: var(--matcha-opacity-secondary, 0.54);
128
+ pointer-events: none;
129
+ }
130
+
131
+ // Recuo travado ([maxIndentLevel]): o bloco não recua nem desenha guia; a linha
132
+ // fica no recuo do pai e o contexto entrega `clamped` pra ela sinalizar (L5+).
133
+ .matcha-tree-view .matcha-tree-view__children.is-clamped > matcha-tree-branch {
134
+ padding-inline-start: 0;
135
+ }
136
+
137
+ .matcha-tree-view--guides .matcha-tree-view__children.is-clamped > matcha-tree-branch > .matcha-tree-view__node::before,
138
+ .matcha-tree-view--guides .matcha-tree-view__children.is-clamped > matcha-tree-branch > .matcha-tree-view__node.is-last
139
+ .matcha-tree-view-item__row::before {
140
+ content: none;
141
+ }
142
+
143
+ // Telas estreitas: metade do passo. Sem isso, 4 níveis comem metade da largura
144
+ // e o nome do nó (a informação) fica sem espaço.
145
+ @container matcha-tree-view (max-width: 480px) {
146
+ .matcha-tree-view__children {
147
+ --matcha-tree-view-indent-step: var(--matcha-space-200, 16px);
148
+ }
149
+ }
150
+
151
+ // ── Wrapper do nó (o treeitem ARIA) ─────────────────────────────────────────
152
+ .matcha-tree-view__node {
153
+ display: block;
154
+ outline: none;
155
+ }
156
+
157
+ // A row e a subárvore dela são IRMÃS dentro do wrapper, porque a recursão
158
+ // (<matcha-tree-children>) mora no template da row. O wrapper também é o
159
+ // .matcha-drag-item, que o drop-list declara `display: flex` em linha: sem
160
+ // forçar coluna, os filhos renderizam à DIREITA da row.
161
+ .matcha-tree-view .matcha-tree-view__node {
162
+ display: flex;
163
+ flex-direction: column;
164
+ align-items: stretch;
165
+ // Padding ZERO: o respiro é da row (48px de min-height). Somar aqui levava
166
+ // o ritmo a 72px por linha e recuava TODOS os descendentes a cada nível.
167
+ padding: 0;
168
+ // E não pinta fundo: o wrapper CONTÉM a subárvore, e a parte que a row não
169
+ // cobre virava uma faixa de tom diferente a cada nível.
170
+ background: transparent;
171
+ box-shadow: none;
172
+ border-radius: 0;
173
+ overflow: visible;
174
+ }
175
+
176
+ // Focus (teclado) na LINHA do nó focado — roving tabindex do container. O anel
177
+ // do drop-list (no wrapper, com offset) contornaria a subárvore inteira.
178
+ .matcha-tree-view .matcha-tree-view__node.matcha-drag-item:focus-visible {
179
+ outline: none;
180
+ }
181
+
182
+ .matcha-tree-view .matcha-tree-view__node:focus-visible > matcha-tree-view-item .matcha-tree-view-item__row {
183
+ outline: var(--matcha-border-thin, 2px) solid var(--matcha-color-accent);
184
+ outline-offset: calc(-1 * var(--matcha-border-thin, 2px));
185
+ }
186
+
187
+ // "Não arrastável" num nó de árvore NÃO é "desabilitado". O drop-list marca a
188
+ // row com .matcha-drag-disabled (pointer-events:none + cores de disabled), regra
189
+ // pensada pra um card FOLHA. Aqui a row CONTÉM a própria subárvore e
190
+ // pointer-events é herdado: apagaria os filhos do hit-test. Restaura.
191
+ .matcha-tree-view .matcha-tree-view__node.matcha-drag-disabled {
192
+ pointer-events: auto;
193
+ color: inherit;
194
+ background-color: transparent;
195
+ }
196
+
197
+ // ── Item host ───────────────────────────────────────────────────────────────
198
+ matcha-tree-view-item {
199
+ display: flex;
200
+ flex-direction: row;
201
+ align-items: stretch;
202
+ width: 100%;
203
+ box-sizing: border-box;
204
+ outline: none;
205
+
206
+ // Disabled por TOKEN, sem opacidade no wrapper (padrão do Matcha): texto e
207
+ // ícones em disabled/fg, e a linha sai do hit-test.
208
+ &[disabled] {
209
+ color: var(--matcha-color-disabled-fg);
210
+ --matcha-icon-color: var(--matcha-color-disabled-fg);
211
+ pointer-events: none;
212
+
213
+ .matcha-tree-view-item__name,
214
+ .matcha-tree-view-item__counters strong { color: inherit; }
215
+ }
216
+
217
+ &[clickable]:not([disabled]) {
218
+ cursor: pointer;
219
+
220
+ &:focus-visible .matcha-tree-view-item__row {
221
+ outline: var(--matcha-border-thin, 2px) solid var(--matcha-color-accent);
222
+ outline-offset: calc(-1 * var(--matcha-border-thin, 2px));
223
+ }
224
+ }
225
+
226
+ // Selected = barra de 2px accent à esquerda + tinta neutra. O preenchimento
227
+ // cheio competia com o painel do nó-célula, que também é um fundo. Vale
228
+ // pelo [selected] do item e pelo treeitem selecionado no container.
229
+ &[selected] .matcha-tree-view-item__row,
230
+ .matcha-tree-view__node.is-selected > & .matcha-tree-view-item__row {
231
+ background: var(--matcha-color-surface-hover);
232
+
233
+ &::after {
234
+ content: "";
235
+ position: absolute;
236
+ inset-block: 0;
237
+ inset-inline-start: 0;
238
+ width: var(--matcha-border-thin, 2px);
239
+ border-radius: var(--matcha-border-hairline, 1px);
240
+ background: var(--matcha-color-accent);
241
+ }
242
+ }
243
+ }
244
+
245
+ // ── Indent liso (fora do container) — width inline = (level-1) × indentStep ──
246
+ .matcha-tree-view-item__indent {
247
+ flex: none;
248
+ }
249
+
250
+ // ── Row ─────────────────────────────────────────────────────────────────────
251
+ .matcha-tree-view-item__row {
252
+ position: relative; // contexto do pé da guia e da barra de seleção
253
+ flex: 1;
254
+ display: flex;
255
+ flex-direction: row;
256
+ align-items: center;
257
+ gap: var(--matcha-space-100, 8px);
258
+ min-height: 48px;
259
+ // Sem padding à esquerda: a primeira coluna (grip ou disclosure) começa na
260
+ // origem da linha, e é o centro dela (16px) que a guia do próximo nível usa.
261
+ padding: var(--matcha-space-100, 8px) var(--matcha-space-150, 12px) var(--matcha-space-100, 8px) 0;
262
+ background: transparent;
263
+ border-radius: var(--matcha-radius-md, 4px);
264
+ box-sizing: border-box;
265
+ min-width: 0;
266
+ transition: background-color var(--matcha-duration-instant, 80ms) ease;
267
+ flex-wrap: var(--matcha-tree-view-item-wrap, nowrap);
268
+ }
269
+
270
+ // Sem primeira coluna (nem grip nem disclosure: o drill-down mobile, uma lista
271
+ // achatada), a identidade colava na borda e o hover encostava no dot. A row
272
+ // recupera o respiro lateral que a coluna de 32px dava de graça.
273
+ .matcha-tree-view-item__row:not(:has(> .matcha-tree-view-item__grip, > .matcha-tree-view-item__disclosure)) {
274
+ padding-inline-start: var(--matcha-space-150, 12px);
275
+ }
276
+
277
+ // Hover é o ÚNICO fundo que a row ganha fora de selected: transparente, a guia
278
+ // passa por trás sem ser recortada a cada linha.
279
+ matcha-tree-view-item:not([disabled]):hover .matcha-tree-view-item__row {
280
+ background: var(--matcha-color-surface-hover);
281
+ }
282
+
283
+ // ── Prioridade de encolhimento — a identidade nunca cede primeiro ───────────
284
+ .matcha-tree-view-item__row > * {
285
+ min-width: 0; // permite truncar em vez de transbordar
286
+ }
287
+
288
+ // ── Slots da linha (classes que o consumer aplica no conteúdo projetado) ────
289
+
290
+ // Grip: primeira coluna, 32px, NO FLUXO. Reserva o espaço só quando existe
291
+ // (árvore arrastável) e revela o ícone em hover/focus. Em árvore arrastável,
292
+ // projete o grip em TODAS as linhas, raiz inclusive, pra as colunas alinharem.
293
+ .matcha-tree-view-item__grip {
294
+ flex: none;
295
+ display: inline-flex;
296
+ align-items: center;
297
+ justify-content: center;
298
+ width: var(--matcha-tree-view-control-size, 32px);
299
+ height: var(--matcha-tree-view-control-size, 32px);
300
+ --matcha-icon-color: var(--matcha-color-text-muted);
301
+ cursor: grab;
302
+ opacity: 0;
303
+ transition: opacity var(--matcha-duration-instant, 80ms) ease;
304
+
305
+ &:active { cursor: grabbing; }
306
+ }
307
+
308
+ // Ações (kebab): slot reservado, ícone só em hover/focus. 11 kebabs sempre
309
+ // visíveis eram uma coluna de ruído; o slot fica pra os contadores não pularem.
310
+ .matcha-tree-view-item__actions {
311
+ flex: none;
312
+ display: flex;
313
+ align-items: center;
314
+ gap: var(--matcha-space-050, 4px);
315
+ min-width: var(--matcha-tree-view-control-size, 32px);
316
+ opacity: 0;
317
+ transition: opacity var(--matcha-duration-instant, 80ms) ease;
318
+ }
319
+
320
+ matcha-tree-view-item:hover .matcha-tree-view-item__grip,
321
+ matcha-tree-view-item:focus-within .matcha-tree-view-item__grip,
322
+ .matcha-tree-view__node:focus-visible > matcha-tree-view-item .matcha-tree-view-item__grip,
323
+ .matcha-drag-ghost .matcha-tree-view-item__grip,
324
+ matcha-tree-view-item:hover .matcha-tree-view-item__actions,
325
+ matcha-tree-view-item:focus-within .matcha-tree-view-item__actions,
326
+ .matcha-tree-view__node:focus-visible > matcha-tree-view-item .matcha-tree-view-item__actions {
327
+ opacity: 1;
328
+ }
329
+
330
+ // "Solte aqui para tornar filho" — o alvo de uma pasta ABERTA e VAZIA que aceita
331
+ // o item (Figma: filhos · vazio). Aparece durante todo o arraste pra dar onde
332
+ // mirar (IN-42506), mas só onde o drop é possível: nunca numa página, nunca na
333
+ // outra árvore. É sempre neutro: quando o cursor chega nele (`.is-target`), o
334
+ // destaque é o Recebendo na linha do PAI — um sinal só, como no Figma.
335
+ .matcha-tree-view .matcha-drop-list-empty-placeholder {
336
+ display: flex;
337
+ align-items: center;
338
+ justify-content: center;
339
+ min-height: 48px;
340
+ margin: var(--matcha-space-050, 4px) 0;
341
+ padding: var(--matcha-space-100, 8px) var(--matcha-space-150, 12px);
342
+ font-size: var(--matcha-text-body-sm, 12px);
343
+ line-height: 16px;
344
+ color: var(--matcha-color-text-muted);
345
+ border: var(--matcha-border-hairline, 1px) dashed var(--matcha-color-surface-border);
346
+ border-radius: var(--matcha-radius-md, 4px);
347
+ background: transparent;
348
+ box-sizing: border-box;
349
+ pointer-events: auto;
350
+ }
351
+
352
+ // Em ponteiro grosso (toque) não existe hover: grip e ações ficam visíveis.
353
+ @media (hover: none) {
354
+ .matcha-tree-view-item__grip,
355
+ .matcha-tree-view-item__actions { opacity: 1; }
356
+ }
357
+
358
+ // Navegar (›): o trailing do drill-down mobile. Sempre visível; substitui as
359
+ // ações quando a linha inteira navega.
360
+ .matcha-tree-view-item__navigate {
361
+ flex: none;
362
+ display: inline-flex;
363
+ align-items: center;
364
+ justify-content: center;
365
+ width: var(--matcha-tree-view-control-size, 32px);
366
+ height: var(--matcha-tree-view-control-size, 32px);
367
+ --matcha-icon-color: var(--matcha-color-text-muted);
368
+ }
369
+
370
+ // Disclosure: 32px, reserva o slot mesmo na folha (use a classe num <span>
371
+ // vazio) pra a identidade alinhar entre irmãos. Um único chevron-right que o
372
+ // tema gira em 150ms quando o item está [expanded]; caption em repouso, texto
373
+ // no hover/focus.
374
+ matcha-tree-view-item .matcha-tree-view-item__disclosure {
375
+ flex: none;
376
+ display: inline-flex;
377
+ align-items: center;
378
+ justify-content: center;
379
+ width: var(--matcha-tree-view-control-size, 32px);
380
+ height: var(--matcha-tree-view-control-size, 32px);
381
+ --matcha-icon-color: var(--matcha-color-text-muted);
382
+
383
+ matcha-icon {
384
+ transition: transform 150ms var(--matcha-easing-standard, ease);
385
+ }
386
+ }
387
+
388
+ matcha-tree-view-item[expanded] .matcha-tree-view-item__disclosure matcha-icon {
389
+ transform: rotate(90deg);
390
+ }
391
+
392
+ matcha-tree-view-item:hover .matcha-tree-view-item__disclosure,
393
+ matcha-tree-view-item:focus-within .matcha-tree-view-item__disclosure,
394
+ .matcha-tree-view__node:focus-visible > matcha-tree-view-item .matcha-tree-view-item__disclosure {
395
+ --matcha-icon-color: var(--matcha-color-text-primary);
396
+ }
397
+
398
+ // Identidade (dot|avatar + textos). Fica com o espaço que sobra e é a ÚLTIMA a
399
+ // ceder: sem isso o flex encolhe na ordem do DOM e, em tela estreita, o NOME
400
+ // chegava a zero enquanto cargo e contador ficavam intactos.
401
+ .matcha-tree-view-item__identity {
402
+ flex: 1 1 auto;
403
+ min-width: 4ch; // piso: sempre sobra o começo do nome
404
+ display: flex;
405
+ align-items: center;
406
+ gap: var(--matcha-space-100, 8px);
407
+ // SEM overflow:hidden. Quem trunca é o texto (min-width:0 + text-overflow
408
+ // no __name/__secondary), e recortar aqui comia os 2px do anel de nível do
409
+ // avatar — que ficava com as beiradas retas — e comeria também o anel de
410
+ // foco de qualquer controle projetado na identidade.
411
+ overflow: visible;
412
+
413
+ > * { min-width: 0; }
414
+ }
415
+
416
+ // Cor de nível: no dot (6px + anel a 20%) ou no anel do avatar. O consumer
417
+ // informa a cor em --matcha-tree-view-level-color; sem ela, herda o texto.
418
+ .matcha-tree-view-item__dot {
419
+ flex: none;
420
+ width: 6px;
421
+ height: 6px;
422
+ margin: var(--matcha-border-thin, 2px);
423
+ border-radius: var(--matcha-radius-pill, 9999px);
424
+ background: var(--matcha-tree-view-level-color, currentColor);
425
+ box-shadow: 0 0 0 var(--matcha-border-thin, 2px)
426
+ color-mix(in srgb, var(--matcha-tree-view-level-color, currentColor) 20%, transparent);
427
+ }
428
+
429
+ .matcha-tree-view-item__avatar {
430
+ flex: none;
431
+ display: inline-flex;
432
+
433
+ .matcha-avatar {
434
+ border-radius: var(--matcha-radius-pill, 9999px);
435
+ box-shadow: 0 0 0 var(--matcha-border-thin, 2px) var(--matcha-tree-view-level-color, transparent);
436
+ }
437
+ }
438
+
439
+ // Textos: nome (label-medium) e linha secundária opcional (p-small, caption).
440
+ // Com linha secundária a row cresce pra 64px sozinha.
441
+ .matcha-tree-view-item__text {
442
+ flex: 1 1 auto;
443
+ min-width: 0;
444
+ display: flex;
445
+ flex-direction: column;
446
+ gap: var(--matcha-border-thin, 2px);
447
+ }
448
+
449
+ .matcha-tree-view-item__name {
450
+ display: block;
451
+ min-width: 0;
452
+ overflow: hidden;
453
+ text-overflow: ellipsis;
454
+ white-space: nowrap;
455
+ font-size: var(--matcha-text-label-md, 14px);
456
+ font-weight: var(--matcha-font-weight-medium, 500);
457
+ line-height: 20px;
458
+ color: var(--matcha-color-text-primary);
459
+ }
460
+
461
+ .matcha-tree-view-item__secondary {
462
+ display: block;
463
+ min-width: 0;
464
+ overflow: hidden;
465
+ text-overflow: ellipsis;
466
+ white-space: nowrap;
467
+ font-size: var(--matcha-text-body-sm, 12px);
468
+ line-height: 16px;
469
+ color: var(--matcha-color-text-muted);
470
+ }
471
+
472
+ // Meta (cargo + contadores). Cede ANTES do nome e, quando não cabe, sai de cena.
473
+ .matcha-tree-view-item__meta {
474
+ flex: 0 1 auto;
475
+ min-width: 0;
476
+ margin-inline-start: auto;
477
+ display: flex;
478
+ align-items: center;
479
+ gap: var(--matcha-space-100, 8px);
480
+ overflow: hidden;
481
+ color: var(--matcha-color-text-muted);
482
+ }
483
+
484
+ // Cargo é TEXTO, não pílula: pílula em toda linha é peso repetido 30 vezes na
485
+ // tela. Pílula (matcha-badge) fica pra ESTADO (Inativo, Pendente).
486
+ .matcha-tree-view-item__cargo {
487
+ flex: none;
488
+ font-size: var(--matcha-text-label-sm, 12px);
489
+ font-weight: var(--matcha-font-weight-medium, 500);
490
+ line-height: 16px;
491
+ color: var(--matcha-color-text-muted);
492
+ white-space: nowrap;
493
+ }
494
+
495
+ // Contadores: números tabulares (alinham à direita sem parecer relatório) e
496
+ // sem zero à esquerda — isso é do dado, não do CSS: "2 células", não "02".
497
+ .matcha-tree-view-item__counters {
498
+ flex: none;
499
+ display: inline-flex;
500
+ align-items: baseline;
501
+ gap: var(--matcha-space-050, 4px);
502
+ font-variant-numeric: tabular-nums;
503
+ white-space: nowrap;
504
+
505
+ strong {
506
+ font-size: var(--matcha-text-body-sm, 12px);
507
+ font-weight: var(--matcha-font-weight-medium, 500);
508
+ color: var(--matcha-color-text-primary);
509
+ }
510
+
511
+ small {
512
+ font-size: var(--matcha-text-p-tiny, 11px);
513
+ letter-spacing: 0.3px;
514
+ color: var(--matcha-color-text-muted);
515
+ }
516
+ }
517
+
518
+ // Só some quando não há mesmo onde caber. Entre 360 e 480 o flex encolhe o
519
+ // meta antes do nome.
520
+ @container matcha-tree-view (max-width: 360px) {
521
+ .matcha-tree-view-item__meta { display: none; }
522
+ }
523
+
524
+ @container matcha-tree-view (max-width: 480px) {
525
+ .matcha-tree-view-item__indent {
526
+ transform: scaleX(0.6);
527
+ transform-origin: left center;
528
+ }
529
+
530
+ .matcha-tree-view-item__row {
531
+ gap: var(--matcha-space-050, 4px);
532
+ min-height: 44px; // alvo de toque WCAG 2.5.5 em mobile
533
+ }
534
+ }
535
+
536
+ // ── Drag-and-drop (compõe com o motor do matcha-drop-list) ──────────────────
537
+ // Um alvo por vez: a árvore resolve o destino sob o cursor e pinta UMA coisa —
538
+ // Recebendo na pasta que vai receber, Recusado na linha que não aceita, ou a
539
+ // linha do Figma entre irmãos. As classes vêm do branch (estado da árvore).
540
+
541
+ // Dragging = o FANTASMA na origem, durante o arraste inteiro (Figma:
542
+ // opacity/disabled). Esmaece o bloco todo: a subárvore vai junto com o nó.
543
+ .matcha-tree-view .matcha-tree-view__node.is-dragging {
544
+ opacity: var(--matcha-opacity-disabled, 0.38);
545
+ }
546
+
547
+ // Durante o arraste o hover das linhas sai de cena: um fundo de hover sob o
548
+ // cursor parecia um segundo alvo ao lado do Recebendo, e o grip e o kebab
549
+ // revelados na linha de destino eram ruído (ela é destino, não alvo de clique).
550
+ .matcha-tree-view--dragging matcha-tree-view-item:not([disabled]):hover .matcha-tree-view-item__row {
551
+ background: transparent;
552
+ }
553
+
554
+ .matcha-tree-view--dragging matcha-tree-view-item:hover .matcha-tree-view-item__grip,
555
+ .matcha-tree-view--dragging matcha-tree-view-item:hover .matcha-tree-view-item__actions {
556
+ opacity: 0;
557
+ }
558
+
559
+ // Recebendo = a pasta que vai receber o item como filho: tinta accent + hairline
560
+ // accent. Mesma especificidade da regra acima e declarada depois: vence o hover
561
+ // suprimido e o selected.
562
+ .matcha-tree-view .matcha-tree-view__node.is-drop-into > matcha-tree-view-item .matcha-tree-view-item__row {
563
+ background: var(--matcha-color-accent-surface-hover, var(--matcha-color-accent-alpha));
564
+ box-shadow: inset 0 0 0 var(--matcha-border-hairline, 1px) var(--matcha-color-accent);
565
+ }
566
+
567
+ // Recusado = destino inválido (tipo ou profundidade), só na linha sob o cursor:
568
+ // tracejado danger de 2px (Figma: border/thin).
569
+ .matcha-tree-view .matcha-tree-view__node.is-drop-rejected > matcha-tree-view-item .matcha-tree-view-item__row {
570
+ outline: var(--matcha-border-thin, 2px) dashed var(--matcha-color-danger);
571
+ outline-offset: calc(-1 * var(--matcha-border-thin, 2px));
572
+ }
573
+
574
+ // Entre irmãos = a linha do Figma (matcha/tree-view/drop-indicator): 2px accent
575
+ // com uma bolinha no começo, na borda do nó e no recuo do nível dele.
576
+ .matcha-tree-view__drop-line {
577
+ position: absolute;
578
+ inset-inline: 0;
579
+ top: calc(-1 * var(--matcha-border-thin, 2px) / 2);
580
+ height: var(--matcha-border-thin, 2px);
581
+ border-radius: var(--matcha-radius-pill, 9999px);
582
+ background: var(--matcha-color-accent);
583
+ pointer-events: none;
584
+ z-index: 1;
585
+
586
+ &::before {
587
+ content: "";
588
+ position: absolute;
589
+ inset-inline-start: 0;
590
+ top: 50%;
591
+ width: var(--matcha-space-075, 6px);
592
+ height: var(--matcha-space-075, 6px);
593
+ border-radius: var(--matcha-radius-pill, 9999px);
594
+ background: var(--matcha-color-accent);
595
+ transform: translateY(-50%);
596
+ }
597
+
598
+ &--after {
599
+ top: auto;
600
+ bottom: calc(-1 * var(--matcha-border-thin, 2px) / 2);
601
+ }
602
+ }
603
+
604
+ // Levantado = a cópia que acompanha o cursor: SÓ a linha, com superfície e
605
+ // elevação level-2 — a sombra é da row, não da caixa do clone. Escopado no
606
+ // clone de nó da árvore: o ghost das listas planas segue com a opacidade e a
607
+ // sombra do drop-list.
608
+ .matcha-drag-ghost:has(> .matcha-tree-view__node) {
609
+ opacity: 1;
610
+ box-shadow: none;
611
+ border-radius: 0;
612
+ }
613
+
614
+ // O motor clona o wrapper inteiro (a subárvore junto); esconder os filhos no
615
+ // clone deixa a cópia do tamanho de uma linha.
616
+ .matcha-drag-ghost {
617
+ .matcha-tree-view__children-host { display: none; }
618
+
619
+ .matcha-tree-view-item__row {
620
+ background: var(--matcha-color-surface);
621
+ box-shadow: var(--matcha-shadow-2);
622
+ border-radius: var(--matcha-radius-md, 4px);
623
+ }
624
+
625
+ .matcha-tree-view-item__grip { opacity: 1; }
626
+ }
627
+
628
+ // Região do aria-live: só pra leitor de tela.
629
+ .matcha-tree-view__live {
630
+ position: absolute;
631
+ width: 1px;
632
+ height: 1px;
633
+ margin: -1px;
634
+ padding: 0;
635
+ overflow: hidden;
636
+ clip: rect(0 0 0 0);
637
+ white-space: nowrap;
638
+ border: 0;
639
+ }
640
+
641
+ // Respeita preferência de redução de movimento
642
+ @media (prefers-reduced-motion: reduce) {
643
+ matcha-tree-view-item,
644
+ matcha-tree-view-item:not(.matcha-drag-dragging),
645
+ .matcha-tree-view__children,
646
+ .matcha-tree-view-item__disclosure matcha-icon,
647
+ .matcha-tree-view-item__row,
648
+ .matcha-tree-view-item__grip,
649
+ .matcha-tree-view-item__actions {
650
+ animation: none !important;
651
+ transition: none !important;
652
+ }
653
+ }
654
+
655
+ // ── Theme mixin ─────────────────────────────────────────────────────────────
656
+ @mixin matcha-tree-view-theme($theme) {
657
+ // Tudo via CSS vars — sem theme-specific overrides.
658
+ }