@snksergio/design-system 0.62.0 → 0.64.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (149) hide show
  1. package/dist-lib/ai/blocos/chart/budget-breakdown.tsx +174 -0
  2. package/dist-lib/ai/blocos/indice.md +43 -0
  3. package/dist-lib/ai/blocos/paneldetail/detalhe-com-tabela.tsx +450 -0
  4. package/dist-lib/ai/blocos/paneldetail/detalhe-de-tarefa-com-abas.tsx +570 -0
  5. package/dist-lib/ai/blocos/paneldetail/detalhe-do-registro.tsx +555 -0
  6. package/dist-lib/ai/componentes/DataTable.md +2 -1
  7. package/dist-lib/ai/componentes/TableToolbar.md +1 -1
  8. package/dist-lib/ai/exemplos/app-shell/app-shell-example.tsx +140 -0
  9. package/dist-lib/ai/exemplos/app-shell/index.ts +3 -0
  10. package/dist-lib/ai/exemplos/app-shell/nav-data.ts +97 -0
  11. package/dist-lib/ai/exemplos/app-shell/routes.tsx +75 -0
  12. package/dist-lib/ai/exemplos/chat/chat-screen.tsx +152 -0
  13. package/dist-lib/ai/exemplos/chat/chat-v2-mocks.ts +171 -0
  14. package/dist-lib/ai/exemplos/chat/chat-v2.styles.ts +23 -0
  15. package/dist-lib/ai/exemplos/chat/chat-v2.types.ts +81 -0
  16. package/dist-lib/ai/exemplos/chat/components/ChannelDot/channel-dot.tsx +28 -0
  17. package/dist-lib/ai/exemplos/chat/components/ConversationActionsMenu/conversation-actions-menu.tsx +83 -0
  18. package/dist-lib/ai/exemplos/chat/components/ConversationActionsMenu/index.ts +4 -0
  19. package/dist-lib/ai/exemplos/chat/components/ConversationColumn/conversation-column.styles.ts +22 -0
  20. package/dist-lib/ai/exemplos/chat/components/ConversationColumn/conversation-column.tsx +203 -0
  21. package/dist-lib/ai/exemplos/chat/components/ConversationColumn/conversation-column.types.ts +10 -0
  22. package/dist-lib/ai/exemplos/chat/components/ConversationColumn/index.ts +2 -0
  23. package/dist-lib/ai/exemplos/chat/components/ConversationListItem/conversation-list-item.styles.ts +55 -0
  24. package/dist-lib/ai/exemplos/chat/components/ConversationListItem/conversation-list-item.tsx +52 -0
  25. package/dist-lib/ai/exemplos/chat/components/ConversationListItem/conversation-list-item.types.ts +7 -0
  26. package/dist-lib/ai/exemplos/chat/components/ConversationListItem/index.ts +2 -0
  27. package/dist-lib/ai/exemplos/chat/components/DateSeparator/date-separator.tsx +18 -0
  28. package/dist-lib/ai/exemplos/chat/components/DetailField/detail-field.tsx +23 -0
  29. package/dist-lib/ai/exemplos/chat/components/DetailSection/detail-section.tsx +41 -0
  30. package/dist-lib/ai/exemplos/chat/components/DetailSection/index.ts +1 -0
  31. package/dist-lib/ai/exemplos/chat/components/DetailsColumn/details-column.styles.ts +30 -0
  32. package/dist-lib/ai/exemplos/chat/components/DetailsColumn/details-column.tsx +142 -0
  33. package/dist-lib/ai/exemplos/chat/components/DetailsColumn/details-column.types.ts +16 -0
  34. package/dist-lib/ai/exemplos/chat/components/DetailsColumn/index.ts +5 -0
  35. package/dist-lib/ai/exemplos/chat/components/FilterRow/filter-row.styles.ts +37 -0
  36. package/dist-lib/ai/exemplos/chat/components/FilterRow/filter-row.tsx +45 -0
  37. package/dist-lib/ai/exemplos/chat/components/FilterRow/index.ts +1 -0
  38. package/dist-lib/ai/exemplos/chat/components/FiltersColumn/filters-column.styles.ts +27 -0
  39. package/dist-lib/ai/exemplos/chat/components/FiltersColumn/filters-column.tsx +66 -0
  40. package/dist-lib/ai/exemplos/chat/components/FiltersColumn/filters-column.types.ts +13 -0
  41. package/dist-lib/ai/exemplos/chat/components/FiltersColumn/filters-rail.tsx +38 -0
  42. package/dist-lib/ai/exemplos/chat/components/FiltersColumn/index.ts +6 -0
  43. package/dist-lib/ai/exemplos/chat/components/MessageBubble/index.ts +2 -0
  44. package/dist-lib/ai/exemplos/chat/components/MessageBubble/message-bubble.styles.ts +37 -0
  45. package/dist-lib/ai/exemplos/chat/components/MessageBubble/message-bubble.tsx +29 -0
  46. package/dist-lib/ai/exemplos/chat/components/MessageBubble/message-bubble.types.ts +5 -0
  47. package/dist-lib/ai/exemplos/chat/components/PersonAvatar/index.ts +5 -0
  48. package/dist-lib/ai/exemplos/chat/components/PersonAvatar/person-avatar.tsx +31 -0
  49. package/dist-lib/ai/exemplos/chat/components/QueueColumn/index.ts +2 -0
  50. package/dist-lib/ai/exemplos/chat/components/QueueColumn/queue-column.styles.ts +19 -0
  51. package/dist-lib/ai/exemplos/chat/components/QueueColumn/queue-column.tsx +140 -0
  52. package/dist-lib/ai/exemplos/chat/components/QueueColumn/queue-column.types.ts +13 -0
  53. package/dist-lib/ai/exemplos/chat/components/RailItem/index.ts +1 -0
  54. package/dist-lib/ai/exemplos/chat/components/RailItem/rail-item.styles.ts +30 -0
  55. package/dist-lib/ai/exemplos/chat/components/RailItem/rail-item.tsx +42 -0
  56. package/dist-lib/ai/exemplos/chat/hooks/use-resizable.ts +98 -0
  57. package/dist-lib/ai/exemplos/chat/index.ts +1 -0
  58. package/dist-lib/ai/exemplos/clientes/_table-data.ts +59 -0
  59. package/dist-lib/ai/exemplos/clientes/clientes-screen.tsx +505 -0
  60. package/dist-lib/ai/exemplos/clientes/clientes-showcase-mocks.ts +117 -0
  61. package/dist-lib/ai/exemplos/clientes/clientes-showcase.styles.ts +13 -0
  62. package/dist-lib/ai/exemplos/clientes/clientes-showcase.types.ts +16 -0
  63. package/dist-lib/ai/exemplos/clientes/components/DetailDrawer/detail-drawer.styles.ts +28 -0
  64. package/dist-lib/ai/exemplos/clientes/components/DetailDrawer/detail-drawer.tsx +303 -0
  65. package/dist-lib/ai/exemplos/clientes/components/DetailDrawer/detail-drawer.types.ts +14 -0
  66. package/dist-lib/ai/exemplos/clientes/components/DetailDrawer/index.ts +2 -0
  67. package/dist-lib/ai/exemplos/clientes/components/NovoClienteDrawer/index.ts +2 -0
  68. package/dist-lib/ai/exemplos/clientes/components/NovoClienteDrawer/novo-cliente-drawer.tsx +207 -0
  69. package/dist-lib/ai/exemplos/clientes/index.ts +1 -0
  70. package/dist-lib/ai/exemplos/edit-page/components/StepNav.tsx +81 -0
  71. package/dist-lib/ai/exemplos/edit-page/components/section-card.tsx +85 -0
  72. package/dist-lib/ai/exemplos/edit-page/edit-page-screen.tsx +234 -0
  73. package/dist-lib/ai/exemplos/edit-page/index.ts +1 -0
  74. package/dist-lib/ai/exemplos/finance/_table-data.ts +57 -0
  75. package/dist-lib/ai/exemplos/finance/clientes-financeiro-mocks.ts +227 -0
  76. package/dist-lib/ai/exemplos/finance/clientes-financeiro.types.ts +75 -0
  77. package/dist-lib/ai/exemplos/finance/clientes-showcase-mocks.ts +117 -0
  78. package/dist-lib/ai/exemplos/finance/clientes-showcase.styles.ts +13 -0
  79. package/dist-lib/ai/exemplos/finance/clientes-showcase.types.ts +16 -0
  80. package/dist-lib/ai/exemplos/finance/components/EditarFinanceDrawer/editar-finance-drawer.tsx +241 -0
  81. package/dist-lib/ai/exemplos/finance/components/EditarFinanceDrawer/index.ts +5 -0
  82. package/dist-lib/ai/exemplos/finance/components/ExtratoExpansion/extrato-expansion.tsx +172 -0
  83. package/dist-lib/ai/exemplos/finance/components/ExtratoExpansion/index.ts +1 -0
  84. package/dist-lib/ai/exemplos/finance/components/FinanceDetailPanel/finance-detail-panel.tsx +241 -0
  85. package/dist-lib/ai/exemplos/finance/components/FinanceDetailPanel/index.ts +2 -0
  86. package/dist-lib/ai/exemplos/finance/components/NovoClienteDrawer/index.ts +2 -0
  87. package/dist-lib/ai/exemplos/finance/components/NovoClienteDrawer/novo-cliente-drawer.tsx +207 -0
  88. package/dist-lib/ai/exemplos/finance/components/SacarDialog/index.ts +2 -0
  89. package/dist-lib/ai/exemplos/finance/components/SacarDialog/sacar-dialog.tsx +346 -0
  90. package/dist-lib/ai/exemplos/finance/finance-screen.tsx +821 -0
  91. package/dist-lib/ai/exemplos/finance/index.ts +1 -0
  92. package/dist-lib/ai/exemplos/gantt/_gantt-data.tsx +402 -0
  93. package/dist-lib/ai/exemplos/gantt/gantt-screen.tsx +512 -0
  94. package/dist-lib/ai/exemplos/gantt/index.ts +1 -0
  95. package/dist-lib/ai/exemplos/login/index.ts +1 -0
  96. package/dist-lib/ai/exemplos/login/login-screen.tsx +246 -0
  97. package/dist-lib/ai/exemplos/mapa-rede/components/ConsultorDetailPanel/consultor-detail-panel.tsx +158 -0
  98. package/dist-lib/ai/exemplos/mapa-rede/components/ConsultorDetailPanel/index.ts +2 -0
  99. package/dist-lib/ai/exemplos/mapa-rede/index.ts +1 -0
  100. package/dist-lib/ai/exemplos/mapa-rede/mapa-de-rede-mocks.ts +655 -0
  101. package/dist-lib/ai/exemplos/mapa-rede/mapa-de-rede.types.ts +53 -0
  102. package/dist-lib/ai/exemplos/mapa-rede/mapa-rede-screen.tsx +227 -0
  103. package/dist-lib/ai/exemplos/order-detail/components/ActivityTab.tsx +77 -0
  104. package/dist-lib/ai/exemplos/order-detail/components/AttachmentsTab.tsx +45 -0
  105. package/dist-lib/ai/exemplos/order-detail/components/CommentsTab.tsx +111 -0
  106. package/dist-lib/ai/exemplos/order-detail/components/DetailsTab.tsx +189 -0
  107. package/dist-lib/ai/exemplos/order-detail/components/OverviewTab.tsx +200 -0
  108. package/dist-lib/ai/exemplos/order-detail/components/section-card.tsx +85 -0
  109. package/dist-lib/ai/exemplos/order-detail/index.ts +1 -0
  110. package/dist-lib/ai/exemplos/order-detail/order-detail-screen.tsx +119 -0
  111. package/dist-lib/ai/exemplos/order-detail/order-mocks.ts +186 -0
  112. package/dist-lib/ai/exemplos/order-detail/order.types.ts +118 -0
  113. package/dist-lib/ai/global/componentes.md +7 -0
  114. package/dist-lib/ai/indice.json +30 -15
  115. package/dist-lib/ai/manifest.json +32 -6
  116. package/dist-lib/ai/roteiros/app-builder/roteiro.md +155 -0
  117. package/dist-lib/ai/roteiros/auth-builder/roteiro.md +42 -0
  118. package/dist-lib/ai/roteiros/cards/roteiro.md +34 -0
  119. package/dist-lib/ai/roteiros/charts/roteiro.md +32 -0
  120. package/dist-lib/ai/roteiros/chat/roteiro.md +31 -0
  121. package/dist-lib/ai/roteiros/crud-builder/blueprint.md +63 -0
  122. package/dist-lib/ai/roteiros/crud-builder/entrevista.md +146 -0
  123. package/dist-lib/ai/roteiros/crud-builder/geracao.md +113 -0
  124. package/dist-lib/ai/roteiros/crud-builder/roteiro.md +89 -0
  125. package/dist-lib/ai/roteiros/drawers/roteiro.md +41 -0
  126. package/dist-lib/ai/roteiros/list-builder/blueprint.md +94 -0
  127. package/dist-lib/ai/roteiros/list-builder/entrevista.md +193 -0
  128. package/dist-lib/ai/roteiros/list-builder/geracao.md +63 -0
  129. package/dist-lib/ai/roteiros/list-builder/roteiro.md +91 -0
  130. package/dist-lib/ai/roteiros/module-replicator/roteiro.md +56 -0
  131. package/dist-lib/ai/roteiros/page-detail/roteiro.md +32 -0
  132. package/dist-lib/ai/roteiros/page-edit/roteiro.md +31 -0
  133. package/dist-lib/ai/roteiros/screen-composer/roteiro.md +95 -0
  134. package/dist-lib/chunks/{panel-B-liPlxr.mjs → panel-CN0ChoHM.mjs} +5 -2
  135. package/dist-lib/chunks/{panel-B-liPlxr.mjs.map → panel-CN0ChoHM.mjs.map} +1 -1
  136. package/dist-lib/chunks/{panel-DoNbjeqX.cjs → panel-Cpq1xHck.cjs} +5 -2
  137. package/dist-lib/chunks/{panel-DoNbjeqX.cjs.map → panel-Cpq1xHck.cjs.map} +1 -1
  138. package/dist-lib/index.cjs +1 -1
  139. package/dist-lib/index.mjs +2 -2
  140. package/dist-lib/preview/clientes.cjs +1 -1
  141. package/dist-lib/preview/clientes.mjs +1 -1
  142. package/dist-lib/src/components/ui/DataTable/data-table.d.ts.map +1 -1
  143. package/dist-lib/src/components/ui/DataTable/data-table.types.d.ts +20 -2
  144. package/dist-lib/src/components/ui/DataTable/data-table.types.d.ts.map +1 -1
  145. package/package.json +1 -1
  146. /package/dist-lib/ai/roteiros/{dashboard → dashboard-builder}/blueprint.md +0 -0
  147. /package/dist-lib/ai/roteiros/{dashboard → dashboard-builder}/entrevista.md +0 -0
  148. /package/dist-lib/ai/roteiros/{dashboard → dashboard-builder}/geracao.md +0 -0
  149. /package/dist-lib/ai/roteiros/{dashboard → dashboard-builder}/roteiro.md +0 -0
