@inchurch/matcha-theme 22.36.2 → 22.38.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -14,6 +14,29 @@
14
14
 
15
15
  @mixin matcha-file-uploader-theme($theme) {
16
16
 
17
+ // ── Shell (modo múltiplo: moldura única em volta de dropzone + lista) ──
18
+ // Recebe o mesmo tratamento visual da dropzone porque é ELE que passa a ser
19
+ // a "área de upload" quando a lista mora dentro — inclusive o realce de
20
+ // dragover, já que os handlers de drag vivem aqui.
21
+ .matcha-file-uploader-shell {
22
+ background: var(--matcha-color-surface-background, var(--matcha-color-surface-bg));
23
+ border-color: var(--matcha-color-surface-border);
24
+
25
+ &.matcha-file-uploader-dragover {
26
+ background: var(--matcha-color-accent-alpha);
27
+ border-color: var(--matcha-color-accent);
28
+ }
29
+
30
+ &.matcha-file-uploader-disabled {
31
+ opacity: 0.5;
32
+ // pointer-events + cursor default, não `not-allowed`: constraint #14 do
33
+ // INTERACTION-SYSTEM (o lint de CSS avisa). A dropzone legada abaixo ainda
34
+ // usa not-allowed — rastreado no backlog, fora do escopo desta mudança.
35
+ pointer-events: none;
36
+ cursor: default;
37
+ }
38
+ }
39
+
17
40
  // ── Dropzone ──
18
41
  .matcha-file-uploader-dropzone {
19
42
  background: var(--matcha-color-surface-background, var(--matcha-color-surface-bg));
@@ -29,6 +52,14 @@
29
52
  cursor: not-allowed;
30
53
  pointer-events: none;
31
54
  }
55
+
56
+ // Dentro do shell a moldura e o fundo são do shell — a dropzone é só a
57
+ // afordância de clique. Duas classes de propósito: precisa vencer o bloco
58
+ // acima, que tem a mesma especificidade.
59
+ &.matcha-file-uploader-dropzone--inset {
60
+ background: transparent;
61
+ border-color: transparent;
62
+ }
32
63
  }
33
64
 
34
65
  .matcha-file-uploader-dropzone__icon-pill {
@@ -94,8 +125,27 @@
94
125
  color: var(--matcha-color-text-primary);
95
126
  }
96
127
 
97
- &.matcha-file-uploader-file__action--delete:hover {
128
+ // Apagar é vermelho EM REPOUSO, não só no hover: remover arquivo é
129
+ // destrutivo e irreversível, e num modo múltiplo com vários itens
130
+ // empilhados a ação precisa ser distinguível antes de o ponteiro chegar
131
+ // nela (em touch não há hover nenhum). `danger` é papel, não hue —
132
+ // o tema pode remapear.
133
+ //
134
+ // `--matcha-icon-color` é obrigatório, e não redundante com o `color`: o
135
+ // matcha-icon resolve o glyph por `var(--matcha-icon-color, …-icon-default)`
136
+ // (matcha-icon.scss:97) e NÃO herda o `color` do pai. Era por isso que o
137
+ // vermelho antigo de hover nunca chegou a pintar a lixeira.
138
+ &.matcha-file-uploader-file__action--delete {
98
139
  color: var(--matcha-color-danger);
140
+ --matcha-icon-color: var(--matcha-color-danger);
141
+
142
+ // Fundo tinted em vez de surface-hover neutro, e a cor é reafirmada
143
+ // porque o :hover genérico acima empurraria text-primary.
144
+ &:hover {
145
+ background: var(--matcha-color-danger-alpha);
146
+ color: var(--matcha-color-danger);
147
+ --matcha-icon-color: var(--matcha-color-danger);
148
+ }
99
149
  }
100
150
  }
101
151
 
@@ -116,6 +166,15 @@
116
166
  &:hover {
117
167
  background: var(--matcha-color-surface-card);
118
168
  }
169
+
170
+ // Mesma regra do delete na linha. Aqui só o GLYPH vira danger: o fundo
171
+ // continua sendo a pastilha de surface-card, que é o que garante contraste
172
+ // do ícone sobre uma imagem qualquer — trocá-lo por danger-alpha (10%)
173
+ // deixaria o vermelho competir com a foto atrás.
174
+ &.matcha-file-uploader-card__action--delete {
175
+ color: var(--matcha-color-danger);
176
+ --matcha-icon-color: var(--matcha-color-danger);
177
+ }
119
178
  }
120
179
  }
121
180
 
@@ -137,6 +196,75 @@
137
196
  width: 100%;
138
197
  }
139
198
 
