@inchurch/matcha-theme 22.38.2 → 22.38.4

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