@snksergio/design-system 0.61.0 → 0.63.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 (193) 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/AlertModal.md +47 -0
  7. package/dist-lib/ai/componentes/AppShell.md +117 -0
  8. package/dist-lib/ai/componentes/Breadcrumb.md +187 -0
  9. package/dist-lib/ai/componentes/Button.md +116 -0
  10. package/dist-lib/ai/componentes/ButtonGroup.md +162 -0
  11. package/dist-lib/ai/componentes/CardCheckbox.md +99 -0
  12. package/dist-lib/ai/componentes/CardOption.md +133 -0
  13. package/dist-lib/ai/componentes/Chart.md +93 -0
  14. package/dist-lib/ai/componentes/Chip.md +68 -0
  15. package/dist-lib/ai/componentes/ChoroplethMap.md +118 -0
  16. package/dist-lib/ai/componentes/ColorPicker.md +70 -0
  17. package/dist-lib/ai/componentes/Combobox.md +51 -0
  18. package/dist-lib/ai/componentes/ConversationListItem.md +90 -0
  19. package/dist-lib/ai/componentes/DataList.md +111 -0
  20. package/dist-lib/ai/componentes/DataTable.md +867 -0
  21. package/dist-lib/ai/componentes/DatePicker.md +84 -0
  22. package/dist-lib/ai/componentes/DateSeparatorChip.md +59 -0
  23. package/dist-lib/ai/componentes/EmptyState.md +72 -0
  24. package/dist-lib/ai/componentes/FileUploadField.md +95 -0
  25. package/dist-lib/ai/componentes/FloatingPanel.md +118 -0
  26. package/dist-lib/ai/componentes/FooterTable.md +62 -0
  27. package/dist-lib/ai/componentes/FormField.md +110 -0
  28. package/dist-lib/ai/componentes/Gantt.md +552 -0
  29. package/dist-lib/ai/componentes/Header.md +98 -0
  30. package/dist-lib/ai/componentes/Icon.md +65 -0
  31. package/dist-lib/ai/componentes/Kanban.md +343 -0
  32. package/dist-lib/ai/componentes/Kpi.md +103 -0
  33. package/dist-lib/ai/componentes/List.md +61 -0
  34. package/dist-lib/ai/componentes/MarkdownText.md +59 -0
  35. package/dist-lib/ai/componentes/MenuSidebar.md +128 -0
  36. package/dist-lib/ai/componentes/MessageAck.md +53 -0
  37. package/dist-lib/ai/componentes/MessageBubble.md +115 -0
  38. package/dist-lib/ai/componentes/MessageComposer.md +80 -0
  39. package/dist-lib/ai/componentes/MessageVariablesPicker.md +104 -0
  40. package/dist-lib/ai/componentes/Modal.md +88 -0
  41. package/dist-lib/ai/componentes/MonthYearPicker.md +49 -0
  42. package/dist-lib/ai/componentes/PageHeader.md +129 -0
  43. package/dist-lib/ai/componentes/Panel.md +84 -0
  44. package/dist-lib/ai/componentes/Scheduler.md +421 -0
  45. package/dist-lib/ai/componentes/ScreenLoader.md +60 -0
  46. package/dist-lib/ai/componentes/SingleMenuSidebar.md +171 -0
  47. package/dist-lib/ai/componentes/Spinner.md +52 -0
  48. package/dist-lib/ai/componentes/Table.md +192 -0
  49. package/dist-lib/ai/componentes/TableToolbar.md +87 -0
  50. package/dist-lib/ai/componentes/TabsNavigation.md +152 -0
  51. package/dist-lib/ai/componentes/Toast.md +49 -0
  52. package/dist-lib/ai/componentes/_primitivos.md +74 -0
  53. package/dist-lib/ai/componentes/avatar-ig.md +181 -0
  54. package/dist-lib/ai/componentes/indice.json +49 -0
  55. package/dist-lib/ai/exemplos/app-shell/app-shell-example.tsx +140 -0
  56. package/dist-lib/ai/exemplos/app-shell/index.ts +3 -0
  57. package/dist-lib/ai/exemplos/app-shell/nav-data.ts +97 -0
  58. package/dist-lib/ai/exemplos/app-shell/routes.tsx +75 -0
  59. package/dist-lib/ai/exemplos/chat/chat-screen.tsx +152 -0
  60. package/dist-lib/ai/exemplos/chat/chat-v2-mocks.ts +171 -0
  61. package/dist-lib/ai/exemplos/chat/chat-v2.styles.ts +23 -0
  62. package/dist-lib/ai/exemplos/chat/chat-v2.types.ts +81 -0
  63. package/dist-lib/ai/exemplos/chat/components/ChannelDot/channel-dot.tsx +28 -0
  64. package/dist-lib/ai/exemplos/chat/components/ConversationActionsMenu/conversation-actions-menu.tsx +83 -0
  65. package/dist-lib/ai/exemplos/chat/components/ConversationActionsMenu/index.ts +4 -0
  66. package/dist-lib/ai/exemplos/chat/components/ConversationColumn/conversation-column.styles.ts +22 -0
  67. package/dist-lib/ai/exemplos/chat/components/ConversationColumn/conversation-column.tsx +203 -0
  68. package/dist-lib/ai/exemplos/chat/components/ConversationColumn/conversation-column.types.ts +10 -0
  69. package/dist-lib/ai/exemplos/chat/components/ConversationColumn/index.ts +2 -0
  70. package/dist-lib/ai/exemplos/chat/components/ConversationListItem/conversation-list-item.styles.ts +55 -0
  71. package/dist-lib/ai/exemplos/chat/components/ConversationListItem/conversation-list-item.tsx +52 -0
  72. package/dist-lib/ai/exemplos/chat/components/ConversationListItem/conversation-list-item.types.ts +7 -0
  73. package/dist-lib/ai/exemplos/chat/components/ConversationListItem/index.ts +2 -0
  74. package/dist-lib/ai/exemplos/chat/components/DateSeparator/date-separator.tsx +18 -0
  75. package/dist-lib/ai/exemplos/chat/components/DetailField/detail-field.tsx +23 -0
  76. package/dist-lib/ai/exemplos/chat/components/DetailSection/detail-section.tsx +41 -0
  77. package/dist-lib/ai/exemplos/chat/components/DetailSection/index.ts +1 -0
  78. package/dist-lib/ai/exemplos/chat/components/DetailsColumn/details-column.styles.ts +30 -0
  79. package/dist-lib/ai/exemplos/chat/components/DetailsColumn/details-column.tsx +142 -0
  80. package/dist-lib/ai/exemplos/chat/components/DetailsColumn/details-column.types.ts +16 -0
  81. package/dist-lib/ai/exemplos/chat/components/DetailsColumn/index.ts +5 -0
  82. package/dist-lib/ai/exemplos/chat/components/FilterRow/filter-row.styles.ts +37 -0
  83. package/dist-lib/ai/exemplos/chat/components/FilterRow/filter-row.tsx +45 -0
  84. package/dist-lib/ai/exemplos/chat/components/FilterRow/index.ts +1 -0
  85. package/dist-lib/ai/exemplos/chat/components/FiltersColumn/filters-column.styles.ts +27 -0
  86. package/dist-lib/ai/exemplos/chat/components/FiltersColumn/filters-column.tsx +66 -0
  87. package/dist-lib/ai/exemplos/chat/components/FiltersColumn/filters-column.types.ts +13 -0
  88. package/dist-lib/ai/exemplos/chat/components/FiltersColumn/filters-rail.tsx +38 -0
  89. package/dist-lib/ai/exemplos/chat/components/FiltersColumn/index.ts +6 -0
  90. package/dist-lib/ai/exemplos/chat/components/MessageBubble/index.ts +2 -0
  91. package/dist-lib/ai/exemplos/chat/components/MessageBubble/message-bubble.styles.ts +37 -0
  92. package/dist-lib/ai/exemplos/chat/components/MessageBubble/message-bubble.tsx +29 -0
  93. package/dist-lib/ai/exemplos/chat/components/MessageBubble/message-bubble.types.ts +5 -0
  94. package/dist-lib/ai/exemplos/chat/components/PersonAvatar/index.ts +5 -0
  95. package/dist-lib/ai/exemplos/chat/components/PersonAvatar/person-avatar.tsx +31 -0
  96. package/dist-lib/ai/exemplos/chat/components/QueueColumn/index.ts +2 -0
  97. package/dist-lib/ai/exemplos/chat/components/QueueColumn/queue-column.styles.ts +19 -0
  98. package/dist-lib/ai/exemplos/chat/components/QueueColumn/queue-column.tsx +140 -0
  99. package/dist-lib/ai/exemplos/chat/components/QueueColumn/queue-column.types.ts +13 -0
  100. package/dist-lib/ai/exemplos/chat/components/RailItem/index.ts +1 -0
  101. package/dist-lib/ai/exemplos/chat/components/RailItem/rail-item.styles.ts +30 -0
  102. package/dist-lib/ai/exemplos/chat/components/RailItem/rail-item.tsx +42 -0
  103. package/dist-lib/ai/exemplos/chat/hooks/use-resizable.ts +98 -0
  104. package/dist-lib/ai/exemplos/chat/index.ts +1 -0
  105. package/dist-lib/ai/exemplos/clientes/_table-data.ts +59 -0
  106. package/dist-lib/ai/exemplos/clientes/clientes-screen.tsx +505 -0
  107. package/dist-lib/ai/exemplos/clientes/clientes-showcase-mocks.ts +117 -0
  108. package/dist-lib/ai/exemplos/clientes/clientes-showcase.styles.ts +13 -0
  109. package/dist-lib/ai/exemplos/clientes/clientes-showcase.types.ts +16 -0
  110. package/dist-lib/ai/exemplos/clientes/components/DetailDrawer/detail-drawer.styles.ts +28 -0
  111. package/dist-lib/ai/exemplos/clientes/components/DetailDrawer/detail-drawer.tsx +303 -0
  112. package/dist-lib/ai/exemplos/clientes/components/DetailDrawer/detail-drawer.types.ts +14 -0
  113. package/dist-lib/ai/exemplos/clientes/components/DetailDrawer/index.ts +2 -0
  114. package/dist-lib/ai/exemplos/clientes/components/NovoClienteDrawer/index.ts +2 -0
  115. package/dist-lib/ai/exemplos/clientes/components/NovoClienteDrawer/novo-cliente-drawer.tsx +207 -0
  116. package/dist-lib/ai/exemplos/clientes/index.ts +1 -0
  117. package/dist-lib/ai/exemplos/dashboard/dashboard-brazil-map.ts +33 -0
  118. package/dist-lib/ai/exemplos/dashboard/dashboard-screen.tsx +1110 -0
  119. package/dist-lib/ai/exemplos/dashboard/index.ts +1 -0
  120. package/dist-lib/ai/exemplos/edit-page/components/StepNav.tsx +81 -0
  121. package/dist-lib/ai/exemplos/edit-page/components/section-card.tsx +85 -0
  122. package/dist-lib/ai/exemplos/edit-page/edit-page-screen.tsx +234 -0
  123. package/dist-lib/ai/exemplos/edit-page/index.ts +1 -0
  124. package/dist-lib/ai/exemplos/finance/_table-data.ts +57 -0
  125. package/dist-lib/ai/exemplos/finance/clientes-financeiro-mocks.ts +227 -0
  126. package/dist-lib/ai/exemplos/finance/clientes-financeiro.types.ts +75 -0
  127. package/dist-lib/ai/exemplos/finance/clientes-showcase-mocks.ts +117 -0
  128. package/dist-lib/ai/exemplos/finance/clientes-showcase.styles.ts +13 -0
  129. package/dist-lib/ai/exemplos/finance/clientes-showcase.types.ts +16 -0
  130. package/dist-lib/ai/exemplos/finance/components/EditarFinanceDrawer/editar-finance-drawer.tsx +241 -0
  131. package/dist-lib/ai/exemplos/finance/components/EditarFinanceDrawer/index.ts +5 -0
  132. package/dist-lib/ai/exemplos/finance/components/ExtratoExpansion/extrato-expansion.tsx +172 -0
  133. package/dist-lib/ai/exemplos/finance/components/ExtratoExpansion/index.ts +1 -0
  134. package/dist-lib/ai/exemplos/finance/components/FinanceDetailPanel/finance-detail-panel.tsx +241 -0
  135. package/dist-lib/ai/exemplos/finance/components/FinanceDetailPanel/index.ts +2 -0
  136. package/dist-lib/ai/exemplos/finance/components/NovoClienteDrawer/index.ts +2 -0
  137. package/dist-lib/ai/exemplos/finance/components/NovoClienteDrawer/novo-cliente-drawer.tsx +207 -0
  138. package/dist-lib/ai/exemplos/finance/components/SacarDialog/index.ts +2 -0
  139. package/dist-lib/ai/exemplos/finance/components/SacarDialog/sacar-dialog.tsx +346 -0
  140. package/dist-lib/ai/exemplos/finance/finance-screen.tsx +821 -0
  141. package/dist-lib/ai/exemplos/finance/index.ts +1 -0
  142. package/dist-lib/ai/exemplos/gantt/_gantt-data.tsx +402 -0
  143. package/dist-lib/ai/exemplos/gantt/gantt-screen.tsx +512 -0
  144. package/dist-lib/ai/exemplos/gantt/index.ts +1 -0
  145. package/dist-lib/ai/exemplos/login/index.ts +1 -0
  146. package/dist-lib/ai/exemplos/login/login-screen.tsx +246 -0
  147. package/dist-lib/ai/exemplos/mapa-rede/components/ConsultorDetailPanel/consultor-detail-panel.tsx +158 -0
  148. package/dist-lib/ai/exemplos/mapa-rede/components/ConsultorDetailPanel/index.ts +2 -0
  149. package/dist-lib/ai/exemplos/mapa-rede/index.ts +1 -0
  150. package/dist-lib/ai/exemplos/mapa-rede/mapa-de-rede-mocks.ts +655 -0
  151. package/dist-lib/ai/exemplos/mapa-rede/mapa-de-rede.types.ts +53 -0
  152. package/dist-lib/ai/exemplos/mapa-rede/mapa-rede-screen.tsx +227 -0
  153. package/dist-lib/ai/exemplos/order-detail/components/ActivityTab.tsx +77 -0
  154. package/dist-lib/ai/exemplos/order-detail/components/AttachmentsTab.tsx +45 -0
  155. package/dist-lib/ai/exemplos/order-detail/components/CommentsTab.tsx +111 -0
  156. package/dist-lib/ai/exemplos/order-detail/components/DetailsTab.tsx +189 -0
  157. package/dist-lib/ai/exemplos/order-detail/components/OverviewTab.tsx +200 -0
  158. package/dist-lib/ai/exemplos/order-detail/components/section-card.tsx +85 -0
  159. package/dist-lib/ai/exemplos/order-detail/index.ts +1 -0
  160. package/dist-lib/ai/exemplos/order-detail/order-detail-screen.tsx +119 -0
  161. package/dist-lib/ai/exemplos/order-detail/order-mocks.ts +186 -0
  162. package/dist-lib/ai/exemplos/order-detail/order.types.ts +118 -0
  163. package/dist-lib/ai/global/componentes.md +217 -0
  164. package/dist-lib/ai/global/composicao.md +182 -0
  165. package/dist-lib/ai/indice.json +192 -0
  166. package/dist-lib/ai/lint/ds-lint-patterns.mjs +115 -0
  167. package/dist-lib/ai/manifest.json +42 -0
  168. package/dist-lib/ai/regras/design.md +88 -0
  169. package/dist-lib/ai/regras/temas.md +192 -0
  170. package/dist-lib/ai/regras-por-componente.json +103 -0
  171. package/dist-lib/ai/roteiros/app-builder/roteiro.md +155 -0
  172. package/dist-lib/ai/roteiros/auth-builder/roteiro.md +42 -0
  173. package/dist-lib/ai/roteiros/cards/roteiro.md +34 -0
  174. package/dist-lib/ai/roteiros/charts/roteiro.md +32 -0
  175. package/dist-lib/ai/roteiros/chat/roteiro.md +31 -0
  176. package/dist-lib/ai/roteiros/crud-builder/blueprint.md +63 -0
  177. package/dist-lib/ai/roteiros/crud-builder/entrevista.md +139 -0
  178. package/dist-lib/ai/roteiros/crud-builder/geracao.md +113 -0
  179. package/dist-lib/ai/roteiros/crud-builder/roteiro.md +89 -0
  180. package/dist-lib/ai/roteiros/dashboard-builder/blueprint.md +47 -0
  181. package/dist-lib/ai/roteiros/dashboard-builder/entrevista.md +62 -0
  182. package/dist-lib/ai/roteiros/dashboard-builder/geracao.md +88 -0
  183. package/dist-lib/ai/roteiros/dashboard-builder/roteiro.md +88 -0
  184. package/dist-lib/ai/roteiros/drawers/roteiro.md +41 -0
  185. package/dist-lib/ai/roteiros/list-builder/blueprint.md +94 -0
  186. package/dist-lib/ai/roteiros/list-builder/entrevista.md +188 -0
  187. package/dist-lib/ai/roteiros/list-builder/geracao.md +63 -0
  188. package/dist-lib/ai/roteiros/list-builder/roteiro.md +91 -0
  189. package/dist-lib/ai/roteiros/module-replicator/roteiro.md +56 -0
  190. package/dist-lib/ai/roteiros/page-detail/roteiro.md +32 -0
  191. package/dist-lib/ai/roteiros/page-edit/roteiro.md +31 -0
  192. package/dist-lib/ai/roteiros/screen-composer/roteiro.md +95 -0
  193. package/package.json +4 -1