199
+ // ── Shell (modo múltiplo) ────────────────────────────────────────────────────
200
+ // A "área de upload" quando a lista mora dentro: uma moldura tracejada só,
201
+ // com a dropzone no topo e a lista rolável embaixo. Sem arquivo nenhum o
202
+ // resultado é visualmente idêntico à dropzone solta — só a moldura mudou de
203
+ // dono, do filho para o pai.
204
+ .matcha-file-uploader-shell {
205
+ display: flex;
206
+ flex-direction: column;
207
+ width: 100%;
208
+ box-sizing: border-box;
209
+ border: var(--matcha-border-thin, 2px) dashed transparent;
210
+ border-radius: var(--matcha-radius-lg, 8px);
211
+ overflow: hidden; // o radius precisa cortar a lista que rola por dentro
212
+ transition: background-color var(--matcha-duration-instant, 80ms) linear,
213
+ border-color var(--matcha-duration-instant, 80ms) linear;
214
+
215
+ // Classe de dimensionamento posta NO HOST tem que alcancar o shell — mesmo
216
+ // padrao (e mesmo racional) do matcha-grid, grid.component.scss:11-18. Sem
217
+ // isto, `<matcha-file-uploader class="h-400">` esticaria o host e deixaria o
218
+ // shell na altura do conteudo, e a area continuaria crescendo por dentro.
219
+ //
220
+ // `height: 100%` contra host de altura auto resolve pra `auto`: e no-op para
221
+ // quem nao define altura, portanto value-preserving nos usos existentes.
222
+ height: 100%;
223
+
224
+ // O foco visível é da dropzone interna (o elemento focável), não do shell.
225
+ &:focus-within {
226
+ outline: none;
227
+ }
228
+
229
+ // Com altura definida no host, e a DROPZONE que absorve a sobra: com 1 arquivo
230
+ // ela fica grande e a area nao tem buraco; conforme a lista cresce, cede
231
+ // espaco ate o proprio conteudo (pill + dois textos), que o min-height auto
232
+ // do flex protege de ser esmagado. Sem altura definida, nao ha sobra para
233
+ // distribuir e o resultado e o mesmo de antes.
234
+ .matcha-file-uploader-dropzone--inset {
235
+ flex: 1 1 auto;
236
+ }
237
+ }
238
+
239
+ // ── Lista de arquivos rolável (dentro do shell) ──────────────────────────────
240
+ // max-height em custom property com fallback, igual --matcha-panel-max-height
241
+ // (280px é o mesmo teto que select/autocomplete/panel já usam para "lista com
242
+ // mais conteúdo abaixo"). Passar `none` devolve o crescimento ilimitado antigo.
243
+ .matcha-file-uploader-list {
244
+ display: flex;
245
+ flex-direction: column;
246
+ gap: var(--matcha-space-100, 8px);
247
+ min-height: 0; // sem isso o floor de min-content impede o scroll no flex
248
+ // Pede o tamanho do conteudo e ENCOLHE quando falta espaco — e ai o scroll
249
+ // interno assume. E o que faz a lista caber quando o host tem altura definida
250
+ // e o teto de 280px seria maior do que sobrou.
251
+ flex: 0 1 auto;
252
+ max-height: var(--matcha-file-uploader-list-max-height, 280px);
253
+ overflow-y: auto;
254
+ overflow-x: hidden; // scrollbar vertical + nowrap gera barra horizontal fantasma
255
+ overscroll-behavior: contain; // o scroll não vaza pra página ao chegar no fim
256
+ -webkit-overflow-scrolling: touch;
257
+ padding: 0 var(--matcha-space-100, 8px) var(--matcha-space-100, 8px);
258
+ }
259
+
260
+ // Dentro da lista o espaçamento é do `gap` — o margin-top do item rolaria
261
+ // junto e daria um respiro fantasma no topo do scroll.
262
+ .matcha-file-uploader-list > .matcha-file-uploader-file,
263
+ .matcha-file-uploader-list > .matcha-file-uploader-card {
264
+ margin-top: 0;
265
+ }
266
+
267
+
140
268
  // ── Dropzone box (Estado=Dropzone — Figma 16152:209) — a zona INTEIRA é o alvo
141
269
  .matcha-file-uploader-dropzone {
142
270
  display: flex;
@@ -157,6 +285,24 @@
157
285
  }
158
286
  }
159
287
 
288
+ // Dropzone dentro do shell: sem moldura própria (é do shell) e sem o radius
289
+ // que arredondaria um canto interno. Mantém padding, cursor e foco.
290
+ // Precisa vir DEPOIS do bloco base: mesma especificidade (uma classe), então é
291
+ // a ordem que decide — declarado antes, o `border: 2px dashed` do base vencia e
292
+ // sobravam 2px de borda transparente dentro do shell.
293
+ .matcha-file-uploader-dropzone--inset {
294
+ border-width: 0;
295
+ border-radius: 0;
296
+
297
+ // Anel de foco PARA DENTRO. A dropzone inset ocupa a largura toda do shell,
298
+ // que tem `overflow: hidden` (o radius precisa cortar a lista rolável): com o
299
+ // `outline-offset: 2px` do bloco base o anel cai fora da caixa e é ceifado,
300
+ // deixando o alvo de teclado sem indicação visível nas laterais.
301
+ &:focus-visible {
302
+ outline-offset: -2px;
303
+ }
304
+ }
305
+
160
306
  // layout="card": dropzone vazio compartilha a proporção do card preenchido
