@seedgrid/ai-toolkit 0.0.0-stage → 0.3.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 (225) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +151 -2
  3. package/dist/adapters/claude.js +114 -0
  4. package/dist/adapters/codex.js +108 -0
  5. package/dist/adapters/index.js +17 -0
  6. package/dist/adapters/shared.js +142 -0
  7. package/dist/adapters/types.js +1 -0
  8. package/dist/cli.js +203 -0
  9. package/dist/commands/common.js +98 -0
  10. package/dist/commands/doctor.js +290 -0
  11. package/dist/commands/init.js +9 -0
  12. package/dist/commands/install.js +107 -0
  13. package/dist/commands/remove.js +54 -0
  14. package/dist/commands/review.js +127 -0
  15. package/dist/commands/status.js +73 -0
  16. package/dist/commands/update.js +8 -0
  17. package/dist/commands/validate.js +27 -0
  18. package/dist/core/apply.js +181 -0
  19. package/dist/core/blocks.js +64 -0
  20. package/dist/core/content.js +528 -0
  21. package/dist/core/env.js +40 -0
  22. package/dist/core/frontmatter.js +29 -0
  23. package/dist/core/hash.js +14 -0
  24. package/dist/core/inspect.js +51 -0
  25. package/dist/core/lock.js +124 -0
  26. package/dist/core/paths.js +65 -0
  27. package/dist/core/plan.js +242 -0
  28. package/dist/core/tools.js +62 -0
  29. package/dist/core/types.js +11 -0
  30. package/dist/core/updates.js +121 -0
  31. package/docs/arquitetura.md +80 -0
  32. package/docs/compatibilidade.md +50 -0
  33. package/docs/formato.md +155 -0
  34. package/docs/instalacao.md +105 -0
  35. package/docs/manutencao.md +115 -0
  36. package/package.json +43 -4
  37. package/seedgridKB/SeedGrid/Extensions/Catalogo-de-enums.md +161 -0
  38. package/seedgridKB/SeedGrid/Extensions/Catalogo-de-propriedades.md +971 -0
  39. package/seedgridKB/SeedGrid/Extensions/Indice.md +63 -0
  40. package/seedgridKB/SeedGrid/Extensions/ai-pricing/Configuracao.md +124 -0
  41. package/seedgridKB/SeedGrid/Extensions/ai-pricing/Enums.md +40 -0
  42. package/seedgridKB/SeedGrid/Extensions/ai-pricing/Exemplos.md +97 -0
  43. package/seedgridKB/SeedGrid/Extensions/ai-pricing/Visao-geral.md +114 -0
  44. package/seedgridKB/SeedGrid/Extensions/apikeys/Configuracao-Rust.md +69 -0
  45. package/seedgridKB/SeedGrid/Extensions/apikeys/Configuracao.md +88 -0
  46. package/seedgridKB/SeedGrid/Extensions/apikeys/Enums.md +33 -0
  47. package/seedgridKB/SeedGrid/Extensions/apikeys/Exemplos.md +121 -0
  48. package/seedgridKB/SeedGrid/Extensions/apikeys/Rust.md +126 -0
  49. package/seedgridKB/SeedGrid/Extensions/apikeys/Visao-geral.md +111 -0
  50. package/seedgridKB/SeedGrid/Extensions/audit/Configuracao-Rust.md +93 -0
  51. package/seedgridKB/SeedGrid/Extensions/audit/Configuracao.md +127 -0
  52. package/seedgridKB/SeedGrid/Extensions/audit/Enums.md +66 -0
  53. package/seedgridKB/SeedGrid/Extensions/audit/Exemplos.md +151 -0
  54. package/seedgridKB/SeedGrid/Extensions/audit/Rust.md +120 -0
  55. package/seedgridKB/SeedGrid/Extensions/audit/Visao-geral.md +114 -0
  56. package/seedgridKB/SeedGrid/Extensions/backup/Configuracao-Rust.md +136 -0
  57. package/seedgridKB/SeedGrid/Extensions/backup/Configuracao.md +319 -0
  58. package/seedgridKB/SeedGrid/Extensions/backup/Enums.md +131 -0
  59. package/seedgridKB/SeedGrid/Extensions/backup/Exemplos.md +210 -0
  60. package/seedgridKB/SeedGrid/Extensions/backup/Rust.md +135 -0
  61. package/seedgridKB/SeedGrid/Extensions/backup/Visao-geral.md +150 -0
  62. package/seedgridKB/SeedGrid/Extensions/billing/Configuracao-Rust.md +86 -0
  63. package/seedgridKB/SeedGrid/Extensions/billing/Configuracao.md +243 -0
  64. package/seedgridKB/SeedGrid/Extensions/billing/Enums.md +165 -0
  65. package/seedgridKB/SeedGrid/Extensions/billing/Exemplos.md +205 -0
  66. package/seedgridKB/SeedGrid/Extensions/billing/Rust.md +109 -0
  67. package/seedgridKB/SeedGrid/Extensions/billing/Visao-geral.md +181 -0
  68. package/seedgridKB/SeedGrid/Extensions/broker/Configuracao-Rust.md +40 -0
  69. package/seedgridKB/SeedGrid/Extensions/broker/Visao-geral.md +114 -0
  70. package/seedgridKB/SeedGrid/Extensions/cache/Configuracao-Rust.md +73 -0
  71. package/seedgridKB/SeedGrid/Extensions/cache/Configuracao.md +112 -0
  72. package/seedgridKB/SeedGrid/Extensions/cache/Enums.md +36 -0
  73. package/seedgridKB/SeedGrid/Extensions/cache/Exemplos.md +149 -0
  74. package/seedgridKB/SeedGrid/Extensions/cache/Rust.md +81 -0
  75. package/seedgridKB/SeedGrid/Extensions/cache/Visao-geral.md +90 -0
  76. package/seedgridKB/SeedGrid/Extensions/commons/Configuracao.md +107 -0
  77. package/seedgridKB/SeedGrid/Extensions/commons/Enums.md +105 -0
  78. package/seedgridKB/SeedGrid/Extensions/commons/Exemplos.md +141 -0
  79. package/seedgridKB/SeedGrid/Extensions/commons/Visao-geral.md +99 -0
  80. package/seedgridKB/SeedGrid/Extensions/exchange/Configuracao.md +122 -0
  81. package/seedgridKB/SeedGrid/Extensions/exchange/Enums.md +29 -0
  82. package/seedgridKB/SeedGrid/Extensions/exchange/Exemplos.md +82 -0
  83. package/seedgridKB/SeedGrid/Extensions/exchange/Visao-geral.md +118 -0
  84. package/seedgridKB/SeedGrid/Extensions/filemanagement/Configuracao-Rust.md +110 -0
  85. package/seedgridKB/SeedGrid/Extensions/filemanagement/Configuracao.md +157 -0
  86. package/seedgridKB/SeedGrid/Extensions/filemanagement/Exemplos.md +157 -0
  87. package/seedgridKB/SeedGrid/Extensions/filemanagement/Rust.md +70 -0
  88. package/seedgridKB/SeedGrid/Extensions/filemanagement/Visao-geral.md +88 -0
  89. package/seedgridKB/SeedGrid/Extensions/login-tenancy/Configuracao-Rust.md +124 -0
  90. package/seedgridKB/SeedGrid/Extensions/login-tenancy/Configuracao.md +195 -0
  91. package/seedgridKB/SeedGrid/Extensions/login-tenancy/Enums.md +71 -0
  92. package/seedgridKB/SeedGrid/Extensions/login-tenancy/Exemplos.md +149 -0
  93. package/seedgridKB/SeedGrid/Extensions/login-tenancy/Rust.md +139 -0
  94. package/seedgridKB/SeedGrid/Extensions/login-tenancy/Visao-geral.md +130 -0
  95. package/seedgridKB/SeedGrid/Extensions/notification/Configuracao.md +141 -0
  96. package/seedgridKB/SeedGrid/Extensions/notification/Enums.md +52 -0
  97. package/seedgridKB/SeedGrid/Extensions/notification/Exemplos.md +141 -0
  98. package/seedgridKB/SeedGrid/Extensions/notification/Visao-geral.md +113 -0
  99. package/seedgridKB/SeedGrid/Extensions/privacy/Configuracao-Rust.md +67 -0
  100. package/seedgridKB/SeedGrid/Extensions/privacy/Configuracao.md +94 -0
  101. package/seedgridKB/SeedGrid/Extensions/privacy/Enums.md +79 -0
  102. package/seedgridKB/SeedGrid/Extensions/privacy/Exemplos.md +172 -0
  103. package/seedgridKB/SeedGrid/Extensions/privacy/Rust.md +107 -0
  104. package/seedgridKB/SeedGrid/Extensions/privacy/Visao-geral.md +90 -0
  105. package/seedgridKB/SeedGrid/Extensions/realtime/Configuracao-Rust.md +72 -0
  106. package/seedgridKB/SeedGrid/Extensions/realtime/Configuracao.md +104 -0
  107. package/seedgridKB/SeedGrid/Extensions/realtime/Exemplos.md +104 -0
  108. package/seedgridKB/SeedGrid/Extensions/realtime/Rust.md +69 -0
  109. package/seedgridKB/SeedGrid/Extensions/realtime/Visao-geral.md +105 -0
  110. package/seedgridKB/SeedGrid/Extensions/resilience/Configuracao-Rust.md +68 -0
  111. package/seedgridKB/SeedGrid/Extensions/resilience/Configuracao.md +186 -0
  112. package/seedgridKB/SeedGrid/Extensions/resilience/Enums.md +96 -0
  113. package/seedgridKB/SeedGrid/Extensions/resilience/Exemplos.md +229 -0
  114. package/seedgridKB/SeedGrid/Extensions/resilience/Rust.md +80 -0
  115. package/seedgridKB/SeedGrid/Extensions/resilience/Visao-geral.md +112 -0
  116. package/seedgridKB/SeedGrid/Extensions/runtime/Configuracao-Rust.md +90 -0
  117. package/seedgridKB/SeedGrid/Extensions/runtime/Visao-geral.md +114 -0
  118. package/seedgridKB/SeedGrid/Extensions/security/Configuracao-Rust.md +327 -0
  119. package/seedgridKB/SeedGrid/Extensions/security/Configuracao.md +510 -0
  120. package/seedgridKB/SeedGrid/Extensions/security/Enums.md +95 -0
  121. package/seedgridKB/SeedGrid/Extensions/security/Exemplos.md +218 -0
  122. package/seedgridKB/SeedGrid/Extensions/security/Rust.md +203 -0
  123. package/seedgridKB/SeedGrid/Extensions/security/Visao-geral.md +131 -0
  124. package/seedgridKB/SeedGrid/Extensions/subdomain-tenancy/Configuracao-Rust.md +188 -0
  125. package/seedgridKB/SeedGrid/Extensions/subdomain-tenancy/Configuracao.md +345 -0
  126. package/seedgridKB/SeedGrid/Extensions/subdomain-tenancy/Enums.md +117 -0
  127. package/seedgridKB/SeedGrid/Extensions/subdomain-tenancy/Exemplos.md +205 -0
  128. package/seedgridKB/SeedGrid/Extensions/subdomain-tenancy/Rust.md +161 -0
  129. package/seedgridKB/SeedGrid/Extensions/subdomain-tenancy/Visao-geral.md +142 -0
  130. package/seedgridKB/SeedGrid/Extensions/whatsapp/Configuracao-Rust.md +75 -0
  131. package/seedgridKB/SeedGrid/Extensions/whatsapp/Configuracao.md +152 -0
  132. package/seedgridKB/SeedGrid/Extensions/whatsapp/Enums.md +198 -0
  133. package/seedgridKB/SeedGrid/Extensions/whatsapp/Exemplos.md +173 -0
  134. package/seedgridKB/SeedGrid/Extensions/whatsapp/Rust.md +83 -0
  135. package/seedgridKB/SeedGrid/Extensions/whatsapp/Visao-geral.md +99 -0
  136. package/seedgridKB/SeedGrid/Mapa-dos-repositorios.md +112 -0
  137. package/seedgridKB/SeedGrid/SeedGrid-components/Indice.md +323 -0
  138. package/seedgridKB/SeedGrid/SeedGrid-components/buttons/API.md +257 -0
  139. package/seedgridKB/SeedGrid/SeedGrid-components/buttons/Exemplos.md +307 -0
  140. package/seedgridKB/SeedGrid/SeedGrid-components/buttons/Visao-geral.md +51 -0
  141. package/seedgridKB/SeedGrid/SeedGrid-components/datatable/API.md +174 -0
  142. package/seedgridKB/SeedGrid/SeedGrid-components/datatable/Exemplos.md +236 -0
  143. package/seedgridKB/SeedGrid/SeedGrid-components/datatable/Visao-geral.md +76 -0
  144. package/seedgridKB/SeedGrid/SeedGrid-components/digits/API.md +339 -0
  145. package/seedgridKB/SeedGrid/SeedGrid-components/digits/Exemplos.md +311 -0
  146. package/seedgridKB/SeedGrid/SeedGrid-components/digits/Visao-geral.md +57 -0
  147. package/seedgridKB/SeedGrid/SeedGrid-components/editor/API.md +125 -0
  148. package/seedgridKB/SeedGrid/SeedGrid-components/editor/Exemplos.md +116 -0
  149. package/seedgridKB/SeedGrid/SeedGrid-components/editor/Visao-geral.md +86 -0
  150. package/seedgridKB/SeedGrid/SeedGrid-components/feedback-e-exibicao/API.md +490 -0
  151. package/seedgridKB/SeedGrid/SeedGrid-components/feedback-e-exibicao/Exemplos.md +544 -0
  152. package/seedgridKB/SeedGrid/SeedGrid-components/feedback-e-exibicao/Visao-geral.md +69 -0
  153. package/seedgridKB/SeedGrid/SeedGrid-components/fundamentos/API.md +113 -0
  154. package/seedgridKB/SeedGrid/SeedGrid-components/fundamentos/Exemplos.md +159 -0
  155. package/seedgridKB/SeedGrid/SeedGrid-components/fundamentos/Visao-geral.md +92 -0
  156. package/seedgridKB/SeedGrid/SeedGrid-components/gadgets/API.md +516 -0
  157. package/seedgridKB/SeedGrid/SeedGrid-components/gadgets/Exemplos.md +629 -0
  158. package/seedgridKB/SeedGrid/SeedGrid-components/gadgets/Visao-geral.md +80 -0
  159. package/seedgridKB/SeedGrid/SeedGrid-components/inputs-selecao/API.md +615 -0
  160. package/seedgridKB/SeedGrid/SeedGrid-components/inputs-selecao/Exemplos.md +384 -0
  161. package/seedgridKB/SeedGrid/SeedGrid-components/inputs-selecao/Visao-geral.md +111 -0
  162. package/seedgridKB/SeedGrid/SeedGrid-components/inputs-texto/API.md +661 -0
  163. package/seedgridKB/SeedGrid/SeedGrid-components/inputs-texto/Exemplos.md +312 -0
  164. package/seedgridKB/SeedGrid/SeedGrid-components/inputs-texto/Visao-geral.md +123 -0
  165. package/seedgridKB/SeedGrid/SeedGrid-components/layout/API.md +1090 -0
  166. package/seedgridKB/SeedGrid/SeedGrid-components/layout/Exemplos.md +1172 -0
  167. package/seedgridKB/SeedGrid/SeedGrid-components/layout/Visao-geral.md +98 -0
  168. package/seedgridKB/SeedGrid/SeedGrid-components/modulos/Visao-geral.md +98 -0
  169. package/seedgridKB/SeedGrid/SeedGrid-components/modulos/fe-apikeys.md +118 -0
  170. package/seedgridKB/SeedGrid/SeedGrid-components/modulos/fe-audit.md +88 -0
  171. package/seedgridKB/SeedGrid/SeedGrid-components/modulos/fe-backup.md +131 -0
  172. package/seedgridKB/SeedGrid/SeedGrid-components/modulos/fe-billing-platform.md +132 -0
  173. package/seedgridKB/SeedGrid/SeedGrid-components/modulos/fe-billing-user.md +120 -0
  174. package/seedgridKB/SeedGrid/SeedGrid-components/modulos/fe-login-tenancy.md +119 -0
  175. package/seedgridKB/SeedGrid/SeedGrid-components/modulos/fe-security.md +427 -0
  176. package/seedgridKB/SeedGrid/SeedGrid-components/modulos/fe-self-enter.md +104 -0
  177. package/seedgridKB/SeedGrid/SeedGrid-components/modulos/fe-subdomain-tenancy.md +110 -0
  178. package/seedgridKB/SeedGrid/SeedGrid-components/navegacao-e-overlay/API.md +490 -0
  179. package/seedgridKB/SeedGrid/SeedGrid-components/navegacao-e-overlay/Exemplos.md +561 -0
  180. package/seedgridKB/SeedGrid/SeedGrid-components/navegacao-e-overlay/Visao-geral.md +82 -0
  181. package/seedgridKB/SeedGrid/SeedGrid-components/pacotes/Visao-geral.md +68 -0
  182. package/seedgridKB/SeedGrid/SeedGrid-components/pacotes/fe-commons.md +61 -0
  183. package/seedgridKB/SeedGrid/SeedGrid-components/pacotes/fe-core.md +140 -0
  184. package/seedgridKB/SeedGrid/SeedGrid-components/pacotes/fe-playground.md +112 -0
  185. package/seedgridKB/SeedGrid/SeedGrid-components/pacotes/fe-theme.md +97 -0
  186. package/seedgridKB/SeedGrid/SeedGrid-components/providers/API.md +177 -0
  187. package/seedgridKB/SeedGrid/SeedGrid-components/providers/Exemplos.md +332 -0
  188. package/seedgridKB/SeedGrid/SeedGrid-components/providers/Visao-geral.md +106 -0
  189. package/seedgridKB/SeedGrid/SeedGrid-components/showcase.md +70 -0
  190. package/seedgridKB/SeedGrid/Toolkit/agents/arquiteto.md +53 -0
  191. package/seedgridKB/SeedGrid/Toolkit/agents/backend-java.md +45 -0
  192. package/seedgridKB/SeedGrid/Toolkit/agents/backend-rust.md +43 -0
  193. package/seedgridKB/SeedGrid/Toolkit/agents/frontend-react.md +41 -0
  194. package/seedgridKB/SeedGrid/Toolkit/agents/qa.md +44 -0
  195. package/seedgridKB/SeedGrid/Toolkit/agents/revisor.md +40 -0
  196. package/seedgridKB/SeedGrid/Toolkit/references/fluxo-de-trabalho.md +78 -0
  197. package/seedgridKB/SeedGrid/Toolkit/references/glossario.md +15 -0
  198. package/seedgridKB/SeedGrid/Toolkit/references/modos-shared-native.md +27 -0
  199. package/seedgridKB/SeedGrid/Toolkit/rules/backend-java-seedgrid.md +54 -0
  200. package/seedgridKB/SeedGrid/Toolkit/rules/coordenacao.md +39 -0
  201. package/seedgridKB/SeedGrid/Toolkit/rules/formato-entrega.md +29 -0
  202. package/seedgridKB/SeedGrid/Toolkit/rules/frontend-seedgrid.md +47 -0
  203. package/seedgridKB/SeedGrid/Toolkit/rules/personalizacao-local.md +22 -0
  204. package/seedgridKB/SeedGrid/Toolkit/skills/planejar-mudanca/SKILL.md +38 -0
  205. package/seedgridKB/SeedGrid/Toolkit/skills/revisar-codigo/SKILL.md +33 -0
  206. package/seedgridKB/SeedGrid/Toolkit/skills/revisar-codigo/references/checklist.md +25 -0
  207. package/seedgridKB/SeedGrid/Toolkit/skills/seedgrid-backend-crud/SKILL.md +29 -0
  208. package/seedgridKB/SeedGrid/Toolkit/skills/seedgrid-bump/SKILL.md +26 -0
  209. package/seedgridKB/SeedGrid/Toolkit/skills/seedgrid-crud/SKILL.md +221 -0
  210. package/seedgridKB/SeedGrid/Toolkit/skills/seedgrid-crud/agents/openai.yaml +4 -0
  211. package/seedgridKB/SeedGrid/Toolkit/skills/seedgrid-crud/references/checklist.md +31 -0
  212. package/seedgridKB/SeedGrid/Toolkit/skills/seedgrid-crud/references/patterns.md +185 -0
  213. package/seedgridKB/SeedGrid/Toolkit/skills/seedgrid-crud/references/routing.md +66 -0
  214. package/seedgridKB/SeedGrid/Toolkit/skills/seedgrid-new-screen/SKILL.md +56 -0
  215. package/seedgridKB/SeedGrid/Toolkit/skills/seedgrid-new-screen/agents/openai.yaml +4 -0
  216. package/seedgridKB/SeedGrid/Toolkit/skills/seedgrid-new-screen/references/checklist.md +32 -0
  217. package/seedgridKB/SeedGrid/Toolkit/skills/seedgrid-new-screen/references/steps.md +114 -0
  218. package/seedgridKB/SeedGrid/Toolkit/skills/seedgrid-review/SKILL.md +61 -0
  219. package/seedgridKB/SeedGrid/Toolkit/skills/validar-mudanca/SKILL.md +29 -0
  220. package/seedgridKB/SeedGrid/Toolkit/templates/decisao-arquitetura.md +29 -0
  221. package/seedgridKB/SeedGrid/Toolkit/templates/especificacao-tarefa.md +32 -0
  222. package/seedgridKB/SeedGrid/Toolkit/templates/relatorio-validacao.md +30 -0
  223. package/seedgridKB/SeedGrid/Versoes.md +64 -0
  224. package/seedgridKB/SeedGrid/Visao-geral.md +35 -0
  225. package/seedgridKB/manifest.json +142 -0