@@ -0,0 +1,193 @@
1
+ > **Nota de portabilidade.** Este roteiro foi extraído do pipeline do iGreen DS
2
+ > para Claude Code. Menções a slash command (`/ds-create-…`), a `.claude/` e a
3
+ > ferramentas daquele ambiente descrevem **como ele é acionado lá** — aqui o
4
+ > equivalente é carregar este roteiro pelo `indice.json`. O conteúdo de decisão
5
+ > (entrevista, blueprint, regras de composição) vale igual.
6
+
7
+
8
+ > **Modo submódulo (`ds-link`).** Existe `.claude/ds-config.json` com `"mode": "submodule"`?
9
+ > Então **NÃO rode `igreen:add`** — esse script não existe no seu projeto. Os componentes e
10
+ > exemplos já estão no disco em `<dsPath>/src`: importe pelo `importBase` do config
11
+ > (compostos) e pelo `primitivesBase` (primitivos shadcn), e **leia** o exemplo direto de
12
+ > `<dsPath>/src/examples/`.
13
+
14
+ # List Builder — Entrevista
15
+
16
+ ## ⛔ Perguntas obrigatórias (NUNCA pular, mesmo inferindo)
17
+
18
+ 1. **Shape do card (Fase 2)** — mesmo inferindo, APRESENTAR o mapa de slots
19
+ (leading/title/subtitle/meta/...) e **confirmar em lote**. Nunca gerar com o
20
+ card só inferido sem o usuário ver/confirmar.
21
+ 2. **Views (Fase 4)** — **OFERECER e explicar o valor**: _"abas com filtros
22
+ pré-configurados (ex.: Admins, Ativos) — troca de recorte num clique. Quer
23
+ alguma?"_ Default = nenhuma, mas só após perguntar.
24
+
25
+ Princípios:
26
+
27
+ - **Fases agrupadas com defaults explícitos** — cada pergunta mostra o default;
28
+ "ok/Enter" aceita.
29
+ - **Modo expresso** — o usuário pode dizer "aceita os defaults daqui pra frente".
30
+ - **Dados podem ser incompletos** — fonte sem payload → slots viram hipóteses a
31
+ confirmar (nunca gerar silenciosamente).
32
+ - `AskUserQuestion` quando enumerável; prosa quando aberto.
33
+
34
+ ---
35
+
36
+ ## Fase 0 — Entidade + fonte de dados (obrigatória)
37
+
38
+ 1. **Entidade**: singular/plural (ex: "Membro/Membros") + 1 frase de domínio.
39
+ 2. **Fonte de dados** — uma de:
40
+ - **(a) Sample JSON colado** ← preferido (inferência valor+nome).
41
+ - **(b) Interface TypeScript** (inferência nome+tipo).
42
+ - **(c) Descrição de endpoint** (inferência só por nome → confiança baixa).
43
+ - **(d) Listagem manual** (`campo: tipo`).
44
+ 3. **Client vs server mode**:
45
+ - API pagina/filtra no servidor e devolve `total`? → **server**
46
+ (`mode="server"` + `onQueryChange` + `total`; DataList NÃO filtra local).
47
+ - Dataset completo de uma vez (ou mock)? → **client** (default).
48
+ 4. **Volume estimado** (decide proposta de escala na Fase 6). Default "< 1.000".
49
+ 5. **Campo id único** — todo item precisa `id`. Default `id`.
50
+
51
+ ---
52
+
53
+ ## Fase 1 — Página e shell (agrupada)
54
+
55
+ | Pergunta | Default |
56
+ | ---------------------- | ---------------------------------------------------------------------- |
57
+ | Título da página | plural da entidade |
58
+ | Descrição (1-2 frases) | gerada do domínio, confirmar |
59
+ | **Wrapper** | ver abaixo |
60
+ | Rota (kebab-case) | derivada do nome — **verificar colisão no router deste projeto** |
61
+ | Onde entra na nav | perguntar (menu lateral? submenu? qual grupo?) |
62
+
63
+ **Wrapper — 3 opções:**
64
+
65
+ - **(a) `ExamplePageLayout`** (default neste repo) — standalone, padrão dos
66
+ `List*Preview`. Props `category/title/description/code/children`. Dá altura
67
+ definida pro preview (pré-requisito de `fillHeight`/virtualização).
68
+ - **(b) `AppShell` + `PageHeader`** — tela "real". Perguntar drawer de criação /
69
+ DetailDrawer no item click. Forms seguem L-023 (`FormField`) + L-024 (`gap-form-gap`).
70
+ - **(c) Componente puro** — consumer (PAGES_DIR/REGISTRO do ambiente).
71
+
72
+ ---
73
+
74
+ ## Fase 2 — Card (shape) — confirmação em lote
75
+
76
+ O DataList passa cada item pro `List`, que monta o card por **slots** OU por
77
+ **`renderItem`** (card rico). Decidir qual:
78
+
79
+ ### 2a. Slots (caso comum) — mapear campos → slots
80
+
81
+ Apresentar UM mapa e confirmar em lote:
82
+
83
+ ```
84
+ | slot | campo / conteúdo | nota |
85
+ |------------|-----------------------------|------|
86
+ | leading | <avatar/ícone> | opcional |
87
+ | title | <campo> | OBRIGATÓRIO |
88
+ | subtitle | <campo> | opcional (ex: email) |
89
+ | description | <campo> | opcional (line-clamp 2) |
90
+ | meta[] | <label:campo (align)>, ... | colunas à direita (ROLE/STATUS/VISTO) |
91
+ | trailing | <badge/chip/contagem> | opcional |
92
+ ```
93
+
94
+ Inferência de slot por nome (PT+EN): `name/nome/title` → title · `email` →
95
+ subtitle · `status/role/papel` → meta (com dot ou chip) · `avatar/photo/foto` →
96
+ leading. `meta[].value` pode ser texto ou um chip/StatusDot — confirmar.
97
+
98
+ ### 2b. renderItem (card rico) — quando MUITOS campos / layout custom
99
+
100
+ Se o item tem layout próprio (ex: pedido com header+meta+footer, progresso,
101
+ avatar-stack) → `renderItem={(item) => <Card .../>}`. Espelhar
102
+ `ListRichPreview.tsx`. O wrapper (card/hover/click/menu) continua do List.
103
+
104
+ | Item | Default |
105
+ | ------------------------------ | --------------------------------------------- |
106
+ | Densidade | `comfortable` (ou `compact`) |
107
+ | Menu por card (`getMenuItems`) | oferecer Editar/Excluir (Excluir destructive) |
108
+
109
+ ---
110
+
111
+ ## Fase 3 — Layout (agrupada)
112
+
113
+ | Layout | Quando | Extras a perguntar |
114
+ | ---------------------- | --------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
115
+ | **standard** (default) | lista plana | — |
116
+ | **grouped** | seções por status/categoria | `groups` (id/label/color) · `enableDnD` (arrastar entre/dentro → `onMove`/`onReorder`) · `groupSurface` |
117
+ | **hierarchical** | árvore (pai→filho) | itens com `children` · `defaultExpandedIds` · **`branchHighlight`**: `none` (conectores) / `block` (painéis) / `active` (ramo do último aberto) · lazy `onLoadChildren` |
118
+
119
+ `branchHighlight` só em hierarchical. DnD só em standard/grouped (excludente com virtualização).
120
+
121
+ ---
122
+
123
+ ## Fase 4 — Toolbar (agrupada)
124
+
125
+ A toolbar do DataList é enxuta (reusa o TableToolbar): visões(abas)/título ·
126
+ refresh · busca · filtro(drawer) · ⋯. Sem colunas/toggle de visão.
127
+
128
+ > ⛔ **Anti-pattern — NUNCA gerar form/selects soltos ACIMA da lista.** Intenção de
129
+ > "adicionar filtro" (select de status em cima, campo de período, "filtrar por X") →
130
+ > **sugira o padrão certo** (o DataList já filtra reativo, com chips clicáveis/editáveis):
131
+ >
132
+ > - **Filtro por campo** (status/categoria/tipo/data…) → declare em `filterFields`. Quer
133
+ > abrir já filtrado? **pré-aplique** via `views` ou `filterModel` → abre com o **chip
134
+ > aplicado**, editável, reativo. Pode pré-setar **vários** de uma vez.
135
+ > - ⛔ **O `data-list` NÃO tem slot pra componente no toolbar.** O `data-table` ganhou
136
+ > `toolbar.customLeft` (`0.64.0`+); o `data-list` só tem `toolbarActions`, cujos kinds são
137
+ > `button`/`dropdown`/`input`. Seletor de período com calendário numa lista vai **fora**
138
+ > do componente (`PageHeader` ou linha própria). Não tente `customLeft` aqui — não
139
+ > existe e o TS reprova.
140
+ > - **toolbarActions é SÓ pra caso pequeno e simples que NÃO reage com campo** (ex.:
141
+ > data/período, escopo) — **label curta**, **máx ~2**. Se mexe com os campos, é grande,
142
+ > ou são muitos → **NÃO use o toolbar.**
143
+ > - **Muitos filtros, ou ligados a campo** → SEMPRE os nativos **pré-aplicados** (chips no
144
+ > load) + drawer "Filtros". Nunca empilhar selects.
145
+ >
146
+ > Regra de ouro: **filtro é recurso do DataList (reativo), não UI montada na unha.**
147
+
148
+ | Item | Pergunta | Default |
149
+ | ------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------- |
150
+ | Título OU views | título à esquerda, ou abas de visão? | título (plural) |
151
+ | Busca | `searchable` (cobre title/subtitle/description + accessors) | on |
152
+ | **filterFields** | quais campos filtram? cada um: `{ id, label, type, accessor, options? }` | inferir dos campos select/status; confirmar |
153
+ | **Views (abas)** | presets `{ id, label, query:{search, filterModel} }` — OFERECER (ver obrigatória) | nenhuma |
154
+ | Refresh | `onRefresh` | on |
155
+ | **toolbarActions** | ações custom no toolbar (`button`/`dropdown`/`input`, ex.: seletor de período/mês). Inline no desktop; **colapsam no ⋯ no mobile**. Oferecer quando o usuário pedir um seletor/botão extra na barra | off |
156
+ | moreActions (⋯) | itens extras? | off |
157
+
158
+ `filterFields.type` ∈ text/select/boolean/number/date. Chips de filtro aplicado
159
+ aparecem automaticamente (ToolbarApplied). Filtro abre o MESMO drawer da tabela.
160
+
161
+ ---
162
+
163
+ ## Fase 5 — Seleção, bulk e click
164
+
165
+ | Item | Pergunta | Default |
166
+ | ------------- | ------------------------------------------------------------------------------ | ----------------- |
167
+ | `selectable` | checkbox por card + bulk bar | off |
168
+ | `bulkActions` | `{ label, icon?, onClick(ids), destructive? }[]` (ex: Editar/Arquivar/Excluir) | se selectable on |
169
+ | `onItemClick` | nada / abrir detalhe / navegar | nada (standalone) |
170
+
171
+ Excluir (destructive) em drawer/form ⇒ confirmação via `AlertModal`.
172
+
173
+ ---
174
+
175
+ ## Fase 6 — Escala (excludentes)
176
+
177
+ | Opção | Quando | Props |
178
+ | ------------------- | -------------------------------------------- | ---------------------------------------------------------------- |
179
+ | Nenhuma (default) | < ~1.000 itens | — |
180
+ | **Virtualização** | listas grandes (só `standard`) — desliga DnD | `virtualized` (+ `estimateItemSize`) |
181
+ | **Infinite scroll** | paginar ao rolar | `onLoadMore` + `hasMore` + `loadingMore` (+ skeleton automático) |
182
+
183
+ Em tela dedicada (`ExamplePageLayout`), propor `fillHeight` + `className="flex-1
184
+ min-h-0"` (toolbar fixa, só a lista rola). Não combinar `fillHeight` com `virtualized`.
185
+
186
+ ---
187
+
188
+ ## Encerramento
189
+
190
+ Consolidar TODAS as escolhas num objeto de decisões (em memória — nada em disco),
191
+ carregar `blueprint.md` e montar o preview do gate.
192
+
193
+ Sinal: `BLUEPRINT_PRONTO: <Entidade> (lista) — aguardando gate`
@@ -0,0 +1,63 @@
1
+ > **Nota de portabilidade.** Este roteiro foi extraído do pipeline do iGreen DS
2
+ > para Claude Code. Menções a slash command (`/ds-create-…`), a `.claude/` e a
3
+ > ferramentas daquele ambiente descrevem **como ele é acionado lá** — aqui o
4
+ > equivalente é carregar este roteiro pelo `indice.json`. O conteúdo de decisão
5
+ > (entrevista, blueprint, regras de composição) vale igual.
6
+
7
+ > **Modo submódulo (`ds-link`).** Existe `.claude/ds-config.json` com `"mode": "submodule"`?
8
+ > Então **NÃO rode `igreen:add`** — esse script não existe no seu projeto. Os componentes e
9
+ > exemplos já estão no disco em `<dsPath>/src`: importe pelo `importBase` do config
10
+ > (compostos) e pelo `primitivesBase` (primitivos shadcn), e **leia** o exemplo direto de
11
+ > `<dsPath>/src/examples/`.
12
+
13
+ # List Builder — Geração (consumidor)
14
+
15
+ Só entre aqui após o gate aprovado. Ordem obrigatória:
16
+
17
+ ## 1. Puxar do registry (componente + exemplo canônico)
18
+
19
+ ```bash
20
+ npm run igreen:add -- data-list example-mapa-rede
21
+ # + outros componentes citados no blueprint (chip, page-header, floating-panel,
22
+ # alert-modal, etc — o registry resolve as deps automaticamente)
23
+ ```
24
+
25
+ `data-list` traz junto `list`, `table-toolbar`, `data-table` (via registryDependencies).
26
+
27
+ ## 2. LER antes de escrever (precedência de fontes)
28
+
29
+ 1. `src/examples/mapa-rede/mapa-rede-screen.tsx` — o molde real (DataList
30
+ `layout="hierarchical"` + `branchHighlight` + `renderItem` do card + `fillHeight`
31
+ - painel de detalhe `FloatingPanel` + `AlertModal`).
32
+ 2. `src/components/ui/DataList/USAGE.md` + `src/components/ui/List/USAGE.md` + types ao lado — API exata.
33
+ 3. Pra card rico / outros layouts (standard/grouped/DnD): adapte a forma do exemplo.
34
+
35
+ Nunca gere props de memória — copie a forma do exemplo.
36
+
37
+ ## 3. Criar a página
38
+
39
+ - Caminho/rota conforme o blueprint (`PAGES_DIR`/`REGISTRO`).
40
+ - Wrapper: `<div className="flex flex-col h-full min-h-0 gap-gp-2xl">` → `<PageHeader .../>`
41
+ → `<DataList fillHeight className="flex-1 min-h-0" .../>`.
42
+ - Card via **slots** (`leading/title/subtitle/meta/trailing`) OU `renderItem` (card rico).
43
+ - Layout `standard`/`grouped`(+`enableDnD`)/`hierarchical`(+`branchHighlight`) conforme blueprint.
44
+ - `filterFields` com `accessor: (item) => valor`; views (abas); seleção/bulk; escala
45
+ (`virtualized` XOR `onLoadMore`) — um por vez.
46
+ - Painel de detalhe / modais (se houver): espelhe `ConsultorDetailPanel` (FloatingPanel) e
47
+ o `AlertModal` do exemplo, ligados via estado da página.
48
+ - Tokens/spacing/typography conforme `.claude/rules/ds-design.md` + `DESIGN.md`.
49
+
50
+ ## 4. Registrar a rota
51
+
52
+ No ponto que o usuário indicou (router / App). Página órfã = incompleto.
53
+
54
+ ## 5. Validar
55
+
56
+ ```bash
57
+ npx tsc --noEmit # abort se falhar — corrija antes do handoff
58
+ ```
59
+
60
+ ## 6. Handoff
61
+
62
+ `LIST_PRONTO: <Entidade>` + onde foi registrada + como rodar (`npm run dev`).
63
+ Sugira ao usuário abrir a tela e conferir; ofereça ajustes finos (card, filtros, layout).
@@ -0,0 +1,91 @@
1
+ > **Nota de portabilidade.** Este roteiro foi extraído do pipeline do iGreen DS
2
+ > para Claude Code. Menções a slash command (`/ds-create-…`), a `.claude/` e a
3
+ > ferramentas daquele ambiente descrevem **como ele é acionado lá** — aqui o
4
+ > equivalente é carregar este roteiro pelo `indice.json`. O conteúdo de decisão
5
+ > (entrevista, blueprint, regras de composição) vale igual.
6
+
7
+
8
+ # List Builder (consumidor) — Router
9
+
10
+ Você guia a criação de uma tela de **lista de cards** que consome `<DataList>`
11
+ **sem fugir do exemplo e da documentação**. NÃO inventa API de props, NÃO gera
12
+ código de memória, NÃO toca em arquivo antes do gate aprovado.
13
+
14
+ ## ⚠️ Desambiguação ANTES de tudo (anti-erro)
15
+
16
+ Muita gente chama tabela de "lista". Se você chegou aqui direto sem o front-door,
17
+ confirme em 1 pergunta que o caso é mesmo lista de cards — senão a pessoa cria errado:
18
+
19
+ | Lista de cards (ESTA skill) | Tabela/grade (→ `crud-builder`) |
20
+ | ----------------------------------------------------------------------- | ------------------------------------------------------------------ |
21
+ | cada item é um **card**; poucos campos em destaque (avatar/título/meta) | colunas × linhas; muitos campos por registro |
22
+ | visual, hierarquia/agrupamento/DnD, feed, organograma | comparar/ordenar/filtrar **por coluna**, editar célula, somatórios |
23
+ | ex: membros, tarefas, organização (árvore), rede, atividades | ex: clientes, financeiro, pedidos com muitas colunas |
24
+
25
+ Caso for tabela → **PARAR** e usar `crud-builder` (`/ds-create-crud`).
26
+
27
+ ## Ambiente (este é um projeto CONSUMIDOR, copy-in)
28
+
29
+ | Variável | Valor |
30
+ | ------------------------ | ----------------------------------------------------------------------------------------------------------------------- |
31
+ | `IMPORT_PATH` | `@/components/ui/DataList`, `@/components/ui/List`, etc (copy-in via alias) |
32
+ | `EXEMPLO_CANÔNICO` | `example-mapa-rede` → `npm run igreen:add -- example-mapa-rede` → ler `src/examples/mapa-rede/mapa-rede-screen.tsx` |
33
+ | `DOC` | `src/components/ui/DataList/USAGE.md` + `src/components/ui/List/USAGE.md` (após `igreen:add data-list`) + types ao lado |
34
+ | `PAGES_DIR` / `REGISTRO` | perguntar ao usuário (onde mora a página + como registra rota) |
35
+
36
+ Se o componente/exemplo ainda não está no disco, **puxe via `igreen:add`** antes de ler — nunca gere de memória.
37
+
38
+ > **Modo submódulo (ds-link).** Se existe `.claude/ds-config.json` com `"mode": "submodule"`,
39
+ > o DS é consumido como **submódulo** (não copy-in): os componentes/exemplos JÁ estão no disco
40
+ > em `<dsPath>/src` e **não** há registry. Use `importBase` do config (ex.: `@ds/components/ui/<Nome>`)
41
+ > e leia o exemplo canônico direto em `<dsPath>/src/examples/mapa-rede/mapa-rede-screen.tsx` —
42
+ > **NÃO** rode `igreen:add`. `PAGES_DIR`/`REGISTRO` continuam do projeto pai.
43
+
44
+ ## Fluxo — 3 estágios
45
+
46
+ ```
47
+ /ds-create-list (ou /ds-create-screen → desambiguação → aqui)
48
+ ▼ interview.md
49
+ 1. ENTREVISTA (fases 0-6) — acumula escolhas, ZERO edição em disco
50
+ ▼ blueprint.md
51
+ 2. BLUEPRINT [GATE] — preview consolidado + pré-validações → aguarda "aprovar"
52
+ ▼ generate.md
53
+ 3. GERAÇÃO — igreen:add → ler exemplo → criar página → registrar → tsc → handoff
54
+ ```
55
+
56
+ Carregue cada sub-arquivo só no estágio correspondente: `interview.md` agora, `blueprint.md` ao fim da entrevista, `generate.md` só após o gate.
57
+
58
+ ## ⚠️ Precedência de fontes (anti-drift)
59
+
60
+ ```
61
+ 1. src/examples/mapa-rede/mapa-rede-screen.tsx (exemplo real, vence tudo)
62
+ 2. src/components/ui/DataList/USAGE.md + src/components/ui/List/USAGE.md + types ao lado
63
+ 3. Snippets desta skill
64
+ 4. Memória da IA ← NUNCA confiar sozinha
65
+ ```
66
+
67
+ Se USAGE.md divergir do exemplo/types, o exemplo + types vencem.
68
+
69
+ ## Guardrails (não-negociáveis)
70
+
71
+ 1. `virtualized` e `enableDnD` são **mutuamente exclusivos**; `virtualized` e
72
+ `onLoadMore` (infinite-scroll) **não combinam** — escolha um.
73
+ 2. `branchHighlight` (`block`/`active`) só faz efeito em `layout="hierarchical"`.
74
+ 3. `filterFields` declara `accessor: (item) => valor` (NÃO column def); `select`
75
+ precisa `options`. Operador de view/filtro válido pro tipo (multiSelect⇒isAnyOf,
76
+ select⇒equals, text⇒contains, number⇒equals, date⇒between, boolean⇒equals).
77
+ 4. `fillHeight` em tela dedicada ⇒ pai com altura + `className="flex-1 min-h-0"`
78
+ (toolbar/chips/bulk fixos, só a lista rola). Não usar com `virtualized`.
79
+ 5. `layout="grouped"` exige `groups`; `hierarchical` exige itens com `children`.
80
+ 6. Card via slots OU `renderItem` (não os dois). Forms (criar/editar em drawer)
81
+ usam `<FormField>` + `gap-form-gap`.
82
+ 7. Classes DS antes de Tailwind literal; zero hardcode de cor/tamanho (ver `.claude/rules/ds-design.md`).
83
+ 8. Wrapper da tela: `flex flex-col h-full min-h-0 gap-gp-2xl` (PageHeader → 16px → lista). Ver `DESIGN.md`.
84
+ 9. Página registrada no roteador do usuário — página órfã = tarefa incompleta.
85
+ 10. `npx tsc --noEmit` limpo antes do handoff (abort-on-error).
86
+ 11. LER o exemplo canônico ANTES de gerar — nunca de memória.
87
+
88
+ ## Handoff
89
+
90
+ - Entrevista pronta → `BLUEPRINT_PRONTO: <Entidade> (lista) — aguardando gate`
91
+ - Pós-geração → `LIST_PRONTO: <Entidade>` (+ onde foi registrada)
@@ -0,0 +1,56 @@
1
+ > **Nota de portabilidade.** Este roteiro foi extraído do pipeline do iGreen DS
2
+ > para Claude Code. Menções a slash command (`/ds-create-…`), a `.claude/` e a
3
+ > ferramentas daquele ambiente descrevem **como ele é acionado lá** — aqui o
4
+ > equivalente é carregar este roteiro pelo `indice.json`. O conteúdo de decisão
5
+ > (entrevista, blueprint, regras de composição) vale igual.
6
+
7
+
8
+ > **Modo submódulo (`ds-link`).** Existe `.claude/ds-config.json` com `"mode": "submodule"`?
9
+ > Então **NÃO rode `igreen:add`** — esse script não existe no seu projeto. Os componentes e
10
+ > exemplos já estão no disco em `<dsPath>/src`: importe pelo `importBase` do config
11
+ > (compostos) e pelo `primitivesBase` (primitivos shadcn), e **leia** o exemplo direto de
12
+ > `<dsPath>/src/examples/`.
13
+
14
+ # module-replicator — Replicar família de telas (segmento)
15
+
16
+ Quando um app tem **módulos espelhados** (ex.: várias verticais/segmentos com a
17
+ mesma estrutura de telas), replica a família trocando só o que varia.
18
+
19
+ ## ⚠️ Antes de copiar: copiar OU parametrizar?
20
+
21
+ Copiar N vezes = N cópias pra manter (todo bug/ajuste ×N). **Se as telas são
22
+ idênticas em estrutura e só mudam dados/rótulos**, o melhor costuma ser
23
+ **parametrizar** — 1 componente dirigido por config de segmento:
24
+
25
+ ```tsx
26
+ const SEGMENTOS = { energia: {...}, telecom: {...}, seguros: {...} };
27
+ function SegmentoDashboard({ seg }: { seg: SegKey }) { /* lê SEGMENTOS[seg] */ }
28
+ ```
29
+
30
+ Ofereça as duas ao usuário: **(a) parametrizar** (recomendado se ≥3 clones ou
31
+ manutenção conjunta) ou **(b) replicar arquivos** (ok pra 1-2 e quando os
32
+ segmentos devem divergir depois). Só siga pra cópia se ele escolher (b).
33
+
34
+ ## Fluxo (replicar arquivos — opção b)
35
+
36
+ 1. **Identifique o módulo-fonte**: as telas/arquivos + o contexto de nav dele
37
+ (`nav-data`) + as rotas (`routes`).
38
+ 2. **Separe o que VARIA** (dataset/mock, rótulos/títulos, id/ícone/cor do contexto,
39
+ hrefs `#/<segmento>/...`) do que é **ESTRUTURAL** (layout, colunas, componentes,
40
+ spacing) — o estrutural fica **idêntico**.
41
+ 3. **Copie** as telas → novo segmento; troque só o que varia (1 arquivo de mock por
42
+ segmento, mesma shape/tipos).
43
+ 4. **Registre** o novo contexto em `nav-data` + as entradas no mapa de rotas
44
+ (ver skill `app-builder`). Hrefs únicos por segmento.
45
+ 5. `npx tsc --noEmit` limpo.
46
+
47
+ ## Gotchas do tipo
48
+
49
+ - **Nunca altere a ESTRUTURA na cópia** — se divergir, vira manutenção ×N e perde o
50
+ sentido de "família". Só dados/rótulos/ícone/cor/href mudam.
51
+ - **Mock**: um arquivo por segmento com a MESMA shape (reuse os tipos). Não duplique tipos.
52
+ - **Nav/rotas**: `id`/label/icon/color do contexto únicos; hrefs `#/<segmento>/<tela>`;
53
+ 1 linha por tela no mapa de rotas (não if-chain).
54
+ - Se depois um segmento precisar de tela exclusiva, aí sim diverge só aquela.
55
+
56
+ Aplique `DESIGN.md`. Handoff: `MODULO_PRONTO: <segmento> (N telas)` + rotas.
@@ -0,0 +1,32 @@
1
+ > **Nota de portabilidade.** Este roteiro foi extraído do pipeline do iGreen DS
2
+ > para Claude Code. Menções a slash command (`/ds-create-…`), a `.claude/` e a
3
+ > ferramentas daquele ambiente descrevem **como ele é acionado lá** — aqui o
4
+ > equivalente é carregar este roteiro pelo `indice.json`. O conteúdo de decisão
5
+ > (entrevista, blueprint, regras de composição) vale igual.
6
+
7
+
8
+ # page-detail — Página de detalhamento
9
+
10
+ Página de leitura/inspeção de um registro: cabeçalho + abas + cards de seção.
11
+
12
+ ## Fluxo
13
+ 1. `npm run igreen:add -- example-order-detail` (traz a tela + `Tabs`, `Card`, `Chip`, `PageHeader`).
14
+ 2. **Leia** `src/examples/order-detail/order-detail-screen.tsx` + USAGE dos componentes.
15
+ 3. Adapte as abas/seções/campos ao registro do usuário.
16
+ 4. Registre a rota. `npx tsc --noEmit` limpo.
17
+
18
+ > **Modo submódulo (ds-link).** Se existe `.claude/ds-config.json` com `"mode": "submodule"`,
19
+ > o DS é consumido como **submódulo** (não copy-in): os componentes/exemplos JÁ estão no disco
20
+ > em `<dsPath>/src` e **não** há registry. Use `importBase` do config (ex.: `@ds/components/shadcn/tabs`)
21
+ > e leia o exemplo direto em `<dsPath>/src/examples/order-detail/order-detail-screen.tsx` —
22
+ > **NÃO** rode `igreen:add`.
23
+
24
+ ## Gotchas do tipo
25
+ - Estrutura: `PageHeader` (título + badges de status + ações) → `Tabs` (visão geral / detalhes / atividade / comentários / anexos) → cards de seção (`section-card`).
26
+ - `Tabs` tem a variant `line` (underline) além da default segmented — use `line` pra navegação de abas de detalhe/ficha; segmented pra alternância de conteúdo curto.
27
+ - Layout 2 colunas (conteúdo + painel lateral do cliente/meta) num grid responsivo; empilha no mobile.
28
+ - Badges de status via `Chip`/`Badge` com cor semântica (`success`/`warning`/...).
29
+ - Wrapper de página: `flex flex-col h-full min-h-0 gap-gp-2xl`.
30
+ - Campos label/valor: rótulo `text-caption` em `fg-muted`, valor `text-body`.
31
+
32
+ Se a tela também edita inline ou abre drawer de edição → ver skill `drawers`. Aplique `DESIGN.md`. Handoff: `DETAIL_PRONTO: <Entidade>` + rota.
@@ -0,0 +1,31 @@
1
+ > **Nota de portabilidade.** Este roteiro foi extraído do pipeline do iGreen DS
2
+ > para Claude Code. Menções a slash command (`/ds-create-…`), a `.claude/` e a
3
+ > ferramentas daquele ambiente descrevem **como ele é acionado lá** — aqui o
4
+ > equivalente é carregar este roteiro pelo `indice.json`. O conteúdo de decisão
5
+ > (entrevista, blueprint, regras de composição) vale igual.
6
+
7
+
8
+ # page-edit — Tela de edição/cadastro
9
+
10
+ Tela de formulário (criar/editar). Não gere de memória — puxe e adapte o exemplo.
11
+
12
+ ## Fluxo
13
+ 1. `npm run igreen:add -- example-edit-page` (traz a tela + `FormField`, `Button`, etc).
14
+ 2. **Leia** `src/examples/edit-page/edit-page-screen.tsx` + `src/components/ui/FormField/USAGE.md`.
15
+ 3. Adapte os campos ao caso do usuário (mantendo a estrutura de seções/steps).
16
+ 4. Registre a rota onde o usuário indicar. `npx tsc --noEmit` limpo.
17
+
18
+ > **Modo submódulo (ds-link).** Se existe `.claude/ds-config.json` com `"mode": "submodule"`,
19
+ > o DS é consumido como **submódulo** (não copy-in): os componentes/exemplos JÁ estão no disco
20
+ > em `<dsPath>/src` e **não** há registry. Use `importBase` do config (ex.: `@ds/components/ui/FormField`)
21
+ > e leia o exemplo direto em `<dsPath>/src/examples/edit-page/edit-page-screen.tsx` —
22
+ > **NÃO** rode `igreen:add`.
23
+
24
+ ## Gotchas do tipo
25
+ - **Sempre `<FormField>`** (FormFieldInput/Select/Textarea/Switch) — nunca `<label>` cru (peso/cor/dark-mode divergem). Spacing entre campos = `gap-form-gap` (20px).
26
+ - Validação inline via `errorMessage` no FormField; helper via `helperText`.
27
+ - Multi-step: padrão `StepNav` lateral do example-edit-page (estado `activeStep` + refs de seção).
28
+ - Wrapper de página: `flex flex-col h-full min-h-0 gap-gp-2xl`; PageHeader com ações Cancelar/Salvar.
29
+ - Ações: Salvar = `<Button color="primary" variant="filled">`; Cancelar = `secondary outline`.
30
+
31
+ Aplique `DESIGN.md` + `.claude/rules/ds-design.md`. Handoff: `EDIT_PRONTO: <Entidade>` + rota.
@@ -0,0 +1,95 @@
1
+ > **Nota de portabilidade.** Este roteiro foi extraído do pipeline do iGreen DS
2
+ > para Claude Code. Menções a slash command (`/ds-create-…`), a `.claude/` e a
3
+ > ferramentas daquele ambiente descrevem **como ele é acionado lá** — aqui o
4
+ > equivalente é carregar este roteiro pelo `indice.json`. O conteúdo de decisão
5
+ > (entrevista, blueprint, regras de composição) vale igual.
6
+
7
+
8
+ # screen-composer — Página composta (estado compartilhado)
9
+
10
+ Não é um tipo de peça — é a **cola** entre peças. Cada peça vem de um builder
11
+ (crud/list/dashboard/drawers); aqui você monta o layout e **cabeia o estado que
12
+ elas compartilham**. A receita completa está logo abaixo, em "Os 2 padrões".
13
+
14
+ ## Quando esta skill (vs os builders diretos)
15
+
16
+ - 1 peça só (uma tabela, uma lista, um dashboard) → vá direto no builder.
17
+ - **2+ peças que reagem entre si** (master-detail e/ou cross-filter) → **aqui**.
18
+
19
+ ## Fluxo
20
+
21
+ 1. **Decomponha** a página: quais peças (tabela / lista / KPIs+gráfico / detalhe /
22
+ filtro global) e quais **interações** (clicar→detalhe? controle→filtra tudo?).
23
+ 2. **Monte cada peça** pelo builder certo (crud/list/dashboard) OU puxe o exemplo
24
+ composto: `npm run igreen:add -- example-finance` (master-detail: tabela +
25
+ detail panel + drawers) / `example-order-detail`. **Leia** o exemplo.
26
+ 3. **Cabeie o estado no nível da PÁGINA** — ver "Os 2 padrões" abaixo.
27
+ 4. `npx tsc --noEmit` limpo.
28
+
29
+ ## Os 2 padrões (cobrem quase toda página composta)
30
+
31
+ Estado que 2+ peças compartilham **não mora em cada peça**: sobe pro componente da
32
+ página (single source of truth) e desce por props.
33
+
34
+ ### Master-detail — clicar num item abre o detalhe
35
+
36
+ ```tsx
37
+ function ClientesPage() {
38
+ const [selectedId, setSelectedId] = useState<string | null>(null);
39
+ const selected = selectedId ? findById(selectedId) : null;
40
+ return (
41
+ <div className="flex h-full min-h-0 gap-gp-2xl">
42
+ <DataTable
43
+ rows={rows}
44
+ columns={cols}
45
+ onRowClick={(row) => setSelectedId(row.id)} // grade → estado
46
+ className="flex-1 min-h-0"
47
+ />
48
+ {/* ao LADO = FloatingPanel/painel fixo · POR CIMA = Drawer/Sheet */}
49
+ <DetailPanel item={selected} onClose={() => setSelectedId(null)} />
50
+ </div>
51
+ );
52
+ }
53
+ ```
54
+
55
+ Nunca duplique a linha no detalhe — passe só o `id`/objeto selecionado.
56
+
57
+ ### Cross-filter — um controle alimenta várias peças
58
+
59
+ ```tsx
60
+ function PainelPage() {
61
+ const [periodo, setPeriodo] = useState<Periodo>("mes");
62
+ const data = useMemo(() => filtrar(base, periodo), [periodo]); // 1 fonte
63
+ return (
64
+ <div className="flex flex-col gap-gp-2xl">
65
+ <PageHeader actions={<PeriodSelector value={periodo} onChange={setPeriodo} />} />
66
+ <KpiGroup>{/* lê `data` */}</KpiGroup>
67
+ <ChartCard data={data} />
68
+ <DataTable rows={data.rows} columns={cols} />
69
+ </div>
70
+ );
71
+ }
72
+ ```
73
+
74
+ - **Um** `useMemo` deriva o dataset; todas as peças leem dele (não refazem fetch).
75
+ - Filtro por **coluna** continua nativo/pré-aplicado (chips) — ver `ds-components.md`.
76
+ O cross-filter aqui é o **escopo global** (período/segmento), no `PageHeader.actions`.
77
+ - Os dois combinam: `selectedId` e `periodo` convivem no mesmo nível.
78
+
79
+ > **Modo submódulo (ds-link).** Se existe `.claude/ds-config.json` com `"mode": "submodule"`,
80
+ > NÃO rode `igreen:add` — leia os exemplos em `<dsPath>/src/examples/` e importe via `importBase`.
81
+
82
+ ## Gotchas do tipo
83
+
84
+ - **Single source of truth**: estado que 2+ peças compartilham SOBE pra página, não
85
+ fica duplicado em cada peça. Peça isolada mantém o seu.
86
+ - **Master-detail**: passe só `id`/objeto seleto pro detalhe (nunca remonte a linha).
87
+ Ao lado = `FloatingPanel`/painel fixo; por cima = `Drawer`/`Sheet`.
88
+ - **Cross-filter**: um `useMemo(filtrar(base, filtro))` alimenta KPIs+gráfico+tabela;
89
+ não refaça fetch por peça. Filtro por COLUNA continua nativo/pré-aplicado (L-051);
90
+ o cross-filter é o escopo global (período/segmento), no `PageHeader.actions`.
91
+ - **Layout**: shell `flex flex-col gap-gp-2xl` (ou `flex gap` p/ master-detail lado a lado);
92
+ `fillHeight`/`flex-1 min-h-0` nas peças que rolam.
93
+ - Conteúdo/estilo de cada peça = responsabilidade do builder dela; aqui é só layout + estado.
94
+
95
+ Aplique `DESIGN.md`. Handoff: `SCREEN_PRONTO: <página>` + rota.
@@ -12416,7 +12416,10 @@ function DataTableInternal(props, ref) {
12416
12416
  }
12417
12417
  )
12418
12418
  ) : void 0,
12419
- actions: toolbarConfig.actions && toolbarConfig.actions.length > 0 ? /* @__PURE__ */ jsx(ToolbarActions, { actions: toolbarConfig.actions }) : void 0,
12419
+ actions: toolbarConfig.customLeft || toolbarConfig.actions && toolbarConfig.actions.length > 0 ? /* @__PURE__ */ jsxs(Fragment, { children: [
12420
+ toolbarConfig.customLeft,
12421
+ toolbarConfig.actions && toolbarConfig.actions.length > 0 ? /* @__PURE__ */ jsx(ToolbarActions, { actions: toolbarConfig.actions }) : null
12422
+ ] }) : void 0,
12420
12423
  fullscreen: enableFullscreen ? /* @__PURE__ */ jsx(
12421
12424
  ToolbarToolButton,
12422
12425
  {
@@ -13167,4 +13170,4 @@ export {
13167
13170
  DEFAULT_FILTER_OPERATORS as y,
13168
13171
  DataTableActionsCell as z
13169
13172
  };
13170
- //# sourceMappingURL=panel-B-liPlxr.mjs.map
13173
+ //# sourceMappingURL=panel-CN0ChoHM.mjs.map