161
307
  // (aspect-ratio aplicado inline via previewRatio) pra empty e filled terem a
162
308
  // MESMA altura lado a lado. Sem isso, vazio é dimensionado por padding/conteúdo
@@ -369,6 +515,14 @@
369
515
  width: 20px;
370
516
  height: 20px;
371
517
  }
518
+ // Com o uploader desabilitado a linha continua legivel, mas as acoes saem de
519
+ // operacao. `pointer-events: none` + `cursor: default` em vez de
520
+ // `not-allowed`: constraint #14 do INTERACTION-SYSTEM.
521
+ &:disabled {
522
+ opacity: var(--matcha-opacity-disabled, 0.38);
523
+ pointer-events: none;
524
+ cursor: default;
525
+ }
372
526
  }
373
527
 
374
528
  // ── Card layout — preview preenchido 16:9 + ações no hover (Estado=Drop filled) ──
@@ -429,6 +583,14 @@
429
583
  width: 18px;
430
584
  height: 18px;
431
585
  }
586
+
587
+ // Mesma regra da acao da linha: desabilitado sai de operacao sem virar
588
+ // `not-allowed` (constraint #14 do INTERACTION-SYSTEM).
589
+ &:disabled {
590
+ opacity: var(--matcha-opacity-disabled, 0.38);
591
+ pointer-events: none;
592
+ cursor: default;
593
+ }
432
594
  }
433
595
 
434
596
  // ── Cropper inline (modo crop: imagem única) ──────────────────────────────
@@ -464,6 +626,7 @@
464
626
 
465
627
  // ── Reduced motion ───────────────────────────────────────────────────────────
466
628
  @media (prefers-reduced-motion: reduce) {
629
+ .matcha-file-uploader-shell,
467
630
  .matcha-file-uploader-dropzone,
468
631
  .matcha-file-uploader-file__progress-fill,
469
632
  .matcha-file-uploader-file__action,
@@ -424,6 +424,33 @@
424
424
  --matcha-table-cell-bg: var(--matcha-table-row-bg-hover-accent);
425
425
  }
426
426
 
427
+ // O ALVO é a CÉLULA inteira, não só o texto do nome.
428
+ //
429
+ // A âncora envolve o nome, e em título curto isso vira um alvo de poucos pixels —
430
+ // reclamação de quem usa, medida em séries. O `::after` esticado resolve sem trocar
431
+ // a âncora por handler de clique: o href continua existindo, então ctrl+clique,
432
+ // clique do meio e "abrir em nova aba" seguem funcionando, e o foco de teclado
433
+ // continua sendo o do link.
434
+ //
435
+ // De quebra conserta o hover: a regra acima só pinta a linha quando o mouse está
436
+ // sobre o TEXTO. Com a área esticada, pinta ao entrar na célula — que é o que faz
437
+ // a linha parecer clicável.
438
+ //
439
+ // Escopado em `.matcha-table td` de propósito: `a[matcha-cell-link]` também aparece
440
+ // em card de listagem, fora de tabela, e lá o link deve seguir do tamanho do texto.
441
+ //
442
+ // O custo é a seleção de texto DENTRO desta célula. No resto da linha continua
443
+ // funcionando, que é a diferença para a linha toda clicável.
444
+ td:has(a[matcha-cell-link]) {
445
+ position: relative;
446
+ }
447
+
448
+ td a[matcha-cell-link]::after {
449
+ content: '';
450
+ position: absolute;
451
+ inset: 0;
452
+ }
453
+
427
454
  tbody tr.is-selected td {
428
455
  --matcha-table-cell-bg: var(--matcha-table-row-bg-selected);
429
456
  }
@@ -1,54 +1,195 @@
1
1
  // =============================================================================
2
- // matcha-tree-view.scss — Slot row indentado por nível hierárquico
3
- // Componente é um FRAME minimal (indent + estados). Consumer compõe o conteúdo
4
- // livre via ng-content. Responsivo via container queries.
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.
5
9
  // =============================================================================
6
10
 
7
- // ── Container opcional (qualquer wrapper .matcha-tree-view) ─────────────────
8
- // Provê: bg "tray" Figma + gap entre rows + propagação de gap dentro de drop-list.
11
+ // ── Container ───────────────────────────────────────────────────────────────
9
12
  .matcha-tree-view {
10
13
  display: flex;
11
14
  flex-direction: column;
12
- gap: var(--matcha-space-050, 4px);
13
- padding: var(--matcha-space-200, 16px);
14
- background: var(--matcha-color-surface-background);
15
- border-radius: var(--matcha-radius-lg, 8px);
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;
16
22
 
17
- // Container queries — base pra responsivo dos filhos
18
23
  container-type: inline-size;
19
24
  container-name: matcha-tree-view;
20
25
 
21
26
  .matcha-drop-list-container {
22
27
  display: flex;
23
28
  flex-direction: column;
24
- gap: var(--matcha-space-050, 4px);
29
+ gap: 0;
25
30
  }
26
31
  }