@@ -0,0 +1,192 @@
1
+ {
2
+ "rotas": [
3
+ {
4
+ "sinais": [
5
+ "tabela",
6
+ "grade",
7
+ "grid de dados",
8
+ "crud",
9
+ "datatable",
10
+ "planilha",
11
+ "colunas"
12
+ ],
13
+ "rota": "skill `crud-builder` (`/ds-create-crud`) — entrevista guiada",
14
+ "roteiro": "crud-builder"
15
+ },
16
+ {
17
+ "sinais": [
18
+ "kanban",
19
+ "board",
20
+ "funil",
21
+ "pipeline de vendas",
22
+ "quadro por status/etapa"
23
+ ],
24
+ "rota": "skill `crud-builder` (`/ds-create-crud`) — kanban é `viewMode` do DataTable; ref. `example-finance` (kanban por situação)",
25
+ "roteiro": "crud-builder"
26
+ },
27
+ {
28
+ "sinais": [
29
+ "tabela e lista no mesmo lugar",
30
+ "alternar tabela/lista",
31
+ "toggle de visão tabela↔lista"
32
+ ],
33
+ "rota": "skill `crud-builder` (`/ds-create-crud`) — é `viewMode:\"list\"` + `listConfig` do DataTable (não DataList paralelo)",
34
+ "roteiro": "crud-builder"
35
+ },
36
+ {
37
+ "sinais": [
38
+ "lista de cards",
39
+ "árvore",
40
+ "hierarquia",
41
+ "rede/organograma",
42
+ "níveis",
43
+ "treeview",
44
+ "feed de cards"
45
+ ],
46
+ "rota": "skill `list-builder` (`/ds-create-list`) — entrevista guiada",
47
+ "roteiro": "list-builder"
48
+ },
49
+ {
50
+ "sinais": [
51
+ "lista",
52
+ "listagem de x"
53
+ ],
54
+ "rota": "PERGUNTE \"grade de colunas ou cards?\" → `crud-builder` ou `list-builder` (ou front-door `/ds-create-screen`)"
55
+ },
56
+ {
57
+ "sinais": [
58
+ "formulário",
59
+ "cadastro",
60
+ "tela de edição",
61
+ "editar x",
62
+ "novo x",
63
+ "multi-step"
64
+ ],
65
+ "rota": "skill `page-edit` → `example-edit-page`",
66
+ "roteiro": "page-edit"
67
+ },
68
+ {
69
+ "sinais": [
70
+ "detalhe",
71
+ "detalhamento",
72
+ "ficha",
73
+ "página de x com abas",
74
+ "visão geral do pedido"
75
+ ],
76
+ "rota": "skill `page-detail` → `example-order-detail`",
77
+ "roteiro": "page-detail"
78
+ },
79
+ {
80
+ "sinais": [
81
+ "login",
82
+ "entrar",
83
+ "acesso",
84
+ "autenticação",
85
+ "sign in",
86
+ "esqueci a senha",
87
+ "tela de login"
88
+ ],
89
+ "rota": "skill `auth-builder` (`/ds-create-login`) → `example-login` (fullscreen, painel por tokens)",
90
+ "roteiro": "auth-builder"
91
+ },
92
+ {
93
+ "sinais": [
94
+ "dashboard",
95
+ "painel",
96
+ "visão geral",
97
+ "indicadores"
98
+ ],
99
+ "rota": "skill `dashboard-builder` (`/ds-create-dashboard`) — entrevista → gate → geração ancorada no `example-dashboard`",
100
+ "roteiro": "dashboard-builder"
101
+ },
102
+ {
103
+ "sinais": [
104
+ "tabela + detalhe ao lado",
105
+ "clicar abre o detalhe",
106
+ "filtro no topo que muda tudo"
107
+ ],
108
+ "rota": "skill `screen-composer` — master-detail / cross-filter; monta as peças pelos builders + cabeia o estado compartilhado (a receita está na própria skill)",
109
+ "roteiro": "screen-composer"
110
+ },
111
+ {
112
+ "sinais": [
113
+ "gráfico",
114
+ "chart",
115
+ "barras/linha/área/pizza"
116
+ ],
117
+ "rota": "skill `charts` → `Chart/USAGE.md` + `example-dashboard`",
118
+ "roteiro": "charts"
119
+ },
120
+ {
121
+ "sinais": [
122
+ "financeiro",
123
+ "extrato",
124
+ "saldo",
125
+ "transações"
126
+ ],
127
+ "rota": "`example-finance` (puxar + adaptar)"
128
+ },
129
+ {
130
+ "sinais": [
131
+ "chat",
132
+ "inbox",
133
+ "conversas",
134
+ "atendimento"
135
+ ],
136
+ "rota": "skill `chat` → `example-chat`",
137
+ "roteiro": "chat"
138
+ },
139
+ {
140
+ "sinais": [
141
+ "drawer/painel de criar/editar/ver detalhe"
142
+ ],
143
+ "rota": "skill `drawers` → drawers do `example-finance`",
144
+ "roteiro": "drawers"
145
+ },
146
+ {
147
+ "sinais": [
148
+ "cards",
149
+ "blocos",
150
+ "painéis soltos",
151
+ "seções"
152
+ ],
153
+ "rota": "skill `cards` → `Card`/`Panel` + showcase",
154
+ "roteiro": "cards"
155
+ },
156
+ {
157
+ "sinais": [
158
+ "igual ao exemplo de <x>",
159
+ "estrutura do <x>"
160
+ ],
161
+ "rota": "puxar `example-<X>` e adaptar"
162
+ },
163
+ {
164
+ "sinais": [
165
+ "esqueleto do app",
166
+ "estrutura/base do app",
167
+ "shell + navegação + rotas",
168
+ "montar o app do zero"
169
+ ],
170
+ "rota": "skill `app-builder` (`/ds-create-app`) → `example-app-shell` (AppShell + nav-data + mapa de rotas declarativo)",
171
+ "roteiro": "app-builder"
172
+ },
173
+ {
174
+ "sinais": [
175
+ "replica o módulo x igual ao y",
176
+ "mesma estrutura pra outro segmento/vertical",
177
+ "clonar telas"
178
+ ],
179
+ "rota": "skill `module-replicator` (`/ds-replicate-module`) — avalia copiar × parametrizar; troca dados/rótulos, mantém estrutura",
180
+ "roteiro": "module-replicator"
181
+ },
182
+ {
183
+ "sinais": [
184
+ "que componente uso pra x",
185
+ "tem componente de y?",
186
+ "quais opções pra abas / filtro / data",
187
+ "o que o ds tem pra formulário"
188
+ ],
189
+ "rota": "rule `.claude/rules/ds-components.md` — vocabulário dos componentes por tarefa, com o critério de escolha. Não é pedido de tela: responda pela rule, não abra builder"
190
+ }
191
+ ]
192
+ }
@@ -0,0 +1,115 @@
1
+ /**
2
+ * ds-lint-patterns — FONTE ÚNICA dos anti-patterns de estilo do DS.
3
+ *
4
+ * Consumido por DOIS clientes (nunca duplique a tabela):
5
+ * - .claude/hooks/ds-lint-styles.sh → aviso local, nunca bloqueia
6
+ * - scripts/lint-styles.mjs --ratchet → check de CI, bloqueia violação nova
7
+ *
8
+ * ⚠️ E por um TERCEIRO, fora deste repo: este arquivo é foundational
9
+ * (`foundational-pairs.mjs`) e é copiado inteiro para
10
+ * `cli/templates/default/_claude/hooks/`, que o ds:link projeta no projeto do
11
+ * consumidor. Lá, `.ai/` e os caminhos internos do DS NÃO EXISTEM — os que
12
+ * aparecem nos comentários abaixo só resolvem aqui. Por isso nenhuma `msg`
13
+ * cita caminho: mensagem de lint tem que se bastar onde for lida.
14
+ *
15
+ * ⚠️ Só entram aqui regras erradas INDEPENDENTE DE CONTEXTO (valor divergente
16
+ * do token, classe que não existe). Regras que exigem contexto cross-elemento
17
+ * ou julgamento de intenção — L-004 (afordância de foco pode estar no wrapper)
18
+ * e L-007 (escolha de preset tipográfico) — pertencem ao revisor semântico,
19
+ * NÃO a este arquivo. Ver `.ai/specs/pipeline-governance-ci.md` §1.1.
20
+ *
21
+ * Buracos de cobertura conhecidos (não fechados nesta rodada — cada um exige
22
+ * medição/decisão de política própria; ver it.todo no teste):
23
+ * - `space-x-N` / `space-y-N` (utility legado, sem token DS direto) e
24
+ * `w-N`/`h-N` isolados fora das famílias `h|min-h|size` acima.
25
+ * - **Template literals**: o delimitador cobre aspas simples e duplas, mas
26
+ * NÃO crase — `` `flex gap-4` `` passa limpo (forma diferente, não
27
+ * coberta nesta rodada).
28
+ * - **Números fora do que foi medido no baseline**: as alternações listam
29
+ * só os valores encontrados na varredura de 2026-07-29, não a escala
30
+ * Tailwind inteira — `w-10`, `p-9`, `gap-11`, `h-20` passam limpo hoje.
31
+ * Ampliar a faixa numérica exige nova medição própria, fora desta correção.
32
+ */
33
+
34
+ export const DS_LINT_PATTERNS = [
35
+ {
36
+ id: "L-001",
37
+ re: /ring-ring-[a-z-]+\/[0-9]+/,
38
+ msg: "ring-ring-*/N — o token de ring já tem alpha embutido. Remova o /N.",
39
+ },
40
+ // `0` fora da alternação de propósito: não existe token DS pra zero
41
+ // (p-0/gap-0 são resets legítimos, comuns com `!` sobre base do shadcn).
42
+ {
43
+ id: "L-002",
44
+ re: /['"][^'"]*\bgap(-[xy])?-(1|2|3|4|5|6|7|8|9|10|12|14|16|20|24)\b[^'"]*['"]/,
45
+ msg: "gap-N literal → use gap-gp-{2xs,xs,sm,md,lg,xl,2xl}.",
46
+ },
47
+ {
48
+ id: "L-002",
49
+ re: /['"][^'"]*\b(px|py|pt|pb|pl|pr|p)-(1|2|3|4|5|6|7|8|10|12|16)\b[^'"]*['"]/,
50
+ msg: "pad/space literal → use p-sp-* (space) ou px-pad-* (pad).",
51
+ },
52
+ // ⚠️ Esta msg NÃO aponta pra arquivo, e é de propósito. Ela terminava com
53
+ // "ver .ai/context/tokens/sizing-shape-elevation.md" — caminho que existe aqui
54
+ // e que o CONSUMIDOR nunca recebe: este módulo é foundational (ver
55
+ // foundational-pairs.mjs) e roda também no `.claude/` projetado pelo ds:link,
56
+ // onde `.ai/` não existe. Mensagem que manda ler o inalcançável faz a pessoa
57
+ // parar de investigar achando que a resposta está em outro lugar (L-060).
58
+ // A regra aqui é: msg de lint se basta ou não cita caminho.
59
+ {
60
+ id: "L-002",
61
+ re: /['"][^'"]*\b(h|min-h|size)-(7|8|9|10|11|12|13|14|16)\b[^'"]*['"]/,
62
+ msg: "height/size fixo → use min-h-form-* (h-9=form-md, h-10=form-lg, h-11=form-xl). Se for quadrado, size-comp-*. Se for maior (~h-12 a h-16, 48-64px), não é form — use token de layout (ex.: h-layout-navbar).",
63
+ },
64
+ // `none` e `full` fora da alternação: são numericamente IDÊNTICOS ao token DS
65
+ // (--radius-radius-full: 9999px, --radius-radius-none: 0px) → não podem ser
66
+ // defeito. Já sm..3xl DIVERGEM (nativo lg=0.5rem vs DS 0.625rem) → defeito
67
+ // real. Side variants (rounded-t-lg) carregam o mesmo valor divergente.
68
+ {
69
+ id: "L-002",
70
+ re: /['"][^'"]*\brounded(-(t|b|l|r|tl|tr|bl|br|s|e|ss|se|es|ee))?-(sm|md|lg|xl|2xl|3xl)\b[^'"]*['"]/,
71
+ msg: "rounded-N nativo tem VALOR DIFERENTE do token DS (nativo lg=0.5rem vs DS 0.625rem) → use rounded-radius-*.",
72
+ },
73
+ {
74
+ id: "L-002",
75
+ re: /['"][^'"]*\bshadow-(2xs|xs|sm|md|lg|xl|2xl)\b[^'"]*['"]/,
76
+ msg: "shadow-N nativo → use shadow-sh-*.",
77
+ },
78
+ {
79
+ id: "L-003",
80
+ re: /['"][^'"]*\bring-3\b[^'"]*['"]/,
81
+ msg: "ring-3 não existe no Tailwind (vira no-op silencioso) → use ring-4.",
82
+ },
83
+ {
84
+ id: "L-005",
85
+ re: /['"][^'"]*\bbg-input\/[0-9]+[^'"]*['"]/,
86
+ msg: "bg-input/N é var do shadcn → use o token DS bg-bg-surface (ou bg-bg-muted).",
87
+ },
88
+ {
89
+ id: "IMPORT",
90
+ re: /from\s+['"]tailwind-variants['"]/,
91
+ msg: 'import errado: use `import { tv } from "@/utils/tv"` — o wrapper do DS carrega o twMergeConfig da L-016.',
92
+ },
93
+ ];
94
+
95
+ /** Linha de comentário não é código — citar uma classe proibida ao explicar a
96
+ * regra não pode reprovar o CI. Cobre `//`, `/*`, ` *` e o comentário JSX
97
+ * `{/* ... *\/}`, que entrou no escopo junto com o `.tsx`. */
98
+ const isComment = (text) => /^\s*(\/\/|\/\*|\*|\{\s*\/\*)/.test(text);
99
+
100
+ /**
101
+ * Roda todos os patterns contra uma lista de linhas.
102
+ * @param {Array<{n: number, text: string}>} lines
103
+ * @returns {Array<{id: string, msg: string, n: number, text: string}>}
104
+ */
105
+ export function scanLines(lines) {
106
+ const out = [];
107
+ for (const { n, text } of lines) {
108
+ if (isComment(text)) continue;
109
+ for (const p of DS_LINT_PATTERNS) {
110
+ // `re` sem flag /g → .test() não mantém lastIndex, seguro reusar.
111
+ if (p.re.test(text)) out.push({ id: p.id, msg: p.msg, n, text });
112
+ }
113
+ }
114
+ return out;
115
+ }
@@ -0,0 +1,42 @@
1
+ {
2
+ "pacote": "@snksergio/design-system",
3
+ "versao": "0.63.0",
4
+ "commit": "d9db4cd",
5
+ "gerado": "2026-09-15",
6
+ "conteudo": {
7
+ "roteiros": [
8
+ "app-builder",
9
+ "auth-builder",
10
+ "cards",
11
+ "charts",
12
+ "chat",
13
+ "crud-builder",
14
+ "dashboard-builder",
15
+ "drawers",
16
+ "list-builder",
17
+ "module-replicator",
18
+ "page-detail",
19
+ "page-edit",
20
+ "screen-composer"
21
+ ],
22
+ "exemplos": [
23
+ "app-shell",
24
+ "chat",
25
+ "clientes",
26
+ "dashboard",
27
+ "edit-page",
28
+ "finance",
29
+ "gantt",
30
+ "login",
31
+ "mapa-rede",
32
+ "order-detail"
33
+ ],
34
+ "componentes": 47,
35
+ "componentesComRegra": 19,
36
+ "rotas": 19,
37
+ "rotasComRoteiro": 15,
38
+ "arquivosDeExemplo": 108,
39
+ "arquivosDeBloco": 4,
40
+ "residuoClaudeCode": 42
41
+ }
42
+ }
@@ -0,0 +1,88 @@
1
+
2
+ # Regras de design iGreen (auto-carregadas)
3
+
4
+ Ao gerar ou editar QUALQUER UI neste projeto, aplique sem ser pedido. Detalhe e
5
+ contexto em `DESIGN.md` (raiz). API de cada componente em
6
+ `src/components/ui/<Nome>/USAGE.md`.
7
+
8
+ > **Modo submódulo.** Se existe `.claude/ds-config.json` com `"mode": "submodule"`, três
9
+ > coisas mudam nesta regra: (1) `DESIGN.md` e os `USAGE.md` ficam em `<dsPath>/` e
10
+ > `<dsPath>/src/components/ui/<Nome>/`, não na sua raiz; (2) **não** existe `igreen:add`,
11
+ > manifesto nem hook de proteção — os componentes estão no disco e você importa pelo
12
+ > `importBase`; (3) a regra de **não editar o tema/fundação** continua valendo, só que por
13
+ > disciplina, não por bloqueio: o que você editar no submódulo some no próximo `git pull`.
14
+
15
+ ## Composição de tela
16
+ - Wrapper de página: `flex flex-col h-full min-h-0 gap-gp-2xl`.
17
+ - **16px (`gap-gp-2xl`) entre o `PageHeader` e o próximo bloco** — nunca grudado.
18
+ - Conteúdo que precisa preencher (tabela): `className="flex-1 min-h-0"` + pai com altura.
19
+ - Forms: `<FormField>` (nunca `<label>` cru) + `gap-form-gap` (20px) entre campos.
20
+ - Card: densidade pela prop `size` do `<Card>` — `sm` 16 · **`md` 20 (default)** · `lg` 24 (tokens `p-pad-card-sm/md/lg`; `base` é alias depreciado de `md`); entre cards `gap-gp-md`/`gap-gp-lg`.
21
+
22
+ ## Tokens (classe DS antes de Tailwind literal)
23
+ ```
24
+ gap-4 → gap-gp-md p-4 → p-sp-md/p-pad-2xl rounded-lg → rounded-radius-lg
25
+ shadow-md → shadow-sh-md h-9/h-10 → min-h-form-md/lg size-5 → size-icon-md
26
+ ```
27
+ - **Prefira o token de COMPONENTE ao genérico**: altura `min-h-form-*` (não `h-9/10`), gap de form `gap-form-gap`, ícone `size-icon-*` (não `size-5`), padding de card `p-pad-card-*`, gutter `px-pad-page-*`, chrome `h-layout-*`, largura `max-w-*`. Genérico (`gap-gp-*`/`p-sp-*`/`px-pad-*`) só como fallback. Cheat-sheet completo em `DESIGN.md` ("Tokens de componente").
28
+ - Foco: `focus-visible:outline-none focus-visible:ring-4 focus-visible:ring-ring-{color}` (ring já tem alpha — nunca `/30`, nunca `ring-3`).
29
+ - Cor só por token semântico (`bg-bg-brand`, `text-fg-default`...). Zero hex em className. Destrutivo na API = `color="critical"`.
30
+
31
+ - ⚠️ **`max-w-container-*` NÃO existe** — `container` é o único namespace que não dobra o
32
+ prefixo. `max-w-md` já é os **768px do DS** (não os 448px do Tailwind); use `max-w-lg`,
33
+ `max-w-drawer-md`, `max-w-modal-sm`. A forma com `container` não emite CSS e some em silêncio.
34
+ - ⚠️ **`bg-bg-scrollbar-thumb` / `-hover` são de uso interno** dos `@utility scrollbar-*`
35
+ (alpha neutro, pra barra ter contraste próprio). Não use como fundo de elemento.
36
+
37
+ ## Tipografia
38
+ - Default interativo: `text-body-sm` (13/500). **7 papéis**: display/heading/title/body/caption/**stat**/code.
39
+ - **Número de KPI/métrica = `text-stat-{sm,md,lg,xl}`** (20/24/30/34px) + `tabular-nums`. Nunca `text-[Npx]` na unha, nunca `display-*`/`heading-*` pra valor de indicador.
40
+ - **Código / identificador / valor técnico = `text-code-{sm,md}`** (13/14px, Geist Mono) — chave de env, ID, hash, slug, path. Nunca `font-mono text-body-*` + `tracking-*` na unha: `code` é 1 dos 7 papéis e existe pra isto.
41
+ - Override de peso via `font-bold/semibold/medium/normal`. Nunca `text-xs font-semibold` avulso → use preset.
42
+
43
+ ## ⛔ O tema já traz o runtime — não redeclare
44
+ O `tailwind-theme.css` importado no seu CSS de entrada **não é só CSS vars**. Ele traz
45
+ `@font-face` do Geist, `--font-sans`/`--font-mono`, `@custom-variant dark`, regras de
46
+ `html`/`body`/`button` e as utilities `outline-float` e `scrollbar-thin`/`scrollbar-default`.
47
+
48
+ **Não redeclare nenhuma delas** no seu CSS: classe comum vence `@utility`, e a **segunda**
49
+ declaração de `@custom-variant` vence a primeira — você acaba com um comportamento no seu
50
+ projeto e outro no resto do sistema, sem erro nenhum. Os `.woff2` do Geist, sim, são seus
51
+ (o `@font-face` aponta pra `/fonts/`, raiz do site).
52
+
53
+ ## 🖼️ Trabalhando a partir de print / Figma / tela existente
54
+ A referência decide **conteúdo**; o DS decide **pele e comportamento**.
55
+ - **Dela**: copy, labels, nomenclatura, ordem dos campos. Copie e não "melhore" sem pedir — o jargão é do domínio do usuário.
56
+ - **Do DS, sempre**: fonte/família, tamanho, peso, tracking, cor, espaçamento, radius, sombra, foco e **comportamento de componente**. Preset existe → use o preset; compor na unha porque "ficou igual ao print" é drift.
57
+ - **Cor**: a referência escolhe o CONJUNTO (print escuro → `dark`; outra marca → `data-theme`), **nunca** o valor. Não derive hex do pixel.
58
+ - **Chrome (rail/menu/header) na referência = shell no escopo.** Print de app + pedido de "uma tela" é `shell + tela`. Não vai entregar o shell? Avise em linha destacada **antes** de gerar.
59
+
60
+ ## Antes de criar
61
+ - Existe exemplo/skill pra isso? (tabela→`/ds-create-crud`; ver `DESIGN.md` mapa de intenção). Puxe e adapte em vez de escrever do zero.
62
+ - Leu o `USAGE.md` do componente? Não invente prop/variante.
63
+ - `npx tsc --noEmit` limpo antes de entregar.
64
+
65
+ ## ⛔ Arquivos protegidos — NÃO editar (integridade do DS)
66
+ - **NUNCA edite** o tema/tokens (`src/styles/theme/**`) nem a fundação (`src/lib/utils.ts` = cn, `src/utils/tv.ts` = tv, `src/lib/lucide-types.ts`). São a base visual gerada pelo DS — editar quebra o sistema todo e some no próximo update.
67
+
68
+ > **O que de fato te impede, por canal:**
69
+ >
70
+ > | canal | trava |
71
+ > |---|---|
72
+ > | copy-in / scaffold | ✅ hook `protect-ds.mjs` **bloqueia** (`Edit`/`Write`/`MultiEdit`) e **avisa** em `Bash` que escreve nesses paths |
73
+ > | **submódulo** | ✅ **desde o CLI 0.24.0** — o `ds-link` projeta o hook, e ele reconhece o layout de submódulo (bloqueia `<dsPath>/src/styles/theme/**` e `<dsPath>/tokens/**`, sem confundir com o **seu** `src/`). ⚠️ **1 passo manual:** hook só roda se estiver no seu `.claude/settings.json`, e o `ds-link` não escreve nesse arquivo (é seu) — ele **imprime o bloco pronto** e repete o aviso até você colar |
74
+ > | npm install | ❌ nenhuma — o código vive em `node_modules` |
75
+ >
76
+ > ⚠️ **Até o CLI 0.25.1 esta tabela dizia "❌ nenhuma" no submódulo**, justificando com *"o
77
+ > `ds-link` não projeta `hooks/`"*. Era verdade até a 0.23.x e **deixou de ser na 0.24.0** —
78
+ > eu mudei o mecanismo e atualizei a `ds-channels.md`, mas não procurei as outras superfícies
79
+ > que descreviam a mesma coisa. Se você leu a versão anterior e concluiu que no submódulo não
80
+ > há rede de segurança: há, e vale colar o bloco.
81
+ - **Não edite o `.styles.ts`/internals de um componente do DS** pra "ajustar visual" de uma tela. Isso vira edição local (drift) e diverge do padrão. **Customize na COMPOSIÇÃO**: escolha variantes/props do componente + classes DS na SUA tela.
82
+ - Quer outra cor/tom? Use o **token/variante semântico** que já existe (`color="..."`, `bg-bg-*`). Não invente hex nem reescreva o token.
83
+ - Pra evoluir o tema de fato → re-sincronize com o DS (`npm run igreen:add -- theme`), não edite à mão.
84
+
85
+ ## Puxar componentes/exemplos (manifesto)
86
+ - **SEMPRE** `npm run igreen:add -- <item> [<item> ...]` — o wrapper instala E registra no `.igreen-ds/manifest.json` (baseline pro `igreen:drift`/`igreen:update`).
87
+ - **NUNCA** `npx shadcn add @igreen/...` cru: o componente instala mas fica **fora do manifesto** (o `igreen:drift` acusa "não gerenciado"). Se acontecer, recupere rodando `npm run igreen:add -- <os mesmos itens>` (idempotente; re-baseline sem sobrescrever edição).
88
+ - Commite o `.igreen-ds/manifest.json`.
@@ -0,0 +1,192 @@
1
+
2
+ # Temas de marca (iGreen DS)
3
+
4
+ O DS tem 5 marcas. Cada marca não-default é um **overlay de cor** escopado em
5
+ `[data-theme="<id>"]` que sobrescreve **só o que difere** do tema-base — 87 vars em `blue` e
6
+ `green`, 125 em `vibrant`, 166 em `pay`, contra ~350 do base.
7
+
8
+ | id | marca | arquivo |
9
+ |---|---|---|
10
+ | `default` | iGreen (verde padrão) | — **é** o tema-base, não tem overlay |
11
+ | `blue` | Azul | `brand-blue.css` |
12
+ | `green` | Verde (grass) | `brand-green.css` |
13
+ | `pay` | iGreen Pay | `brand-pay.css` |
14
+ | `vibrant` | iGreen Vibrant (verde fluorescente) | `brand-vibrant.css` |
15
+
16
+ ## ⛔ Antes de mexer: 2 fatos que causam 90% dos erros
17
+
18
+ 1. **Importar o CSS não ativa nada.** O overlay é escopado — sem
19
+ `data-theme="<id>"` no `<html>`, nenhuma regra casa e nada muda. Não existe erro:
20
+ falha em silêncio.
21
+ 2. **Ordem de import importa.** O overlay tem que vir **depois** do `tailwind-theme.css`.
22
+ Antes, o tema-base ganha por ordem de fonte.
23
+
24
+ Marca e claro/escuro são **eixos independentes**: `data-theme` no `<html>` + classe
25
+ `.dark`. Combinam livremente.
26
+
27
+ ```html
28
+ <html data-theme="vibrant" class="dark"> <!-- vibrant, escuro -->
29
+ <html data-theme="vibrant"> <!-- vibrant, claro -->
30
+ <html> <!-- default (sem atributo) -->
31
+ ```
32
+
33
+ ## Trocar o tema — identifique o modo PRIMEIRO
34
+
35
+ Existe `.claude/ds-config.json` com `"mode": "submodule"`?
36
+
37
+ ### Modo SUBMÓDULO
38
+
39
+ O **CSS** já está no disco. Importe (ajuste o caminho pro `dsPath` do `ds-config.json`):
40
+
41
+ ```css
42
+ @import "tailwindcss";
43
+ @import "../design-system/src/styles/theme/tailwind-theme.css";
44
+ @import "../design-system/src/styles/theme/brand-vibrant.css";
45
+ ```
46
+
47
+ Não rode `igreen:add` — em modo submódulo ele não se aplica. Tema novo chega com
48
+ `git pull` no submódulo. **Não** precisa de `@source`: o submódulo fica dentro da raiz do
49
+ projeto e o Tailwind v4 já escaneia daí.
50
+
51
+ ⚠️ **Duas coisas NÃO vêm com o submódulo**, e a segunda falha em silêncio:
52
+
53
+ 1. **As dependências.** O submódulo entrega código-fonte, não pacote — `npm i` das libs que os
54
+ componentes importam. O mínimo pra `Button` + `Modal`:
55
+ `tailwind-variants tailwind-merge clsx lucide-react @radix-ui/react-dialog @radix-ui/react-slot`.
56
+ O build quebra alto (`failed to resolve …`), então é fácil de achar.
57
+ 2. **Os arquivos da fonte Geist.** O `@font-face` viaja no tema, mas aponta pra `/fonts/*.woff2`
58
+ — raiz do **site**, não do submódulo. Copie:
59
+ `mkdir -p public/fonts && cp design-system/public/fonts/*.woff2 public/fonts/`.
60
+ Sem isso **não há erro**: o `font-family` segue dizendo `Geist`, o navegador recebe o
61
+ `index.html` no lugar do arquivo, e os 27 presets caem em system-ui. Confira com
62
+ `document.fonts.check("16px Geist")` — tem que ser `true`.
63
+
64
+ ### Modo COPY-IN (scaffold do CLI)
65
+
66
+ Cada tema é item do registry. Traga com o mesmo comando dos componentes:
67
+
68
+ ```bash
69
+ npm run igreen:add -- theme-vibrant # copia src/styles/theme/brand-vibrant.css
70
+ ```
71
+
72
+ Depois importe:
73
+
74
+ ```css
75
+ @import "./styles/theme/tailwind-theme.css";
76
+ @import "./styles/theme/brand-vibrant.css";
77
+ ```
78
+
79
+ ⚠️ O scaffold **apaga** os overlays não escolhidos no prompt "Tema de cor?". Se o arquivo
80
+ não está em `src/styles/theme/`, é porque outro tema foi escolhido na criação — traga com
81
+ o `igreen:add` acima.
82
+
83
+ ### Consumindo o DS por `npm install`
84
+
85
+ ⚠️ **A diretiva `@source` é OBRIGATÓRIA e é o erro nº 1 deste canal.** O Tailwind v4 **não
86
+ escaneia `node_modules`** — sem ela **nenhuma** classe do DS é gerada e os componentes
87
+ renderizam **sem estilo nenhum**, sem erro no console e sem build quebrado. Fácil concluir
88
+ que "o pacote está quebrado".
89
+
90
+ ```css
91
+ @import "tailwindcss";
92
+
93
+ /* Sem esta linha, zero classes do DS. Tem que cobrir `dist-lib/**`, não só o
94
+ index.mjs — as classes dos componentes flutuantes vivem nos *chunks*. */
95
+ @source "../node_modules/@snksergio/design-system/dist-lib/**/*.mjs";
96
+
97
+ @import "@snksergio/design-system/theme.css"; /* obrigatório */
98
+ @import "@snksergio/design-system/theme/brand-vibrant.css"; /* a marca */
99
+ ```
100
+
101
+ Ajuste o caminho do `@source` à profundidade do seu CSS de entrada (de `src/index.css`, a
102
+ raiz do projeto é `../`).
103
+
104
+ **Copie as fontes Geist** — o `@font-face` viaja no tema, mas aponta pra `/fonts/*.woff2`,
105
+ raiz do **site**:
106
+
107
+ ```bash
108
+ mkdir -p public/fonts
109
+ cp node_modules/@snksergio/design-system/dist-lib/fonts/*.woff2 public/fonts/
110
+ ```
111
+
112
+ ⚠️ Sem isso **não há erro**: o `font-family` segue dizendo `Geist`, o navegador recebe o
113
+ `index.html` no lugar do arquivo e os 27 presets caem em system-ui. Confira com
114
+ `document.fonts.check("16px Geist")` — tem que ser `true`.
115
+
116
+ Requer `@snksergio/design-system` **≥ 0.31.1** (antes disso o pacote levava só o tema-base);
117
+ as fontes só são publicadas a partir da **0.35.0**.
118
+
119
+ ## Trocar em runtime (seletor de marca)
120
+
121
+ ### Consumindo por `npm install` → use o hook `useBrand` (≥ 0.33.0)
122
+
123
+ Ele já resolve persistência, sincronia entre abas e a regra de que `default` significa
124
+ **remover** o atributo (o tema-base não tem overlay).
125
+
126
+ ```tsx
127
+ import { useBrand } from "@snksergio/design-system";
128
+
129
+ // Passe SÓ as marcas cujo overlay você importou no CSS.
130
+ const MINHAS_MARCAS = [
131
+ { id: "default", label: "iGreen", swatch: "oklch(0.5248 0.1415 150.9)" },
132
+ { id: "vibrant", label: "iGreen Vibrant", swatch: "#0fff00" },
133
+ ];
134
+
135
+ function SeletorDeMarca() {
136
+ const { brand, brands, current, setBrand } = useBrand({ brands: MINHAS_MARCAS });
137
+ return (
138
+ <select value={brand} onChange={(e) => setBrand(e.target.value)} aria-label="Marca">
139
+ {brands.map((b) => (
140
+ <option key={b.id} value={b.id}>{b.label}</option>
141
+ ))}
142
+ </select>
143
+ );
144
+ }
145
+ ```
146
+
147
+ ⚠️ **O catálogo é o ponto todo.** Sem o argumento, `useBrand` usa as 5 marcas do DS — e o
148
+ seletor listaria temas cujo CSS não está no seu bundle. `data-theme` com id sem overlay é
149
+ **no-op silencioso**: a opção aparece, o usuário clica, nada acontece, e não há erro.
150
+ Declare só o que você importou. `current` devolve a entrada ativa (label + swatch) pronta,
151
+ sem `find()`.
152
+
153
+ Valor persistido fora do catálogo cai na primeira entrada — então um `localStorage` com
154
+ `"pay"` de outro app não deixa este num tema órfão.
155
+
156
+ ### Copy-in / submódulo, ou sem o pacote npm
157
+
158
+ Escreve/remove o atributo na mão. `default` remove:
159
+
160
+ ```ts
161
+ function aplicarMarca(id: string) {
162
+ const root = document.documentElement;
163
+ if (id === "default") root.removeAttribute("data-theme");
164
+ else root.setAttribute("data-theme", id);
165
+ }
166
+ ```
167
+
168
+ Mesma armadilha: só funciona pras marcas cujo CSS **está no bundle**. Se o app oferece N
169
+ marcas ao usuário, importe os N overlays — e valide o id contra a lista que você importou,
170
+ não contra as 5 do DS.
171
+
172
+ ## Criar um tema novo
173
+
174
+ Marca muda **somente cor**. Spacing, sizing, radius, elevation e tipografia vêm sempre da
175
+ `default` — não há como uma marca alterá-los, por design. Se o pedido envolve mudar
176
+ espaçamento ou fonte "só nesta marca", **não é tema** — é outra coisa, pergunte.
177
+
178
+ Criar marca é trabalho no **repo do DS**, não aqui: 3 arquivos em `tokens/brands/<id>/`
179
+ (palette + color-light + color-dark, mesmo contrato de nomes da default) e
180
+ `npm run tokens:brand:<id>`. Neste projeto você **consome** o resultado. Se o usuário
181
+ quer uma marca que não existe, o caminho é abrir a demanda no DS — não improvisar CSS
182
+ sobrescrevendo tokens aqui (isso quebra o `protect-ds` e sai do sistema).
183
+
184
+ ## Nunca faça
185
+
186
+ - Sobrescrever CSS var de tema na unha (`--color-bg-brand: ...`) pra "simular" uma marca.
187
+ Use overlay; var solta divergem do dark, dos status e do resto do sistema.
188
+ - Duplicar o overlay dentro do projeto pra editar cor. Ele é gerado; edição some no
189
+ próximo update.
190
+ - Aplicar `data-theme` num wrapper interno em vez do `<html>`. Os dois blocos do overlay
191
+ (`[data-theme="x"]:not(.dark)` e `.dark[data-theme="x"]`) assumem marca e modo no MESMO
192
+ elemento — em elementos diferentes o light vaza pro dark.