@@ -0,0 +1,110 @@
1
+ ---
2
+ tags: [seedgrid, front, modulo, fe-subdomain-tenancy]
3
+ fonte: front/seedgrid-fe-components/packages/modules/seedgrid-fe-subdomain-tenancy
4
+ branch: main
5
+ commit: ad30fc11de
6
+ analisado-em: 2026-10-14
7
+ ---
8
+
9
+ # @seedgrid/fe-subdomain-tenancy
10
+
11
+ Módulo front de **multitenancy por subdomínio**: cada tenant vive em `empresa.<sufixo>`, com signup público que cria tenant + usuário root e confirmação de e-mail por código. Variante exclusiva com [[SeedGrid/SeedGrid-components/modulos/fe-login-tenancy|fe-login-tenancy]] (`variantGroup: "tenancy"`). Compõe sobre o [[SeedGrid/SeedGrid-components/modulos/fe-security|fe-security]]. Parte dos [[SeedGrid/SeedGrid-components/modulos/Visao-geral|Módulos front]].
12
+
13
+ Backend: [[SeedGrid/Extensions/subdomain-tenancy/Visao-geral|extension subdomain-tenancy]] — `SubdomainTenancyPaths` bate com `java/seedgrid-quarkus-ext-subdomain-tenancy/runtime/src/main/java/br/com/seedgrid/subdomaintenancy/configs/RestControllerPath.java` (`/public/tenants`, `/validate-email`, `/resend-email`) — **Confirmado**.
14
+
15
+ ## Pacote
16
+
17
+ | Item | Valor |
18
+ |---|---|
19
+ | Nome npm / versão | `@seedgrid/fe-subdomain-tenancy` `2026.7.0` |
20
+ | peerDependencies | `@seedgrid/fe-core: *`, `@seedgrid/fe-security: *`, `react: ^18.2.0 \|\| ^19.0.0` (opcional) |
21
+ | `files` | `dist`, `scaffold` |
22
+ | Build | `tsc -p tsconfig.json` + `postbuild` `emit-module-manifest.mjs` |
23
+ | Test (script) | `pnpm run build && node --test tests/module-manifest.test.mjs tests/subdomain-rules.test.mjs` |
24
+
25
+ `exports`: `.` → `./dist/index.{d.ts,js}`; `./server` → `./dist/server/index.{d.ts,js}`; `./client` → `./dist/client/index.{d.ts,js}`.
26
+
27
+ Dependência de módulo: **requer `security`** (tipo `SecurityServer`; scaffold usa `resolveApiBaseUrlForHostname` de `@/config/environment` e `@/modules/core`).
28
+
29
+ ## Exports públicos
30
+
31
+ | Export | Tipo | Subpath | Descrição | Fonte |
32
+ |---|---|---|---|---|
33
+ | `BrazilianState` | type | `.` | UF (`string`) | `front/seedgrid-fe-components/packages/modules/seedgrid-fe-subdomain-tenancy/src/tenant-signup.ts` |
34
+ | `TenantAddress`, `TenantLegalRepresentative`, `TenantSignupRequest`, `TenantValidateEmailRequest`, `TenantSignupResult` | interfaces | `.` | DTOs do signup (`TenantSignupResult` com shape flexível, não confirmado) | `.../src/tenant-signup.ts` |
35
+ | `SubdomainTenancyPaths` | const | `.` | `tenants`, `validateEmail`, `resendEmail(subdomain)` | `.../src/paths.ts → SubdomainTenancyPaths` |
36
+ | `RESERVED_SUBDOMAINS` | const | `.` | 35 nomes reservados (`admin`, `api`, `www`, …) | `.../src/subdomain-rules.ts → RESERVED_SUBDOMAINS` |
37
+ | `SubdomainValidationKey` | type | `.` | Chaves i18n `multitenancy.signup.fields.subdomain.validation.*` | `.../src/subdomain-rules.ts` |
38
+ | `normalizeSubdomain` | função | `.` | trim, minúsculas, não `[a-z0-9-]` → `-`, colapsa/remove hífens | `.../src/subdomain-rules.ts → normalizeSubdomain` |
39
+ | `isReservedSubdomain` | função | `.` | Testa contra `RESERVED_SUBDOMAINS` | idem |
40
+ | `getSubdomainValidationKey` | função | `.` | `required` / `too_short` (<3) / `too_long` (>32) / `invalid_pattern` / `reserved` / `null` | idem |
41
+ | `validateSubdomain` | função | `.` | Chave ou texto traduzido (`translate?`) | idem |
42
+ | `TenantProvider` | componente React | `./client` | Contexto com `currentTenant` (inicial `"default"`) e `setTenant` | `.../src/client/tenant-provider.tsx → TenantProvider` |
43
+ | `useTenantContext` | hook | `./client` | Lança erro fora do provider | idem |
44
+ | `createSubdomainTenancyServer` | função | `./server` | `(session) => SubdomainTenancyServer` | `.../src/server/create-subdomain-tenancy-server.ts` |
45
+ | `SubdomainTenancyServer` | interface | `./server` | `signupTenant`, `validateEmail`, `resendEmail` | idem |
46
+
47
+ Contagem: `.` = 13; `./client` = 2; `./server` = 2.
48
+
49
+ ## Registro no @seedgrid/fe-core (manifesto do CLI)
50
+
51
+ `SeedGridCliModuleManifest` ([[SeedGrid/SeedGrid-components/pacotes/fe-core|@seedgrid/fe-core]]): `id: "subdomain-tenancy"`, `configKey: "subdomain-tenancy"`, `requires: ["security"]`, `variantGroup: "tenancy"`, `provider: [{ import: "TenantProvider", from: "@seedgrid/fe-subdomain-tenancy/client" }]` (o CLI envolve o app com o provider). Sem `navigation`/`messages`.
52
+
53
+ ## Páginas e rotas (scaffold)
54
+
55
+ | Rota | Arquivo | Acesso |
56
+ |---|---|---|
57
+ | `/signup` | `scaffold/src/app/(public)/signup/page.tsx` | público; wizard BR (CNPJ, ViaCEP, UF/cidade), subdomínio validado em tempo real; após validar o e-mail redireciona para `<protocolo>://<subdominio>.<tenantHostSuffix>/auth/login` |
58
+ | `GET /api/locations/states?query=` | `scaffold/src/app/api/locations/states/route.ts` | Route Handler; proxy para `https://cities.seedgrid.com.br/states?countryId=1` |
59
+ | `GET /api/locations/cities?stateId=&query=` | `scaffold/src/app/api/locations/cities/route.ts` | Route Handler; proxy para `https://cities.seedgrid.com.br/cities?stateId=` |
60
+
61
+ Server actions (scaffold, `"use server"`): `createPublicTenantAction`, `validatePublicTenantEmailAction`, `resendPublicTenantActivationEmailAction` (em `scaffold/src/modules/subdomain-tenancy/server/`), com `createApiClient` de `@seedgrid/fe-core`, `requireAuth: false`, retry 2× em 429/502/503/504. Nenhuma permissão envolvida.
62
+
63
+ ## APIs backend chamadas
64
+
65
+ | Método | Path | Onde |
66
+ |---|---|---|
67
+ | POST | `/public/tenants` | `signupTenant` (lib) / `createPublicTenantAction` |
68
+ | POST | `/public/tenants/validate-email` | `validateEmail` / `validatePublicTenantEmailAction` |
69
+ | POST | `/public/tenants/resend-email?subdomain=` | `resendEmail` / `resendPublicTenantActivationEmailAction` |
70
+
71
+ 3 endpoints do backend SeedGrid + 2 externos (`cities.seedgrid.com.br`).
72
+
73
+ ## Separação client/server
74
+
75
+ `.` client-safe (regras puras, testáveis em Node); `./client` React; `./server` SERVER-ONLY. A URL base pública é resolvida por hostname (`x-forwarded-host` → `host`, sem porta) em `scaffold/src/modules/subdomain-tenancy/server/public-api-base-url.ts → resolvePublicApiBaseUrl`; lança erro se não houver host.
76
+
77
+ ## Configuração
78
+
79
+ | Propriedade | Tipo | Valores aceitos | Padrão | Obrigatória | Comportamento | Uso | Relações | Fase | Origem |
80
+ |---|---|---|---|---|---|---|---|---|---|
81
+ | `SEEDGRID_CITIES_API_USERNAME` | string (env) | usuário da API de cidades | — | Condicional (sem ela, UF/cidade ficam vazios) | Compõe Basic auth com a key; ausente → responde `[]` 200 | `GET /api/locations/states`, `/cities` | exige `SEEDGRID_CITIES_API_KEY` | runtime server | `scaffold/src/app/api/locations/states/route.ts → GET`; `.../cities/route.ts → GET` |
82
+ | 🔒 `SEEDGRID_CITIES_API_KEY` | string (env) | `<SEGREDO:cities-api-key>` | — | Condicional (idem) | Senha do Basic auth para `cities.seedgrid.com.br` | idem | exige `SEEDGRID_CITIES_API_USERNAME` | runtime server | idem |
83
+
84
+ Valores do app usados pelo scaffold (definidos fora deste pacote, em `@/config/environment`): `appEnvironment.hosts.tenantHostSuffix`, `appEnvironment.deployment.protocol`, `appEnvironment.namespace`, `resolveApiBaseUrlForHostname`. A URL `https://cities.seedgrid.com.br` é constante no código (`CITIES_API_BASE_URL`), não configurável.
85
+
86
+ ## Exemplos
87
+
88
+ Fonte: README (validação e contexto). Uso real das regras: `scaffold/src/modules/subdomain-tenancy/server/create-public-tenant-action.ts` (normaliza e valida antes do POST).
89
+
90
+ ```ts
91
+ import { normalizeSubdomain, validateSubdomain } from "@seedgrid/fe-subdomain-tenancy";
92
+ const sub = normalizeSubdomain(input);
93
+ const erro = validateSubdomain(sub); // null se ok
94
+ ```
95
+
96
+ Sem consumidor em `apps/showcase`.
97
+
98
+ ## Testes (não executados)
99
+
100
+ - `tests/module-manifest.test.mjs`: `id`, `requires`, `variantGroup`, `configKey`, `provider`.
101
+ - `tests/subdomain-rules.test.mjs`: normalização, reservados, chaves `required/too_short/too_long/reserved`, `validateSubdomain` com e sem tradutor (`invalid_pattern` declarado inalcançável hoje).
102
+
103
+ ## Limitações
104
+
105
+ - `useTenantContext()` expõe `currentTenant` (string) e `setTenant`, não um objeto `tenant`.
106
+ - `TenantProvider` só guarda uma string em estado (`"default"`); não deriva o tenant do host.
107
+ - `createSubdomainTenancyServer` usa `apiFetchSecurity` (sessão), inadequado para o signup pré-auth; o scaffold usa actions próprias.
108
+ - Chaves i18n usam o prefixo `multitenancy.*`; o pacote não entrega mensagens (sem `messages` no manifesto).
109
+ - `TenantAddress.phone` é opcional aqui; no login-tenancy é obrigatório.
110
+
@@ -0,0 +1,490 @@
1
+ ---
2
+ tags: [seedgrid, front, component, navegacao-e-overlay]
3
+ fonte: front/seedgrid-fe-components/packages/seedgrid-fe-components/src/menus, front/seedgrid-fe-components/packages/seedgrid-fe-components/src/overlay, front/seedgrid-fe-components/packages/seedgrid-fe-components/src/wizard
4
+ branch: main
5
+ commit: ad30fc11de
6
+ analisado-em: 2026-10-14
7
+ ---
8
+
9
+ # API — navegação e overlay
10
+
11
+ Visão geral: [[SeedGrid/SeedGrid-components/navegacao-e-overlay/Visao-geral|Navegação e overlay]] · Exemplos: [[SeedGrid/SeedGrid-components/navegacao-e-overlay/Exemplos|Exemplos]] · i18n/estilos: [[SeedGrid/SeedGrid-components/fundamentos/API|Fundamentos › API]]
12
+
13
+ > **Como ler as tabelas.** Geradas a partir do tipo TypeScript real do 1º parâmetro de cada componente (TS checker, commit `ad30fc11de`) — lista completa das props próprias. **Padrão**: valor sem marca = inicializador na desestruturação do componente (Confirmado); `ᶠ` = fallback interno `??` no corpo do componente (Confirmado, expressão pode estar abreviada); `ᵇ` = padrão aplicado pelo componente base para o qual a prop é repassada; `ᵐ` = declarado só no `*.meta.ts`; `ˢ` = declarado só na tabela de props do showcase (`ᵐ`/`ˢ` = Não confirmado no código); `—` = sem padrão. **Descrição**: JSDoc > `*.meta.ts` > tabela do showcase (textos originais, sem acento quando assim na fonte); *(Inferência)* = escrita a partir da leitura do código. **Obrigatória** = prop não opcional no tipo.
14
+
15
+ Nenhum componente deste grupo usa `React.forwardRef`: **nenhum aceita `ref`** (Confirmado — todos são `function` simples). Nenhum repassa atributos HTML arbitrários (os tipos não estendem `React.HTMLAttributes`).
16
+
17
+ ---
18
+
19
+ ## SgDockMenu
20
+
21
+ Dock flutuante de ações (ícone + rótulo em tooltip), com badges, efeito *magnify*, 8 posições ancoradas, arraste opcional e persistência da posição. Fonte: `src/menus/SgDockMenu.tsx` → `SgDockMenu`.
22
+
23
+ ### Import
24
+
25
+ ```tsx
26
+ import { SgDockMenu, type SgDockMenuProps, type SgDockMenuItem, type SgDockMenuPosition, type SgDockMenuOrientation } from "@seedgrid/fe-components";
27
+ ```
28
+
29
+ ### Props
30
+
31
+ | Prop | Tipo | Padrão | Obrigatória | Descrição |
32
+ |---|---|---|---|---|
33
+ | `id` | `string` | — | Não | Unique identifier for the dock |
34
+ | `items` | `SgDockMenuItem[]` | — | Sim | Items to display in the dock |
35
+ | `position` | `SgDockMenuPosition` = `"left-top" \| "left-center" \| "left-bottom" \| "center-top" \| "center-bottom" \| "right-top" \| "right-center" \| "right-bottom"` | `"center-bottom"` | Não | Position of the dock |
36
+ | `enableDragDrop` | `boolean` | `false` | Não | Enable drag and drop repositioning |
37
+ | `dragId` | `string` | — | Não | ID for persisting drag position |
38
+ | `offset` | `{ x?: number; y?: number }` | — | Não | Deslocamento em px somado à posição fixa (afasta da borda ancorada: `right`/`bottom` são reduzidos, `left`/`top` aumentados). Base da borda: 24px (`DOCK_EDGE`). *(Inferência)* |
39
+ | `className` | `string` | `""` | Não | Custom class name for container |
40
+ | `itemClassName` | `string` | `""` | Não | Custom class name for items |
41
+ | `zIndex` | `number` | `50` | Não | Z-index |
42
+ | `itemSize` | `number` | `48` | Não | Item size in pixels |
43
+ | `gap` | `number` | `16` | Não | Gap between items in pixels |
44
+ | `backgroundColor` | `string` | `"rgb(var(--sg-surface, 248 250 252) / 0.9)"` | Não | Background color |
45
+ | `showLabels` | `boolean` | `true` | Não | Show labels on hover |
46
+ | `magnify` | `boolean` | `true` | Não | Magnification effect on hover |
47
+ | `magnifyScale` | `number` | `1.5` | Não | Magnification scale |
48
+ | `borderRadius` | `number` | `16` | Não | Border radius |
49
+ | `elevation` | `"none" \| "sm" \| "md" \| "lg"` | `"lg"` | Não | Shadow elevation |
50
+ | `style` | `React.CSSProperties` | — | Não | Custom style |
51
+
52
+ ### Eventos e callbacks
53
+
54
+ - Não há callback no nível do componente. Cada item tem `onClick?: () => void`, chamado no clique do botão do item, **exceto** se `item.disabled` ou se o ponteiro acabou de arrastar o dock (> 3px de movimento). **Confirmado** (`handleItemClick`).
55
+ - Arraste (`enableDragDrop`): botão esquerdo do ponteiro inicia; a posição é limitada à viewport (ou ao `offsetParent` quando `style.position === "absolute"`) e salva no `pointerup` se houver `dragId`.
56
+ - Menu de contexto (clique direito): só abre quando `enableDragDrop && dragId` e já existe posição salva/arrastada (`buildDockMenuContextMenuState`). Mostra um diálogo de confirmação "resetar posição" (textos i18n `components.dock.resetPosition`/`resetConfirm`, `components.actions.cancel`/`confirm`); confirmar apaga a posição persistida e volta à posição ancorada. **Confirmado**.
57
+
58
+ ### Ref
59
+
60
+ Não aceita `ref`.
61
+
62
+ ### Children, slots e composição
63
+
64
+ Não recebe `children`; o conteúdo vem de `items`. Ícones são `ReactNode` livres (o showcase usa `lucide-react`). Posição: `position: fixed` por padrão; passe `style={{ position: "absolute" }}` para ancorar dentro de um container `relative` (o arraste passa a ser limitado ao pai e a chave de persistência termina em `:parent`).
65
+
66
+ ### Contexto, providers e hooks
67
+
68
+ - Consome `useComponentsI18n()` (textos do diálogo de reset).
69
+ - Consome `useSgPersistence()` e o hook interno `useHasSgEnvironmentProvider()`: dentro de `SgEnvironmentProvider` a posição é salva via estratégia de persistência do ambiente; fora dele, em `localStorage`. Valor salvo inválido é descartado e apagado (`parseStoredPanelDragPosition`). Ver [[SeedGrid/SeedGrid-components/providers/API|Providers]].
70
+
71
+ ### Acessibilidade
72
+
73
+ - Cada item é `<button type="button">` com `aria-label={item.label}`, `title={item.label}` e `disabled={item.disabled}` (coberto por `tests/buttons-menus.test.mjs`). **Confirmado**.
74
+ - O container não tem `role` (ex.: `toolbar`/`menu`) nem navegação por setas; o diálogo de reset não tem `role="dialog"` nem tratamento de `Esc` (fecha clicando no fundo). **Confirmado** (ausência no código).
75
+
76
+ ### Tipos auxiliares exportados
77
+
78
+ `SgDockMenuItem`:
79
+
80
+ | Campo | Tipo | Obrigatório | Descrição |
81
+ |---|---|---|---|
82
+ | `id` | `string` | Sim | Identificador único (chave da lista) |
83
+ | `icon` | `React.ReactNode` | Sim | Ícone exibido |
84
+ | `label` | `string` | Sim | Rótulo/tooltip e `aria-label` |
85
+ | `onClick` | `() => void` | Não | Handler de clique |
86
+ | `disabled` | `boolean` | Não | Desabilita o item (opacidade 0.5, cursor `not-allowed`) |
87
+ | `badge` | `string \| number` | Não | Conteúdo da bolha de badge |
88
+ | `className` | `string` | Não | Classe extra do item |
89
+
90
+ `SgDockMenuPosition` = `"left-top" | "left-center" | "left-bottom" | "center-top" | "center-bottom" | "right-top" | "right-center" | "right-bottom"`. `SgDockMenuOrientation` = `"horizontal" | "vertical"` — derivada da posição: `left-center`/`right-center` → vertical; as demais (inclusive cantos) → horizontal.
91
+
92
+ ### Helpers puros exportados (`src/menus/dock-menu-logic.ts`, `src/layout/drag-position.ts`)
93
+
94
+ | Função | Assinatura | Retorno / comportamento |
95
+ |---|---|---|
96
+ | `resolveDockMenuOrientation` | `(position: SgDockMenuPosition) => SgDockMenuOrientation` | Regra acima |
97
+ | `resolveDockMenuLiftDirection` | `(position, orientation) => number` | `-1`/`1`: horizontal sobe se `position` contém `bottom`; vertical vai para a direita se começa com `left` |
98
+ | `buildDockMenuLayout` | `(position) => { orientation; liftDirection }` | Combina as duas anteriores |
99
+ | `buildDockMenuItemMotion` | `(args: { index; hoveredIndex: number \| null; magnify; magnifyScale; itemSize; gap; orientation; liftDirection }) => { scale; translateX; translateY; transformOrigin; zIndex }` | Curva de ampliação (influência até 3 itens de distância), elevação e espalhamento dos vizinhos |
100
+ | `buildDockMenuLabelStyle` | `(orientation, position) => React.CSSProperties` | Posição do tooltip (acima no horizontal; à direita/esquerda no vertical) |
101
+ | `buildDockMenuContainerStyle` | `(args: { position; zIndex; enableDragDrop; dragPos: {x;y} \| null; offset?: {x?;y?} }) => { style: React.CSSProperties; transform: string }` | `position: fixed` + coordenadas da posição (borda de 24px), sobreposição pela posição arrastada e aplicação de `offset` |
102
+ | `buildDockMenuContextMenuState` | `(args: { enableDragDrop: boolean; dragId?: string; hasStoredPosition: boolean }) => { canOpenContextMenu; canResetPosition }` | Ambos `true` só com arraste + `dragId` + posição salva |
103
+ | `buildDockMenuStorageKey` | `(dragId?: string \| null, isAbsolutePosition = false) => string \| null` | `null` sem `dragId`; senão `sg-dockmenu-pos:<dragId>:parent\|viewport` |
104
+
105
+ ---
106
+
107
+ ## SgPopup
108
+
109
+ Overlay contextual **não modal** ancorado a um elemento, com título/subtítulo opcionais, conteúdo livre e/ou lista de ações. Fonte: `src/overlay/SgPopup.tsx` → `SgPopup`.
110
+
111
+ ### Import
112
+
113
+ ```tsx
114
+ import { SgPopup, type SgPopupProps, type SgPopupAction, type SgPopupPlacement, type SgPopupPreferPlacement, type SgPopupAlign, type SgPopupSeverity } from "@seedgrid/fe-components";
115
+ ```
116
+
117
+ ### Props
118
+
119
+ | Prop | Tipo | Padrão | Obrigatória | Descrição |
120
+ |---|---|---|---|---|
121
+ | `title` | `string` | — | Não | Titulo opcional do popup. |
122
+ | `subtitle` | `string` | — | Não | Subtitulo opcional do popup. |
123
+ | `open` | `boolean` | — (sem `open` o componente é não controlado) | Não | Controla a visibilidade do popup em modo controlado. |
124
+ | `onOpenChange` | `(open: boolean) => void` | — | Não | Callback disparado quando o estado de abertura muda. |
125
+ | `defaultOpen` | `boolean` | `false` | Não | Controle de visibilidade. |
126
+ | `onOpen` | `() => void` | — | Não | Eventos de ciclo de abertura. |
127
+ | `onClose` | `() => void` | — | Não | Eventos de ciclo de abertura. |
128
+ | `anchorRef` | `React.RefObject<HTMLElement>` | — | Sim | Elemento ancora usado para posicionar o popup. |
129
+ | `placement` | `SgPopupPlacement` = `"top" \| "right" \| "bottom" \| "left" \| "auto"` | `"auto"` | Não | Posicionamento principal do popup em relacao a ancora. |
130
+ | `preferPlacement` | `SgPopupPreferPlacement` = `"top" \| "right" \| "bottom" \| "left"` | `"right"` | Não | Posicionamento e alinhamento do popup. |
131
+ | `align` | `SgPopupAlign` = `"start" \| "center" \| "end"` | `"start"` | Não | Posicionamento e alinhamento do popup. |
132
+ | `offset` | `number` | `8` | Não | Distancia e margem de viewport. |
133
+ | `padding` | `number` | `8` | Não | Distancia e margem de viewport. |
134
+ | `closeOnOutsideClick` | `boolean` | `true` | Não | Fecha o popup quando o usuario clica fora dele. |
135
+ | `closeOnEscape` | `boolean` | `true` | Não | Regras de fechamento. |
136
+ | `className` | `string` | — | Não | Customizacoes visuais. |
137
+ | `style` | `React.CSSProperties` | — | Não | Customizacoes visuais. |
138
+ | `zIndex` | `number` | `60` | Não | Customizacoes visuais. |
139
+ | `minWidth` | `number \| string` | `180` | Não | Customizacoes visuais. |
140
+ | `actions` | `SgPopupAction[]` | — | Não | Lista de acoes contextuais renderizadas no popup. |
141
+ | `children` | `React.ReactNode` | — | Não | Conteudo textual e corpo customizado. |
142
+
143
+ ### Eventos e callbacks
144
+
145
+ | Callback | Assinatura | Quando dispara |
146
+ |---|---|---|
147
+ | `onOpenChange` | `(open: boolean) => void` | Sempre que o popup pede para mudar de estado: clique fora (se `closeOnOutsideClick`), `Esc` (se `closeOnEscape`), clique numa ação com `closeOnClick !== false` |
148
+ | `onOpen` | `() => void` | Efeito: transição de fechado → aberto (inclusive em modo controlado) |
149
+ | `onClose` | `() => void` | Efeito: transição de aberto → fechado |
150
+ | `SgPopupAction.onClick` | `() => void` | Clique na ação; depois fecha se `closeOnClick ?? true` |
151
+
152
+ Modo controlado quando `typeof open === "boolean"`; senão usa estado interno iniciado com `defaultOpen`. Não há gatilho interno para abrir — o consumidor abre (ex.: `onClick` do botão âncora). **Confirmado**.
153
+
154
+ ### Posicionamento
155
+
156
+ `placement="auto"` escolhe o lado com espaço a partir de `preferPlacement`; `align` alinha ao início/centro/fim da âncora; `offset` é a distância da âncora e `padding` a margem mínima da viewport. A posição é recalculada em `resize` e `scroll` (captura) enquanto aberto. Antes da primeira medição o painel fica em `top/left = -9999`. **Confirmado** (`computePosition`, `recompute`).
157
+
158
+ ### Ref
159
+
160
+ Não aceita `ref`. A âncora é passada por `anchorRef: React.RefObject<HTMLElement>` (obrigatória).
161
+
162
+ ### Children, slots e composição
163
+
164
+ - `children` → bloco com `p-2` abaixo do cabeçalho.
165
+ - `actions` → lista de botões após o conteúdo (separada por borda se houver `children`).
166
+ - `title` → faixa de cabeçalho (`bg-primary`); `subtitle` → linha abaixo.
167
+ - Renderiza em portal no `document.body` (`position: fixed`, `zIndex` padrão 60). Não renderiza nada quando fechado.
168
+
169
+ ### Contexto, providers e hooks
170
+
171
+ Consome `useComponentsI18n()` (aria-label padrão `components.popup.ariaLabel`).
172
+
173
+ ### Acessibilidade
174
+
175
+ - Painel com `role="dialog"`, `aria-modal="false"`, `aria-label = title ?? i18n("components.popup.ariaLabel")`. **Confirmado**.
176
+ - `Esc` fecha (listener em `document`). Não há gestão de foco (não move o foco para o popup nem o devolve à âncora). Ações são `<button type="button">` com `title={hint}` e `disabled`. **Confirmado**.
177
+
178
+ ### Tipos auxiliares exportados
179
+
180
+ `SgPopupAction`:
181
+
182
+ | Campo | Tipo | Obrigatório | Descrição |
183
+ |---|---|---|---|
184
+ | `label` | `string` | Sim | Texto da ação |
185
+ | `icon` | `React.ReactNode` | Não | Ícone antes do texto |
186
+ | `hint` | `string` | Não | Tooltip nativo (`title`) |
187
+ | `severity` | `SgPopupSeverity` | Não | Cor de fundo da ação; sem valor usa estilo neutro transparente |
188
+ | `disabled` | `boolean` | Não | Desabilita o botão |
189
+ | `closeOnClick` | `boolean` | Não | Fecha após o clique (padrão efetivo `true`) |
190
+ | `onClick` | `() => void` | Não | Handler |
191
+
192
+ `SgPopupSeverity` = `"primary" | "secondary" | "success" | "info" | "warning" | "help" | "danger" | "plain"`. `SgPopupPlacement` = `"auto" | "top" | "right" | "bottom" | "left"`; `SgPopupPreferPlacement` = mesmo sem `"auto"`; `SgPopupAlign` = `"start" | "center" | "end"`.
193
+
194
+ ---
195
+
196
+ ## SgDialog
197
+
198
+ Modal com cabeçalho (leading/título/subtítulo/trailing/fechar), corpo rolável e rodapé; severidade visual, animação, auto-fechamento, gestão de foco e bloqueio de scroll. Fonte: `src/overlay/SgDialog.tsx` → `SgDialog`.
199
+
200
+ ### Import
201
+
202
+ ```tsx
203
+ import { SgDialog, type SgDialogProps, type SgDialogSize, type SgDialogSeverity, type SgDialogAnimation } from "@seedgrid/fe-components";
204
+ ```
205
+
206
+ ### Props
207
+
208
+ | Prop | Tipo | Padrão | Obrigatória | Descrição |
209
+ |---|---|---|---|---|
210
+ | `open` | `boolean` | — (sem `open` o componente é não controlado) | Não | Controla a abertura do dialog em modo controlado. |
211
+ | `onOpenChange` | `(open: boolean) => void` | — | Não | Callback disparado quando o estado de abertura muda. |
212
+ | `defaultOpen` | `boolean` | `false` | Não | Controle de abertura. |
213
+ | `title` | `React.ReactNode` | — | Não | Titulo principal do dialog. |
214
+ | `subtitle` | `React.ReactNode` | — | Não | Subtitulo complementar do dialog. |
215
+ | `leading` | `React.ReactNode` | — | Não | Conteúdo renderizado à esquerda do título no cabeçalho (ex.: ícone/avatar). *(Inferência)* |
216
+ | `trailing` | `React.ReactNode` | — | Não | Conteúdo renderizado à direita no cabeçalho, antes do botão de fechar. *(Inferência)* |
217
+ | `children` | `React.ReactNode` | — | Não | Conteudo principal do corpo do dialog. |
218
+ | `footer` | `React.ReactNode` | — | Não | Estrutura principal do conteúdo. |
219
+ | `size` | `SgDialogSize` = `"sm" \| "md" \| "lg" \| "xl" \| "full"` | `"md"` | Não | Escala do container modal. |
220
+ | `severity` | `SgDialogSeverity` = `"primary" \| "secondary" \| "success" \| "info" \| "warning" \| "help" \| "danger" \| "plain"` | `"plain"` | Não | Tom semantico do cabecalho e acentos visuais. |
221
+ | `animation` | `SgDialogAnimation` = `"fade" \| "zoom" \| "slideUp"` | `"zoom"` | Não | Animação e duração da transição. |
222
+ | `transitionMs` | `number` | `160` | Não | Animação e duração da transição. |
223
+ | `autoCloseMs` | `number` | — | Não | Fecha automaticamente após o tempo informado. |
224
+ | `className` | `string` | — | Não | Customização de estilos por seção. |
225
+ | `style` | `React.CSSProperties` | — | Não | Customização de estilos por seção. |
226
+ | `customColor` | `React.CSSProperties["backgroundColor"]` | — | Não | Customiza cor de fundo e elevacao do card do dialog. |
227
+ | `elevation` | `"none" \| "sm" \| "md" \| "lg" \| React.CSSProperties["boxShadow"]` | — | Não | Customiza cor de fundo e elevacao do card do dialog. |
228
+ | `shadow` | `React.CSSProperties["boxShadow"]` | — | Não | **Obsoleta** (`@deprecated`). Sombra CSS (box-shadow) do card; usada apenas quando `elevation` não é informado. Substituída por `elevation`. *(Inferência)* |
229
+ | `showTopAccent` | `boolean` | `true` | Não | Exibe a borda superior colorida (border-t-4) com a cor da `severity`. *(Inferência)* |
230
+ | `overlayClassName` | `string` | — | Não | Customização de estilos por seção. |
231
+ | `contentClassName` | `string` | — | Não | Customização de estilos por seção. |
232
+ | `headerClassName` | `string` | — | Não | Customização de estilos por seção. |
233
+ | `bodyClassName` | `string` | — | Não | Customização de estilos por seção. |
234
+ | `footerClassName` | `string` | — | Não | Customização de estilos por seção. |
235
+ | `closeable` | `boolean` | `true` | Não | Regras de fechamento. |
236
+ | `onClose` | `() => void` | — | Não | Controle avançado de fechamento e foco. |
237
+ | `closeOnOverlayClick` | `boolean` | `true` | Não | Fecha o dialog ao clicar fora do conteudo. |
238
+ | `closeOnEsc` | `boolean` | `true` | Não | Regras de fechamento. |
239
+ | `lockBodyScroll` | `boolean` | `true` | Não | Acessibilidade e foco. |
240
+ | `initialFocusRef` | `React.RefObject<HTMLElement>` | — | Não | Controle avançado de fechamento e foco. |
241
+ | `restoreFocus` | `boolean` | `true` | Não | Acessibilidade e foco. |
242
+ | `ariaLabel` | `string` | `?? (typeof title === "string" ? title : undefined) ?? t(i18n, "components.dialog.ariaLabel")` ᶠ | Não | Rótulo acessível do `role="dialog"`. Sem valor, usa `title` (se for string) ou o texto i18n `components.dialog.ariaLabel`. *(Inferência)* |
243
+
244
+ ### Eventos e callbacks
245
+
246
+ | Callback | Assinatura | Quando dispara |
247
+ |---|---|---|
248
+ | `onOpenChange` | `(open: boolean) => void` | Ao fechar por botão X, clique no overlay (se `closeOnOverlayClick`), `Esc` (se `closeOnEsc`) ou `autoCloseMs` — sempre com `false` |
249
+ | `onClose` | `() => void` | Logo após `onOpenChange(false)` nos mesmos fechamentos internos; **não** dispara quando o pai muda `open` para `false` |
250
+
251
+ Modo controlado quando `open !== undefined`. O componente não renderiza nada antes de montar no cliente (`mounted`) e mantém o conteúdo presente por `transitionMs` após fechar (animação de saída). **Confirmado**.
252
+
253
+ ### Ref
254
+
255
+ Não aceita `ref`. Foco inicial: `initialFocusRef`, ou o primeiro elemento com `data-sg-dialog-initial-focus="true"`, ou o primeiro focável (`button, [href], input, select, textarea, [tabindex]`).
256
+
257
+ ### Children, slots e composição
258
+
259
+ - `children` → corpo (`overflow-auto`, card com `max-h-[85vh]`).
260
+ - `footer` → rodapé alinhado à direita (renderizado só se informado).
261
+ - `leading`, `title`, `subtitle`, `trailing` → cabeçalho; o cabeçalho só aparece se algum deles existir **ou** `closeable` for `true`.
262
+ - `size`: `sm` → `max-w-sm`, `md` → `max-w-lg`, `lg` → `max-w-2xl`, `xl` → `max-w-4xl`, `full` → viewport menos 2rem.
263
+ - `elevation`: `"none" | "sm" | "md" | "lg"` mapeiam para sombras fixas; qualquer outra string é usada como `box-shadow` literal; sem `elevation` usa `shadow` (obsoleta). `customColor` define o fundo e, se for cor CSS parseável, deriva cores de texto/borda/hover contrastantes.
264
+ - Portal em `document.body`, container `fixed inset-0 z-[1000]` (`className`/`style` vão para esse container externo).
265
+
266
+ ### Contexto, providers e hooks
267
+
268
+ Consome `useComponentsI18n()` (`components.dialog.ariaLabel`, `components.dialog.close`).
269
+
270
+ ### Acessibilidade
271
+
272
+ - Container com `role="dialog"`, `aria-modal="true"` e `aria-label` (ver `ariaLabel`). Botão de fechar com `aria-label` i18n e ícone `aria-hidden`. **Confirmado**.
273
+ - Teclado: `Esc` fecha; `Tab`/`Shift+Tab` circulam entre os focáveis do conteúdo (*focus trap*) — **ambos só ativos quando `closeOnEsc` é `true`**. **Confirmado**.
274
+ - `restoreFocus` devolve o foco ao elemento ativo antes da abertura; `lockBodyScroll` aplica `overflow: hidden` no `body` enquanto aberto. **Confirmado**.
275
+ - Não usa `aria-labelledby`/`aria-describedby` ligados ao título/corpo.
276
+
277
+ ### Tipos auxiliares exportados
278
+
279
+ `SgDialogSize` = `"sm" | "md" | "lg" | "xl" | "full"`; `SgDialogSeverity` = `"primary" | "secondary" | "success" | "info" | "warning" | "help" | "danger" | "plain"` (cor da borda superior quando `showTopAccent`); `SgDialogAnimation` = `"fade" | "zoom" | "slideUp"`.
280
+
281
+ ---
282
+
283
+ ## SgConfirmationDialog
284
+
285
+ Modal de confirmação construído sobre `SgDialog`: mensagem, ícone por severidade e botões Cancelar/Confirmar (`SgButton`). Fonte: `src/overlay/SgConfirmationDialog.tsx` → `SgConfirmationDialog`.
286
+
287
+ ### Import
288
+
289
+ ```tsx
290
+ import { SgConfirmationDialog, type SgConfirmationDialogProps, type SgConfirmationDialogButtonConfig } from "@seedgrid/fe-components";
291
+ ```
292
+
293
+ ### Props
294
+
295
+ O tipo é `Omit<SgDialogProps, "title" | "children" | "footer" | "severity" | "shadow" | "showTopAccent"> & { ... }`. As props herdadas de [[SeedGrid/SeedGrid-components/navegacao-e-overlay/API#SgDialog|SgDialogProps]] não desestruturadas pelo componente são repassadas sem alteração (`{...dialogProps}`) ao `SgDialog` interno — daí os padrões `ᵇ`, válidos (Confirmado). O componente **sobrepõe** os padrões de `closeable` (`false`) e `size` (`"sm"`), e controla `open`, `onOpenChange`, `severity`, `showTopAccent` (= `showSeverityAccent`), `title`, `footer` e `children`.
296
+
297
+ | Prop | Tipo | Padrão | Obrigatória | Descrição |
298
+ |---|---|---|---|---|
299
+ | `className` | `string` | — | Não | Customização de estilos por seção. |
300
+ | `style` | `React.CSSProperties` | — | Não | Customização de estilos por seção. |
301
+ | `size` | `SgDialogSize` = `"sm" \| "md" \| "lg" \| "xl" \| "full"` | `"sm"` | Não | Escala do container modal. |
302
+ | `elevation` | `"none" \| "sm" \| "md" \| "lg" \| React.CSSProperties["boxShadow"]` | — | Não | Customiza customColor e elevation do card do dialog. |
303
+ | `animation` | `SgDialogAnimation` = `"fade" \| "zoom" \| "slideUp"` | `"zoom"` ᵇ | Não | Animação e duração da transição. |
304
+ | `transitionMs` | `number` | `160` ᵇ | Não | Animação e duração da transição. |
305
+ | `headerClassName` | `string` | — | Não | Customização de estilos por seção. |
306
+ | `bodyClassName` | `string` | — | Não | Customização de estilos por seção. |
307
+ | `footerClassName` | `string` | — | Não | Customização de estilos por seção. |
308
+ | `leading` | `React.ReactNode` | — | Não | Repassada ao `SgDialog`: conteúdo à esquerda do título no cabeçalho. *(Inferência)* |
309
+ | `trailing` | `React.ReactNode` | — | Não | Repassada ao `SgDialog`: conteúdo à direita no cabeçalho. *(Inferência)* |
310
+ | `defaultOpen` | `boolean` | `false` | Não | Controle de abertura do dialogo. |
311
+ | `open` | `boolean` | — (sem `open` o componente é não controlado) | Não | Controla a abertura do dialog de confirmacao. |
312
+ | `onOpenChange` | `(open: boolean) => void` | — | Não | Controle de abertura do dialogo. |
313
+ | `ariaLabel` | `string` | `?? (typeof title === "string" ? title : undefined) ?? t(i18n, "components.dialog.ariaLabel")` ᵇ | Não | Repassada ao `SgDialog`: rótulo acessível; sem valor usa `title` string ou o texto i18n `components.dialog.ariaLabel`. *(Inferência)* |
314
+ | `contentClassName` | `string` | — | Não | Customização de estilos por seção. |
315
+ | `closeOnEsc` | `boolean` | `true` ᵇ | Não | Comportamentos de fechamento via ESC e overlay. |
316
+ | `overlayClassName` | `string` | — | Não | Customização de estilos por seção. |
317
+ | `subtitle` | `React.ReactNode` | — | Não | Subtitulo complementar do dialog. |
318
+ | `onClose` | `() => void` | — | Não | Controle avançado de fechamento e foco. |
319
+ | `autoCloseMs` | `number` | — | Não | Fecha automaticamente após o tempo informado. |
320
+ | `customColor` | `React.CSSProperties["backgroundColor"]` | — | Não | Customiza customColor e elevation do card do dialog. |
321
+ | `closeable` | `boolean` | `false` | Não | Regras de fechamento. |
322
+ | `closeOnOverlayClick` | `boolean` | `true` ᵇ | Não | Comportamentos de fechamento via ESC e overlay. |
323
+ | `lockBodyScroll` | `boolean` | `true` ᵇ | Não | Acessibilidade e foco. |
324
+ | `initialFocusRef` | `React.RefObject<HTMLElement>` | — | Não | Controle avançado de fechamento e foco. |
325
+ | `restoreFocus` | `boolean` | `true` ᵇ | Não | Acessibilidade e foco. |
326
+ | `title` | `React.ReactNode` | — | Não | Titulo principal da confirmacao. |
327
+ | `message` | `React.ReactNode` | — | Não | Mensagem principal explicando o risco ou decisao. |
328
+ | `icon` | `React.ReactNode` | — | Não | Icone opcional no corpo. Se nao for informado, info/warning/danger usam icones padrao. |
329
+ | `iconPlacement` | `"left" \| "top"` | `"left"` | Não | Posicao do icone no corpo. |
330
+ | `severity` | `SgDialogSeverity` = `"primary" \| "secondary" \| "success" \| "info" \| "warning" \| "help" \| "danger" \| "plain"` | `"warning"` | Não | Tom semantico da confirmacao. |
331
+ | `showSeverityAccent` | `boolean` | `false` | Não | Habilita a faixa superior de severidade no dialogo. |
332
+ | `cancelButton` | `SgConfirmationDialogButtonConfig` | — | Não | Configuracao visual e comportamental do botao de cancelamento. |
333
+ | `confirmButton` | `SgConfirmationDialogButtonConfig` | — | Não | Configuracao visual e comportamental do botao de confirmacao. |
334
+ | `onCancel` | `() => void` | — | Não | Callback disparado quando o usuario cancela a acao. |
335
+ | `onConfirm` | `() => void` | — | Não | Callback disparado quando o usuario confirma a acao. |
336
+ | `closeOnCancel` | `boolean` | `true` | Não | Define se fecha automaticamente apos acao. |
337
+ | `closeOnConfirm` | `boolean` | `true` | Não | Define se fecha automaticamente apos acao. |
338
+
339
+ - Props declaradas em `SgDialogProps` (contrato reutilizado): `className`, `style`, `size`, `elevation`, `animation`, `transitionMs`, `headerClassName`, `bodyClassName`, `footerClassName`, `leading`, `trailing`, `defaultOpen`, `open`, `onOpenChange`, `ariaLabel`, `contentClassName`, `closeOnEsc`, `overlayClassName`, `subtitle`, `onClose`, `autoCloseMs`, `customColor`, `closeable`, `closeOnOverlayClick`, `lockBodyScroll`, `initialFocusRef`, `restoreFocus`.
340
+ - Tipo base: `Omit< SgDialogProps, "title" \| "children" \| "footer" \| "severity" \| "shadow" \| "showTopAccent" >`.
341
+
342
+ ### Eventos e callbacks
343
+
344
+ | Callback | Assinatura | Quando dispara |
345
+ |---|---|---|
346
+ | `onConfirm` | `() => void` | Clique em Confirmar, depois de `confirmButton.onClick`; em seguida fecha se `closeOnConfirm` |
347
+ | `onCancel` | `() => void` | Clique em Cancelar (depois de `cancelButton.onClick`; fecha se `closeOnCancel`) **e** em qualquer dispensa do dialog (overlay, `Esc`, X, `autoCloseMs`) — "fluxo de cancelamento compartilhado" |
348
+ | `onOpenChange` | `(open: boolean) => void` | Ao fechar por cancelar/confirmar (com os `closeOn*` ligados) ou por dispensa do dialog |
349
+ | `onClose` | `() => void` | Repassado ao `SgDialog`: só nos fechamentos internos do dialog (overlay/Esc/X/auto), não nos botões Cancelar/Confirmar |
350
+
351
+ **Confirmado** (`handleCancel`, `handleConfirm`, `handleDialogOpenChange`; teste `overlay.test.mjs`).
352
+
353
+ ### Padrões dos botões
354
+
355
+ - Cancelar: `appearance` `"outline"`, `severity` `"secondary"`, `shape` `"rounded"`, rótulo i18n `components.actions.cancel`, ícone X; sem `appearance`/`severity`/`className` aplica `customColors` neutras.
356
+ - Confirmar: `appearance` `"solid"`, `severity` = severidade do dialog (ou `"primary"` se `plain`), `shape` `"rounded"`, rótulo i18n `components.actions.confirm`, ícone check.
357
+ - Ícone do corpo: `icon` se informado (inclusive `null` para suprimir); senão ícone padrão para `info`/`warning`/`danger`; outras severidades sem ícone. **Confirmado**.
358
+
359
+ ### Ref
360
+
361
+ Não aceita `ref`.
362
+
363
+ ### Children, slots e composição
364
+
365
+ Não aceita `children`/`footer` (omitidos do tipo). Conteúdo = `message` (+ `icon` à esquerda ou no topo conforme `iconPlacement`). `title` e `subtitle`/`leading`/`trailing` vão para o cabeçalho do `SgDialog`.
366
+
367
+ ### Contexto, providers e hooks
368
+
369
+ Consome `useComponentsI18n()`; herda o comportamento de `SgDialog`.
370
+
371
+ ### Acessibilidade
372
+
373
+ Herda de `SgDialog` (`role="dialog"`, `aria-modal`, `Esc`, *focus trap*, foco inicial no primeiro focável — no caso, o botão Cancelar, por ser o primeiro botão do conteúdo quando `closeable` é `false`: **Inferência** pela ordem do DOM). Ícones padrão com `aria-hidden`.
374
+
375
+ ### Tipos auxiliares exportados
376
+
377
+ `SgConfirmationDialogButtonConfig`:
378
+
379
+ | Campo | Tipo | Obrigatório | Descrição |
380
+ |---|---|---|---|
381
+ | `label` | `React.ReactNode` | Não | Texto do botão (padrão i18n) |
382
+ | `icon` | `React.ReactNode` | Não | Ícone à esquerda (padrão X/check) |
383
+ | `severity` | `SgButtonProps["severity"]` | Não | Severidade do `SgButton` |
384
+ | `appearance` | `SgButtonProps["appearance"]` | Não | `"solid" \| "outline" \| "ghost"` |
385
+ | `shape` | `SgButtonProps["shape"]` | Não | Formato do `SgButton` (padrão `"rounded"`) |
386
+ | `disabled` | `boolean` | Não | Desabilita o botão |
387
+ | `className` | `string` | Não | Classe extra |
388
+ | `onClick` | `() => void` | Não | Chamado antes de `onCancel`/`onConfirm` |
389
+
390
+ Ver `SgButton` em [[SeedGrid/SeedGrid-components/buttons/API|API dos botões]].
391
+
392
+ ---
393
+
394
+ ## SgWizard
395
+
396
+ Fluxo em etapas: renderiza uma `SgWizardPage` por vez, botões Anterior/Próximo/Concluir, stepper opcional (numerado ou por ícones), validação automática dos inputs da etapa e guardas síncronas/assíncronas. Fonte: `src/wizard/SgWizard.tsx` → `SgWizard`.
397
+
398
+ ### Import
399
+
400
+ ```tsx
401
+ import { SgWizard, SgWizardPage, type SgWizardProps, type SgWizardPageProps, type SgWizardLabels, type SgWizardStepper } from "@seedgrid/fe-components";
402
+ ```
403
+
404
+ ### Props
405
+
406
+ | Prop | Tipo | Padrão | Obrigatória | Descrição |
407
+ |---|---|---|---|---|
408
+ | `children` | `React.ReactNode` | — | Sim | Paginas do wizard renderizadas em ordem. |
409
+ | `onFinish` | `() => void \| Promise<void>` | — | Sim | Acao executada ao concluir o wizard. |
410
+ | `onStepChange` | `(index: number) => void` | — | Não | Callback disparado ao trocar de etapa. |
411
+ | `onBeforeNext` | `(index: number) => boolean \| Promise<boolean>` | — | Não | Roda ao clicar em Proximo; devolver false (ou uma Promise<false>) impede o avanco. Enquanto e aguardado, o botao fica desabilitado. |
412
+ | `onBeforeFinish` | `(index: number) => boolean \| Promise<boolean>` | — | Não | Roda ao clicar em concluir; devolver false impede a finalizacao. |
413
+ | `validateStep` | `(index: number) => boolean \| Promise<boolean>` | — | Não | Valida a etapa atual antes de avancar. |
414
+ | `nextDisabled` | `boolean` | `?? false` ᶠ | Não | Desabilita o avanco de forma declarativa: o botao "Proximo" fica desabilitado (opaco, com cursor de bloqueio) e o stepper para de oferecer as etapas seguintes. Complementa `onBeforeNext`/`validateStep`, que so' agem NO CLIQUE. Quando o consumidor ja sabe que a etapa nao pode avancar — tipicamente o resultado de uma checagem assincrona que ja' terminou, como "este CNPJ ja' tem cadastro" — o botao continuava com aparencia de clicavel e o clique nao fazia nada, sem explicar por que. Nao afeta o botao de conclusao da ultima etapa: para esse caso existe `onBeforeFinish`. |
415
+ | `initialStep` | `number` | `0` (via `clampWizardStep`, que também limita ao intervalo de páginas) | Não | Indice inicial da etapa ativa. |
416
+ | `labels` | `Partial<SgWizardLabels>` | textos i18n `components.wizard.next/previous/finish` | Não | Override dos textos dos botoes de navegacao. |
417
+ | `stepper` | `SgWizardStepper` = `"none" \| "numbered" \| "icons"` | `?? "none"` ᶠ | Não | Modo visual do stepper. |
418
+ | `stepNavigation` | `WizardStepNavigation` = `"none" \| "previous" \| "previous-and-next"` | `?? "previous-and-next"` ᶠ | Não | Define quais etapas podem ser acessadas clicando no stepper. |
419
+ | `className` | `string` | — | Não | Classes e estilo inline do container do wizard. |
420
+ | `style` | `React.CSSProperties` | — | Não | Classes e estilo inline do container do wizard. |
421
+
422
+ ### Eventos e callbacks
423
+
424
+ | Callback | Assinatura | Quando dispara |
425
+ |---|---|---|
426
+ | `validateStep` | `(index: number) => boolean \| Promise<boolean>` | No avanço e na conclusão, após a validação automática; `false` bloqueia |
427
+ | `onBeforeNext` | `(index: number) => boolean \| Promise<boolean>` | No avanço (botão Próximo ou clique na etapa seguinte do stepper), após `validateStep` |
428
+ | `onBeforeFinish` | `(index: number) => boolean \| Promise<boolean>` | Na conclusão, após `validateStep` |
429
+ | `onFinish` | `() => void \| Promise<void>` | Quando todas as guardas da última etapa passam; o botão fica desabilitado enquanto a Promise não resolve |
430
+ | `onStepChange` | `(index: number) => void` | Em efeito após render com dependências `[props, step]` (ver observação na visão geral) |
431
+
432
+ Ordem das guardas (`canProceedWizardAction`): **1)** validação automática da etapa — foca e desfoca cada `input/select/textarea` da etapa, aguarda um tick e bloqueia se existir algum elemento `[data-sg-error]`; **2)** `validateStep`; **3)** `onBeforeNext`/`onBeforeFinish`. Durante a execução os botões ficam desabilitados (`isValidating`). Voltar (botão Anterior ou etapa anterior no stepper) não executa guardas. **Confirmado**.
433
+
434
+ ### Ref
435
+
436
+ Não aceita `ref`; não há API imperativa nem etapa controlada.
437
+
438
+ ### Children, slots e composição
439
+
440
+ - `children`: apenas elementos `SgWizardPage` diretos são considerados (filtro por `child.type === SgWizardPage`); fragmentos/wrappers são ignorados.
441
+ - Stepper (`stepper !== "none"`): `<nav>` com `<ol>`; etapa concluída mostra check; em `icons` usa `SgWizardPage.icon` (se ausente, o número); título = `SgWizardPage.title` ou i18n `components.wizard.step`.
442
+ - `stepNavigation`: `"none"` (stepper não clicável), `"previous"` (só etapas anteriores), `"previous-and-next"` (anteriores + somente a imediatamente seguinte). Com `nextDisabled`, etapas futuras deixam de ser clicáveis.
443
+ - Botão Anterior só aparece fora da primeira etapa; na última etapa Próximo vira Concluir.
444
+
445
+ ### Contexto, providers e hooks
446
+
447
+ Consome `useComponentsI18n()` (`components.wizard.next/previous/finish/progress/step`).
448
+
449
+ ### Acessibilidade
450
+
451
+ - Stepper em `<nav aria-label={i18n "components.wizard.progress"}>`; etapa atual com `aria-current="step"`; etapas clicáveis são `<button type="button">` com anel de foco visível; ícone check `aria-hidden`. **Confirmado**.
452
+ - Não move o foco para o conteúdo da nova etapa após avançar/voltar; não há região `aria-live`. **Confirmado** (ausência no código).
453
+
454
+ ### Tipos auxiliares exportados
455
+
456
+ `SgWizardLabels` = `{ next: string; previous: string; finish: string }` (a prop aceita `Partial`). `SgWizardStepper` = `"numbered" | "icons" | "none"`. `WizardStepNavigation` = `"none" | "previous" | "previous-and-next"`. `WizardGuardRunner` = `{ validateCurrentPage: () => boolean | Promise<boolean>; validateStep?: (index: number) => boolean | Promise<boolean>; beforeAction?: (index: number) => boolean | Promise<boolean>; step: number }`.
457
+
458
+ ### Helpers puros exportados (`src/wizard/logic.ts`)
459
+
460
+ | Função | Assinatura | Comportamento |
461
+ |---|---|---|
462
+ | `clampWizardStep` | `(initialStep: number \| undefined, pageCount: number) => number` | `initialStep ?? 0` limitado a `[0, max(pageCount - 1, 0)]` |
463
+ | `canNavigateToWizardStep` | `(args: { currentStep: number; targetStep: number; pageCount: number; stepNavigation?: WizardStepNavigation }) => boolean` | `false` fora do intervalo ou para a etapa atual; anterior permitida em `previous`/`previous-and-next`; posterior só em `previous-and-next` e só `currentStep + 1` (padrão `"previous-and-next"`) |
464
+ | `canProceedWizardAction` | `(runner: WizardGuardRunner) => Promise<boolean>` | Executa `validateCurrentPage` → `validateStep(step)` → `beforeAction(step)`, parando no primeiro `false` |
465
+
466
+ ---
467
+
468
+ ## SgWizardPage
469
+
470
+ Etapa de um `SgWizard`. Renderiza apenas `<div className style>{children}</div>`; `title` e `icon` são lidos pelo `SgWizard` para o stepper. Fonte: `src/wizard/SgWizard.tsx` → `SgWizardPage`.
471
+
472
+ ### Import
473
+
474
+ ```tsx
475
+ import { SgWizardPage, type SgWizardPageProps } from "@seedgrid/fe-components";
476
+ ```
477
+
478
+ ### Props
479
+
480
+ | Prop | Tipo | Padrão | Obrigatória | Descrição |
481
+ |---|---|---|---|---|
482
+ | `title` | `string` | — | Não | Titulo exibido no stepper do wizard. Sem valor, o stepper usa o texto i18n `components.wizard.step` ("Etapa N"). |
483
+ | `icon` | `React.ReactNode` | — | Não | Icone opcional exibido quando o wizard usa stepper por icones. |
484
+ | `children` | `React.ReactNode` | — | Sim | Conteudo da etapa. |
485
+ | `className` | `string` | — | Não | Classes adicionais da etapa. |
486
+ | `style` | `React.CSSProperties` | — | Não | Estilo inline do `<div>` da etapa. *(Inferência)* |
487
+
488
+ ### Ref, eventos e acessibilidade
489
+
490
+ Não aceita `ref`; não tem callbacks; sem atributos ARIA próprios. Só funciona como filho direto de `SgWizard`.