27
32
 
28
- // ── Container data-driven (matcha-tree-view) + branches recursivos ──────────
29
- // O host <matcha-tree-view> reusa a classe .matcha-tree-view acima (tray + gap).
30
- // Cada nível é um <matcha-tree-branch> (drop container); a indentação é por item
31
- // (via [level] do tree-view-item), então os wrappers NÃO adicionam indent.
32
33
  matcha-tree-branch,
33
34
  .matcha-tree-view__children {
34
35
  display: flex;
35
36
  flex-direction: column;
36
- gap: var(--matcha-space-050, 4px);
37
+ gap: 0;
37
38
  min-height: 2px; // alvo de drop mínimo quando o branch está vazio
38
39
  }
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) ─────────────────────────────────────────
40
147
  .matcha-tree-view__node {
41
148
  display: block;
149
+ outline: none;
42
150
  }
43
151
 
44
- // Feedback de rejeição na zona de reparenting (self-drop / tipo não aceito)
45
- .matcha-drop-zone-cannot-accept {
46
- outline: 2px dashed var(--matcha-color-danger, #e5484d);
47
- outline-offset: -2px;
48
- border-radius: var(--matcha-radius-md, 4px);
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;
49
190
  }
50
191
 
51
- // ── Item host — flex row com indent dinâmico ────────────────────────────────
192
+ // ── Item host ───────────────────────────────────────────────────────────────
52
193
  matcha-tree-view-item {
53
194
  display: flex;
54
195
  flex-direction: row;
@@ -57,195 +198,414 @@ matcha-tree-view-item {
57
198
  box-sizing: border-box;
58
199
  outline: none;
59
200
 
60
- // Disabled
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.
61
203
  &[disabled] {
62
- opacity: 0.5;
63
- pointer-events: none;
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; }
64
210
  }
65
211
 
66
- // Clickable
67
212
  &[clickable]:not([disabled]) {
68
213
  cursor: pointer;
69
214
 
70
215
  &:focus-visible .matcha-tree-view-item__row {
71
- outline: 2px solid var(--matcha-color-accent);
72
- outline-offset: -2px;
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);
73
236
  }
74
237
  }
75
238
  }
76
239
 
77
- // ── Indent (Nível 2+) — width vem inline do componente ──────────────────────
240
+ // ── Indent liso (fora do container) — width inline = (level-1) × indentStep ──
78
241
  .matcha-tree-view-item__indent {
79
- flex: none;
80
- // height auto — se ajusta ao row
81
- }
82
-
83
- // ── Guias de conector (modo organograma) — render quando [guides] é passado ──
84
- // Cada célula (largura = indentStep, inline) desenha a linha vertical do ancestral
85
- // (data-guide=line|tee) e/ou o cotovelo do nó (tee ├ / ell └). Linha via
86
- // --matcha-tree-view-guide-color (theme-aware, default = surface-border). As
87
- // verticais transbordam o padding-block da row (--_pad) p/ emendar entre rows —
88
- // use gap:0 no container quando quiser linhas 100% contínuas.
89
- .matcha-tree-view-item__guides {
90
- flex: none;
91
- align-self: stretch;
92
- display: flex;
93
- }
94
- .matcha-tree-view-item__guide {
95
- --_guide: var(--matcha-tree-view-guide-color, var(--matcha-color-surface-border));
96
- --_pad: var(--matcha-space-100, 8px);
97
- position: relative;
98
- flex: none;
99
-
100
- // Linha vertical no centro — 'line'/'tee' atravessam; 'ell' (último) para no centro.
101
- &[data-guide="line"]::before,
102
- &[data-guide="tee"]::before,
103
- &[data-guide="ell"]::before {
104
- content: "";
105
- position: absolute;
106
- left: 50%;
107
- top: calc(-1 * var(--_pad));
108
- width: 1px;
109
- background: var(--_guide);
110
- }
111
- &[data-guide="line"]::before,
112
- &[data-guide="tee"]::before { bottom: calc(-1 * var(--_pad)); }
113
- &[data-guide="ell"]::before { height: calc(50% + var(--_pad)); }
114
-
115
- // Cotovelo horizontal (centro → direita, na metade da altura) — 'tee'/'ell'.
116
- &[data-guide="tee"]::after,
117
- &[data-guide="ell"]::after {
118
- content: "";
119
- position: absolute;
120
- top: 50%;
121
- left: 50%;
122
- right: 0;
123
- height: 1px;
124
- background: var(--_guide);
125
- }
242
+ flex: none;
126
243
  }
127
244
 
