@inchurch/matcha-theme 22.37.0 → 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.
@@ -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.37.0",
3
+ "version": "22.38.0",
4
4
  "description": "Themes for matcha-design-system",
5
5
  "main": "main.scss",
6
6
  "scripts": {