128
- // ── Row — bg transparente por default; container .matcha-tree-view dá bg card
245
+ // ── Row ─────────────────────────────────────────────────────────────────────
129
246
  .matcha-tree-view-item__row {
247
+ position: relative; // contexto do pé da guia e da barra de seleção
130
248
  flex: 1;
131
249
  display: flex;
132
250
  flex-direction: row;
133
251
  align-items: center;
134
252
  gap: var(--matcha-space-100, 8px);
135
253
  min-height: 48px;
136
- padding: var(--matcha-space-100, 8px) var(--matcha-space-150, 12px);
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;
137
257
  background: transparent;
138
- border-bottom: 1px solid var(--matcha-color-surface-border);
139
258
  border-radius: var(--matcha-radius-md, 4px);
140
259
  box-sizing: border-box;
141
260
  min-width: 0;
142
261
  transition: background-color var(--matcha-duration-instant, 80ms) ease;
262
+ flex-wrap: var(--matcha-tree-view-item-wrap, nowrap);
263
+ }
143
264
 
144
- // Permitir conteúdo wrap se consumer quiser
145
- flex-wrap: var(--matcha-tree-view-item-wrap, nowrap);
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);
146
270
  }
147
271
 
148
- // Hover sutil na row
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.
149
274
  matcha-tree-view-item:not([disabled]):hover .matcha-tree-view-item__row {
150
275
  background: var(--matcha-color-surface-hover);
151
276
  }
152
277
 
153
- // ── Estilos comuns dos slots opcionais (CSS classes utilitárias do DS) ─────
154
- // Consumer aplica esses classes nos elementos projetados; o componente NÃO impõe.
155
- // .matcha-tree-view-item__grip — aplicado automaticamente pela diretiva matchaTreeViewGrip.
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.
156
288
  .matcha-tree-view-item__grip {
157
- flex: none;
158
- display: inline-flex;
159
- align-items: center;
160
- justify-content: center;
161
- width: 24px;
162
- height: 24px;
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);
163
295
  --matcha-icon-color: var(--matcha-color-text-muted);
164
- cursor: grab;
165
- transition: --matcha-icon-color var(--matcha-duration-instant, 80ms) ease;
296
+ cursor: grab;
297
+ opacity: 0;
298
+ transition: opacity var(--matcha-duration-instant, 80ms) ease;
166
299
 
167
- &:hover { --matcha-icon-color: var(--matcha-color-text-primary); }
168
300
  &:active { cursor: grabbing; }
169
301
  }
170
302
 
171
- // Dentro do container canon (.matcha-tree-view), row ganha bg "card on tray" (Figma)
172
- .matcha-tree-view matcha-tree-view-item:not([disabled]) .matcha-tree-view-item__row {
173
- background: var(--matcha-color-surface-card);
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;
174
313
  }
175
- .matcha-tree-view matcha-tree-view-item:not([disabled]):hover .matcha-tree-view-item__row {
176
- background: var(--matcha-color-surface-card-strong, var(--matcha-color-surface-card));
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;
177
323
  }
178
324
 
179
- // ── DnD states (compõe com matcha-drop-list) ────────────────────────────────
180
- .matcha-drag-item.matcha-drag-dragging {
181
- opacity: 0.35;
325
+ // Em ponteiro grosso (toque) não existe hover: grip e ações ficam visíveis.
326
+ @media (hover: none) {
327
+ .matcha-tree-view-item__grip,
328
+ .matcha-tree-view-item__actions { opacity: 1; }
329
+ }
182
330
 
183
- .matcha-tree-view-item__row { background: var(--matcha-color-surface-hover); }
331
+ // Navegar (›): o trailing do drill-down mobile. Sempre visível; substitui as
332
+ // ações quando a linha inteira navega.
333
+ .matcha-tree-view-item__navigate {
334
+ flex: none;
335
+ display: inline-flex;
336
+ align-items: center;
337
+ justify-content: center;
338
+ width: var(--matcha-tree-view-control-size, 32px);
339
+ height: var(--matcha-tree-view-control-size, 32px);
340
+ --matcha-icon-color: var(--matcha-color-text-muted);
184
341
  }
185
342
 
186
- .matcha-tree-view .matcha-drop-list-placeholder {
187
- height: 4px;
188
- margin: var(--matcha-space-050, 4px) 0;
189
- background: var(--matcha-color-accent);
190
- border-radius: var(--matcha-radius-sm, 2px);
191
- opacity: 0.85;
192
- box-shadow: 0 0 0 2px var(--matcha-color-accent-alpha, rgba(168, 217, 78, 0.2));
193
- animation: matcha-tree-view-pulse 800ms ease-in-out infinite alternate;
343
+ // Disclosure: 32px, reserva o slot mesmo na folha (use a classe num <span>
344
+ // vazio) pra a identidade alinhar entre irmãos. Um único chevron-right que o
345
+ // tema gira em 150ms quando o item está [expanded]; caption em repouso, texto
346
+ // no hover/focus.
347
+ matcha-tree-view-item .matcha-tree-view-item__disclosure {
348
+ flex: none;
349
+ display: inline-flex;
350
+ align-items: center;
351
+ justify-content: center;
352
+ width: var(--matcha-tree-view-control-size, 32px);
353
+ height: var(--matcha-tree-view-control-size, 32px);
354
+ --matcha-icon-color: var(--matcha-color-text-muted);
355
+
356
+ matcha-icon {
357
+ transition: transform 150ms var(--matcha-easing-standard, ease);
358
+ }
194
359
  }
195
360
 
196
- @keyframes matcha-tree-view-pulse {
197
- from { opacity: 0.7; }
198
- to { opacity: 1; }
361
+ matcha-tree-view-item[expanded] .matcha-tree-view-item__disclosure matcha-icon {
362
+ transform: rotate(90deg);
199
363
  }
200
364
 
201
- .matcha-tree-view .matcha-drop-list-empty-placeholder {
365
+ matcha-tree-view-item:hover .matcha-tree-view-item__disclosure,
366
+ matcha-tree-view-item:focus-within .matcha-tree-view-item__disclosure,
367
+ .matcha-tree-view__node:focus-visible > matcha-tree-view-item .matcha-tree-view-item__disclosure {
368
+ --matcha-icon-color: var(--matcha-color-text-primary);
369
+ }
370
+
371
+ // Identidade (dot|avatar + textos). Fica com o espaço que sobra e é a ÚLTIMA a
372
+ // ceder: sem isso o flex encolhe na ordem do DOM e, em tela estreita, o NOME
373
+ // chegava a zero enquanto cargo e contador ficavam intactos.
374
+ .matcha-tree-view-item__identity {
375
+ flex: 1 1 auto;
376
+ min-width: 4ch; // piso: sempre sobra o começo do nome
377
+ display: flex;
378
+ align-items: center;
379
+ gap: var(--matcha-space-100, 8px);
380
+ // SEM overflow:hidden. Quem trunca é o texto (min-width:0 + text-overflow
381
+ // no __name/__secondary), e recortar aqui comia os 2px do anel de nível do
382
+ // avatar — que ficava com as beiradas retas — e comeria também o anel de
383
+ // foco de qualquer controle projetado na identidade.
384
+ overflow: visible;
385
+
386
+ > * { min-width: 0; }
387
+ }
388
+
389
+ // Cor de nível: no dot (6px + anel a 20%) ou no anel do avatar. O consumer
390
+ // informa a cor em --matcha-tree-view-level-color; sem ela, herda o texto.
391
+ .matcha-tree-view-item__dot {
392
+ flex: none;
393
+ width: 6px;
394
+ height: 6px;
395
+ margin: var(--matcha-border-thin, 2px);
396
+ border-radius: var(--matcha-radius-pill, 9999px);
397
+ background: var(--matcha-tree-view-level-color, currentColor);
398
+ box-shadow: 0 0 0 var(--matcha-border-thin, 2px)
399
+ color-mix(in srgb, var(--matcha-tree-view-level-color, currentColor) 20%, transparent);
400
+ }
401
+
402
+ .matcha-tree-view-item__avatar {
403
+ flex: none;
404
+ display: inline-flex;
405
+
406
+ .matcha-avatar {
407
+ border-radius: var(--matcha-radius-pill, 9999px);
408
+ box-shadow: 0 0 0 var(--matcha-border-thin, 2px) var(--matcha-tree-view-level-color, transparent);
409
+ }
410
+ }
411
+
412
+ // Textos: nome (label-medium) e linha secundária opcional (p-small, caption).
413
+ // Com linha secundária a row cresce pra 64px sozinha.
414
+ .matcha-tree-view-item__text {
415
+ flex: 1 1 auto;
416
+ min-width: 0;
202
417
  display: flex;
203
- align-items: center;
204
- justify-content: center;
205
- padding: var(--matcha-space-400, 32px);
206
- font-size: var(--matcha-text-body-sm, 12px);
207
- color: var(--matcha-color-text-muted);
208
- border: 2px dashed var(--matcha-color-surface-border);
209
- border-radius: var(--matcha-radius-md, 4px);
210
- background: transparent;
418
+ flex-direction: column;
419
+ gap: var(--matcha-border-thin, 2px);
211
420
  }
212
421
 
213
- .matcha-drag-item.matcha-drag-dragging .matcha-tree-view-item__grip { cursor: grabbing; }
422
+ .matcha-tree-view-item__name {
423
+ display: block;
424
+ min-width: 0;
425
+ overflow: hidden;
426
+ text-overflow: ellipsis;
427
+ white-space: nowrap;
428
+ font-size: var(--matcha-text-label-md, 14px);
429
+ font-weight: var(--matcha-font-weight-medium, 500);
430
+ line-height: 20px;
431
+ color: var(--matcha-color-text-primary);
432
+ }
214
433
 
215
- // ── Entrance animation ──────────────────────────────────────────────────────
216
- matcha-tree-view-item:not(.matcha-drag-dragging) {
217
- animation: matcha-tree-view-item-in 220ms cubic-bezier(0.4, 0, 0.2, 1) both;
434
+ .matcha-tree-view-item__secondary {
435
+ display: block;
436
+ min-width: 0;
437
+ overflow: hidden;
438
+ text-overflow: ellipsis;
439
+ white-space: nowrap;
440
+ font-size: var(--matcha-text-body-sm, 12px);
441
+ line-height: 16px;
442
+ color: var(--matcha-color-text-muted);
218
443
  }
219
444
 
220
- @keyframes matcha-tree-view-item-in {
221
- from { opacity: 0; transform: translateY(-4px); }
222
- to { opacity: 1; transform: translateY(0); }
445
+ // Meta (cargo + contadores). Cede ANTES do nome e, quando não cabe, sai de cena.
446
+ .matcha-tree-view-item__meta {
447
+ flex: 0 1 auto;
448
+ min-width: 0;
449
+ margin-inline-start: auto;
450
+ display: flex;
451
+ align-items: center;
452
+ gap: var(--matcha-space-100, 8px);
453
+ overflow: hidden;
454
+ color: var(--matcha-color-text-muted);
455
+ }
456
+
457
+ // Cargo é TEXTO, não pílula: pílula em toda linha é peso repetido 30 vezes na
458
+ // tela. Pílula (matcha-badge) fica pra ESTADO (Inativo, Pendente).
459
+ .matcha-tree-view-item__cargo {
460
+ flex: none;
461
+ font-size: var(--matcha-text-label-sm, 12px);
462
+ font-weight: var(--matcha-font-weight-medium, 500);
463
+ line-height: 16px;
464
+ color: var(--matcha-color-text-muted);
465
+ white-space: nowrap;
466
+ }
467
+
468
+ // Contadores: números tabulares (alinham à direita sem parecer relatório) e
469
+ // sem zero à esquerda — isso é do dado, não do CSS: "2 células", não "02".
470
+ .matcha-tree-view-item__counters {
471
+ flex: none;
472
+ display: inline-flex;
473
+ align-items: baseline;
474
+ gap: var(--matcha-space-050, 4px);
475
+ font-variant-numeric: tabular-nums;
476
+ white-space: nowrap;
477
+
478
+ strong {
479
+ font-size: var(--matcha-text-body-sm, 12px);
480
+ font-weight: var(--matcha-font-weight-medium, 500);
481
+ color: var(--matcha-color-text-primary);
482
+ }
483
+
484
+ small {
485
+ font-size: var(--matcha-text-p-tiny, 11px);
486
+ letter-spacing: 0.3px;
487
+ color: var(--matcha-color-text-muted);
488
+ }
489
+ }
490
+
491
+ // Só some quando não há mesmo onde caber. Entre 360 e 480 o flex encolhe o
492
+ // meta antes do nome.
493
+ @container matcha-tree-view (max-width: 360px) {
494
+ .matcha-tree-view-item__meta { display: none; }
223
495
  }
224
496
 
225
- // ── Responsividade — container query baseada no .matcha-tree-view container
226
- // Em containers estreitos (< 480px), reduz indent visual pra preservar espaço útil.
227
- // Indent visual = padding-left implícito via --matcha-tree-view-item-indent setado
228
- // inline pelo componente. Container query NÃO consegue overridar inline style
229
- // diretamente, então usamos uma estratégia diferente: scale do indent div.
230
497
  @container matcha-tree-view (max-width: 480px) {
231
498
  .matcha-tree-view-item__indent {
232
- // Reduz 50% do width inline — preserva indent visual sem perder hierarquia
233
499
  transform: scaleX(0.6);
234
500
  transform-origin: left center;
235
501
  }
236
502
 
237
503
  .matcha-tree-view-item__row {
238
504
  gap: var(--matcha-space-050, 4px);
239
- padding: var(--matcha-space-100, 8px);
240
- min-height: 44px; // touch target WCAG 2.5.5 em mobile
505
+ min-height: 44px; // alvo de toque WCAG 2.5.5 em mobile
506
+ }
507
+ }
508
+
509
+ // ── Drag-and-drop (compõe com o motor do matcha-drop-list) ──────────────────
510
+
511
+ // Dragging = o FANTASMA na origem. O motor do drop-list aplica isso INLINE no
512
+ // wrapper arrastado (opacidade + translate dos irmãos) — não há classe pra
513
+ // estilizar aqui; o que o tema garante é que o wrapper não ganhe fundo, sombra
514
+ // ou escala de "card solto" (ver as regras do wrapper acima).
515
+
516
+ // Levantado = a cópia que acompanha o cursor: SÓ a linha, com superfície e
517
+ // elevação level-2. O motor clona o wrapper inteiro (a subárvore junto);
518
+ // esconder os filhos no clone deixa a cópia do tamanho de uma linha.
519
+ .matcha-drag-ghost {
520
+ box-shadow: none; // a elevação é da row, não da caixa do clone
521
+
522
+ .matcha-tree-view__children-host { display: none; }
523
+
524
+ .matcha-tree-view-item__row {
525
+ background: var(--matcha-color-surface);
526
+ box-shadow: var(--matcha-shadow-2);
527
+ border-radius: var(--matcha-radius-md, 4px);
241
528
  }
529
+
530
+ .matcha-tree-view-item__grip { opacity: 1; }
531
+ }
532
+
533
+ // Região do aria-live: só pra leitor de tela.
534
+ .matcha-tree-view__live {
535
+ position: absolute;
536
+ width: 1px;
537
+ height: 1px;
538
+ margin: -1px;
539
+ padding: 0;
540
+ overflow: hidden;
541
+ clip: rect(0 0 0 0);
542
+ white-space: nowrap;
543
+ border: 0;
544
+ }
545
+
546
+ // Recebendo = o PAI que vai receber o drop dentro: tinta accent + hairline
547
+ // accent na linha dele. O motor marca o branch dos filhos; a linha do pai é a
548
+ // irmã anterior do bloco, daí o :has() com filhos diretos.
549
+ .matcha-tree-view .matcha-tree-view__node:has(
550
+ > .matcha-tree-view__children-host > .matcha-tree-view__children > matcha-tree-branch.matcha-drop-list-receiving
551
+ ) > matcha-tree-view-item .matcha-tree-view-item__row {
552
+ background: var(--matcha-color-accent-surface-hover, var(--matcha-color-accent-alpha));
553
+ box-shadow: inset 0 0 0 var(--matcha-border-hairline, 1px) var(--matcha-color-accent);
554
+ }
555
+
556
+ // Recusado = destino inválido por TIPO: tracejado danger na linha do pai. A
557
+ // zona em si não ganha moldura, e a subárvore de quem está sendo arrastado
558
+ // (.matcha-drop-zone-self) não é pintada: rejeitar a si mesmo é óbvio.
559
+ .matcha-tree-view .matcha-tree-view__node:has(
560
+ > .matcha-tree-view__children-host > .matcha-drop-zone-cannot-accept:not(.matcha-drop-zone-self)
561
+ ) > matcha-tree-view-item .matcha-tree-view-item__row {
562
+ outline: var(--matcha-border-hairline, 1px) dashed var(--matcha-color-danger);
563
+ outline-offset: calc(-1 * var(--matcha-border-hairline, 1px));
564
+ }
565
+
566
+ // A moldura listrada/tracejada que o drop-list dá à zona não vale na árvore.
567
+ .matcha-tree-view .matcha-tree-view__children.matcha-drop-zone-cannot-accept {
568
+ outline: none;
569
+ background: transparent;
570
+ border: 0;
571
+ }
572
+
573
+ // O branch NÃO herda a moldura listrada do drop-list plano.
574
+ .matcha-tree-view matcha-tree-branch.matcha-drop-list-receiving,
575
+ .matcha-tree-view matcha-tree-branch.matcha-drop-list-can-accept,
576
+ .matcha-tree-view matcha-tree-branch.matcha-drop-list-cannot-accept {
577
+ background: transparent;
578
+ border: 0;
579
+ padding: 0;
580
+
581
+ &::before { content: none; }
582
+ }
583
+
584
+ // Entre irmãos NÃO há linha indicadora: o motor abre o espaço do item arrastado
585
+ // (translateY nos irmãos, 150ms) e deixa o fantasma na origem. É o "indicador"
586
+ // do código; o bloco drop-indicator do Figma é a representação estática disso.
587
+
588
+ // Alvo "Solte aqui" quando o pai ainda não tem filhos.
589
+ .matcha-tree-view .matcha-drop-list-empty-placeholder {
590
+ display: flex;
591
+ align-items: center;
592
+ justify-content: center;
593
+ min-height: 48px;
594
+ padding: var(--matcha-space-150, 12px);
595
+ font-size: var(--matcha-text-body-sm, 12px);
596
+ color: var(--matcha-color-text-muted);
597
+ border: var(--matcha-border-hairline, 1px) dashed var(--matcha-color-surface-border);
598
+ border-radius: var(--matcha-radius-md, 4px);
599
+ background: transparent;
242
600
  }
243
601
 
244
602
  // Respeita preferência de redução de movimento
245
603
  @media (prefers-reduced-motion: reduce) {
246
- matcha-tree-view-item,
247
- matcha-tree-view-item:not(.matcha-drag-dragging),
248
- .matcha-tree-view .matcha-drop-list-placeholder {
604
+ .matcha-tree-view__children,
605
+ .matcha-tree-view-item__disclosure matcha-icon,
606
+ .matcha-tree-view-item__row,
607
+ .matcha-tree-view-item__grip,
608
+ .matcha-tree-view-item__actions {
249
609
  animation: none !important;
250
610
  transition: none !important;
251
611
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@inchurch/matcha-theme",
3
- "version": "22.36.2",
3
+ "version": "22.38.0",
4
4
  "description": "Themes for matcha-design-system",
5
5
  "main": "main.scss",
6
6
  "scripts": {