@seedgrid/ai-toolkit 0.3.0 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,123 +1,123 @@
1
- ---
2
- tags: [seedgrid, component, frontend, react, inputs-texto]
3
- fonte: front/seedgrid-fe-components/packages/seedgrid-fe-components/src/inputs
4
- branch: main
5
- commit: ad30fc11de
6
- analisado-em: 2026-10-14
7
- ---
8
-
9
- # Inputs de texto (SgInput*)
10
-
11
- Este grupo reúne os 15 campos de digitação do pacote `@seedgrid/fe-components` (v`2026.7.1`). Todos estão em `src/inputs/` e todos são exportados pela raiz do pacote. Detalhe de props, eventos e ref: [[SeedGrid/SeedGrid-components/inputs-texto/API|API dos inputs de texto]]. Código: [[SeedGrid/SeedGrid-components/inputs-texto/Exemplos|Exemplos dos inputs de texto]]. Grupos vizinhos: [[SeedGrid/SeedGrid-components/inputs-selecao/Visao-geral|inputs de seleção]], [[SeedGrid/SeedGrid-components/datatable/Visao-geral|SgDatatable]], [[SeedGrid/SeedGrid-components/editor/Visao-geral|SgTextEditor]].
12
-
13
- ## Objetivo
14
-
15
- Os componentes oferecem campos de formulário prontos, com as seguintes características comuns:
16
- - rótulo flutuante, no topo ou à esquerda;
17
- - validação embutida, com mensagens traduzidas;
18
- - máscaras brasileiras (CPF, CNPJ alfanumérico, telefone, CEP);
19
- - integração opcional com react-hook-form, por `register` ou por `control`.
20
-
21
- O padrão de nomes de eventos vem da casa: `onEnter` no foco, `onExit` no blur, `onChange(value)` com o valor já tratado e `onValidation(msg | null)`. **Confirmado**: comentários "padrao seedgrid" nos tipos.
22
-
23
- ## Quando usar cada um
24
-
25
- | Componente | Use para | Base |
26
- |---|---|---|
27
- | `SgInputText` | Texto curto livre (nome, título, código). É a base dos demais. | própria |
28
- | `SgInputTextArea` | Texto longo multilinha, com mínimo de linhas e palavras. | própria (`<textarea>`) |
29
- | `SgInputTextSearch` | Caixa de busca com debounce (`onSearchChange`). | `SgInputText` |
30
- | `SgInputEmail` | E-mail com validação de formato e bloqueio de domínios temporários. | `SgInputText` |
31
- | `SgInputPassword` | Senha com política configurável, barra de força, olho e gerador. | `SgInputText` |
32
- | `SgInputPhone` | Telefone BR com máscara (10 ou 11 dígitos). | `SgInputText` |
33
- | `SgInputCPF` | CPF com máscara e dígito verificador. | `SgInputText` |
34
- | `SgInputCNPJ` | CNPJ numérico ou alfanumérico, com consulta pública opcional. | `SgInputText` |
35
- | `SgInputCPFCNPJ` | Campo único que aceita CPF ou CNPJ e detecta qual é. | `SgInputText` |
36
- | `SgInputPostalCode` | CEP/código postal de BR, PT, US, ES, UY, AR e PY, com ViaCEP opcional. | `SgInputText` |
37
- | `SgInputDate` | Data com o widget nativo (`type="date"`) e limites min/max. | `SgInputText` |
38
- | `SgInputBirthDate` | Data de nascimento com idade mínima/máxima. | `SgInputDate` |
39
- | `SgInputNumber` | Número decimal formatado pelo locale, com min/max. | própria |
40
- | `SgInputCurrency` | Valor monetário com símbolo via `Intl` (padrão BRL). | própria (derivada do código do `SgInputNumber`) |
41
- | `SgInputOTP` | Código de uso único segmentado, com máscara (`999999`, `###-###`). | própria |
42
-
43
- Para escolhas fechadas, como combos e listas, use o grupo [[SeedGrid/SeedGrid-components/inputs-selecao/Visao-geral|inputs de seleção]]. Para texto rico, use o [[SeedGrid/SeedGrid-components/editor/Visao-geral|SgTextEditor]]. Esses mesmos encaminhamentos aparecem nos `aiHints.avoidUseCases` de `SgInputText.meta.ts`. **Confirmado**.
44
-
45
- ## Composição
46
-
47
- ```mermaid
48
- graph TD
49
- T[SgInputText] --> S[SgInputTextSearch]
50
- T --> E[SgInputEmail]
51
- T --> P[SgInputPassword]
52
- T --> Ph[SgInputPhone]
53
- T --> CPF[SgInputCPF]
54
- T --> CNPJ[SgInputCNPJ]
55
- T --> CC[SgInputCPFCNPJ]
56
- T --> CEP[SgInputPostalCode]
57
- T --> D[SgInputDate] --> B[SgInputBirthDate]
58
- T -.também usado por.-> SEL[SgAutocomplete / SgCombobox / SgMultiSelect]
59
- ```
60
-
61
- - Os wrappers usam `Omit<SgInputTextProps, …>`, acrescentam as próprias props e repassam o resto ao `SgInputText`. A integração com o RHF fica no `SgInputText`.
62
- - Cada wrapper mantém **o próprio erro interno** e o passa como `error` ao `SgInputText`, junto com o erro de `fieldState` via `resolveFieldError`. Como o `SgInputText` também valida (required/maxLength…), uma mensagem do wrapper tem precedência sobre a dele. **Confirmado**.
63
- - `SgInputTextArea`, `SgInputNumber`, `SgInputCurrency` e `SgInputOTP` repetem o padrão visual do `SgInputText`, mas têm implementação própria.
64
-
65
- ## Dependências
66
-
67
- - **Peers obrigatórios do pacote:**
68
- - `react` `^18.2.0 || ^19.0.0`;
69
- - `react-hook-form` `^7.0.0`, importado estaticamente (`Controller`) pelos inputs, mesmo sem uso de formulário;
70
- - `lucide-react` `^0.468.0 || ^1.0.0` (ícone `X` do botão limpar).
71
-
72
- **Confirmado** em `package.json` e nos imports.
73
- - **Peers TipTap:** não são usados por este grupo, mas são carregados pela raiz do pacote. Ver [[SeedGrid/SeedGrid-components/editor/Visao-geral|SgTextEditor]].
74
- - **Rede:** `SgInputCNPJ` (`validateWithPublicaCnpj`) e `SgInputPostalCode` (`validateWithViaCep`) chamam `fetch` para `publica.cnpj.ws` e `viacep.com.br` por padrão. Ambos aceitam uma função de consulta própria (`publicaCnpjFetch`, `viaCepFetch`).
75
- - **APIs do navegador:** `SgInputPassword` usa `crypto.getRandomValues` para gerar senha.
76
- - **"use client":** todos os arquivos começam com `"use client"`, o que serve ao Next.js App Router.
77
-
78
- ## Tema e estilos
79
-
80
- - O CSS compilado (Tailwind) é **injetado automaticamente** no `<head>` quando o pacote é importado (`ensureSeedgridStylesInjected()` em `src/injectStyles.ts`, chamado no topo de `src/index.ts`). A injeção tem proteção para SSR e para dupla injeção (id `seedgrid-fe-components-styles`). Também existe `@seedgrid/fe-components/style.css` para quem prefere importar o arquivo. **Confirmado**.
81
- - **Tokens:**
82
- - Cores via variáveis CSS do tema: `hsl(var(--primary))`, `--destructive`, `--foreground`, `--muted`, `--border`.
83
- - Variáveis específicas de input, com fallback: `--sg-input-bg`, `--sg-input-fg`, `--sg-input-placeholder`, `--sg-input-disabled-bg`, `--sg-input-disabled-fg`.
84
-
85
- O pacote `@seedgrid/fe-theme` aparece só como devDependency. A relação exata entre ele e essas variáveis é **Inferência**.
86
- - **Customização:**
87
- - Props: `className` (no `SgInputText` **substitui** as classes do input), `labelClassName`, `width`, `borderRadius`, `elevation`, `withBorder`, `filled`.
88
- - Dark mode do `SgInputDate`: `color-scheme` via `useDarkFlag()`.
89
-
90
- ## Internacionalização
91
-
92
- - **Provider:** textos padrão vêm de `useComponentsI18n()` (`src/i18n/index.ts`). Locales embutidos: `pt-BR`, `pt-PT`, `en-US` (alias `en`), `es`, `fr`.
93
- - **Sem provider:** vale o i18n global, que por padrão é **`en-US`**. Para trocar, use `<SgComponentsI18nProvider locale="pt-BR" messages={…}>` ou `setComponentsI18n(...)`. As mensagens passadas sobrescrevem as embutidas, chave por chave.
94
- - **Chaves deste grupo:** `components.inputs.*`, `components.password.*`, `components.validators.*` e `components.actions.clear`.
95
- - **Props `*Message`:** sempre têm precedência sobre a tradução.
96
-
97
- **Confirmado**.
98
-
99
- ## Testes existentes (lidos, **não executados**)
100
-
101
- - `tests/inputs-dom.test.mjs` (jsdom) cobre:
102
- - `SgInputText` controlado via `inputProps.value` e via RHF;
103
- - `onChange` do `SgInputPassword` e o tamanho da senha gerada;
104
- - asterisco do `SgInputPhone`;
105
- - debounce, `minChars` e "distinct" do `SgInputTextSearch`.
106
- - `tests/inputs-i18n.test.mjs`: rótulos de acessibilidade do `SgInputOTP`.
107
- - `tests/rhf.test.mjs` e `tests/rhf-components-contract.test.mjs`: `resolveFieldError`, `mergeRequiredRule` e presença dos caminhos `register`/`control` no `SgInputTextArea`.
108
- - `tests/i18n-components-contract.test.mjs`: garante que os componentes usam `t(...)` em vez de texto fixo.
109
-
110
- O script `test` do pacote roda `pnpm run build` antes.
111
-
112
- ## Limitações e pontos de atenção
113
-
114
- - `SgInputBirthDate` sem `minAge` nem `maxAge` acusa erro de configuração para qualquer data preenchida. **Confirmado**.
115
- - `SgInputPassword` tem `maxLength` padrão **15**. `SgInputCPF`, `SgInputCNPJ` e `SgInputCPFCNPJ` têm `maxLength` padrão 18. **Confirmado**.
116
- - `SgInputCPF`, `SgInputCNPJ`, `SgInputCPFCNPJ`, `SgInputPostalCode`, `SgInputDate` e `SgInputBirthDate` não repassam `required` ao `SgInputText`. Consequências:
117
- - o rótulo fica sem `*`;
118
- - as rules do RHF ficam sem `required` automático (a validação interna continua funcionando).
119
-
120
- `SgInputPhone`, `SgInputEmail` e `SgInputPassword` repassam. **Confirmado** (`required={required}` só aparece nesses três).
121
- - O erro não é anunciado a leitores de tela no `SgInputText` (sem `aria-invalid`/`aria-describedby`). O `SgToggleSwitch` e o `SgInputOTP` fazem isso. **Confirmado**.
122
- - Para reagir ao foco, use `onEnter`: o `inputProps.onFocus` não é chamado pelo `SgInputText`. **Confirmado**; ver [[SeedGrid/SeedGrid-components/inputs-texto/API#Contrato base SgInputText|contrato base]].
123
- - Os tipos de props de `SgInputEmail`, `SgInputPassword`, `SgInputDate` e `SgInputBirthDate` não são reexportados. **Confirmado**.
1
+ ---
2
+ tags: [seedgrid, component, frontend, react, inputs-texto]
3
+ fonte: front/seedgrid-fe-components/packages/seedgrid-fe-components/src/inputs
4
+ branch: main
5
+ commit: ad30fc11de
6
+ analisado-em: 2026-10-14
7
+ ---
8
+
9
+ # Inputs de texto (SgInput*)
10
+
11
+ Este grupo reúne os 15 campos de digitação do pacote `@seedgrid/fe-components` (v`2026.7.1`). Todos estão em `src/inputs/` e todos são exportados pela raiz do pacote. Detalhe de props, eventos e ref: [[SeedGrid/SeedGrid-components/inputs-texto/API|API dos inputs de texto]]. Código: [[SeedGrid/SeedGrid-components/inputs-texto/Exemplos|Exemplos dos inputs de texto]]. Grupos vizinhos: [[SeedGrid/SeedGrid-components/inputs-selecao/Visao-geral|inputs de seleção]], [[SeedGrid/SeedGrid-components/datatable/Visao-geral|SgDatatable]], [[SeedGrid/SeedGrid-components/editor/Visao-geral|SgTextEditor]].
12
+
13
+ ## Objetivo
14
+
15
+ Os componentes oferecem campos de formulário prontos, com as seguintes características comuns:
16
+ - rótulo flutuante, no topo ou à esquerda;
17
+ - validação embutida, com mensagens traduzidas;
18
+ - máscaras brasileiras (CPF, CNPJ alfanumérico, telefone, CEP);
19
+ - integração opcional com react-hook-form, por `register` ou por `control`.
20
+
21
+ O padrão de nomes de eventos vem da casa: `onEnter` no foco, `onExit` no blur, `onChange(value)` com o valor já tratado e `onValidation(msg | null)`. **Confirmado**: comentários "padrao seedgrid" nos tipos.
22
+
23
+ ## Quando usar cada um
24
+
25
+ | Componente | Use para | Base |
26
+ |---|---|---|
27
+ | `SgInputText` | Texto curto livre (nome, título, código). É a base dos demais. | própria |
28
+ | `SgInputTextArea` | Texto longo multilinha, com mínimo de linhas e palavras. | própria (`<textarea>`) |
29
+ | `SgInputTextSearch` | Caixa de busca com debounce (`onSearchChange`). | `SgInputText` |
30
+ | `SgInputEmail` | E-mail com validação de formato e bloqueio de domínios temporários. | `SgInputText` |
31
+ | `SgInputPassword` | Senha com política configurável, barra de força, olho e gerador. | `SgInputText` |
32
+ | `SgInputPhone` | Telefone BR com máscara (10 ou 11 dígitos). | `SgInputText` |
33
+ | `SgInputCPF` | CPF com máscara e dígito verificador. | `SgInputText` |
34
+ | `SgInputCNPJ` | CNPJ numérico ou alfanumérico, com consulta pública opcional. | `SgInputText` |
35
+ | `SgInputCPFCNPJ` | Campo único que aceita CPF ou CNPJ e detecta qual é. | `SgInputText` |
36
+ | `SgInputPostalCode` | CEP/código postal de BR, PT, US, ES, UY, AR e PY, com ViaCEP opcional. | `SgInputText` |
37
+ | `SgInputDate` | Data com o widget nativo (`type="date"`) e limites min/max. | `SgInputText` |
38
+ | `SgInputBirthDate` | Data de nascimento com idade mínima/máxima. | `SgInputDate` |
39
+ | `SgInputNumber` | Número decimal formatado pelo locale, com min/max. | própria |
40
+ | `SgInputCurrency` | Valor monetário com símbolo via `Intl` (padrão BRL). | própria (derivada do código do `SgInputNumber`) |
41
+ | `SgInputOTP` | Código de uso único segmentado, com máscara (`999999`, `###-###`). | própria |
42
+
43
+ Para escolhas fechadas, como combos e listas, use o grupo [[SeedGrid/SeedGrid-components/inputs-selecao/Visao-geral|inputs de seleção]]. Para texto rico, use o [[SeedGrid/SeedGrid-components/editor/Visao-geral|SgTextEditor]]. Esses mesmos encaminhamentos aparecem nos `aiHints.avoidUseCases` de `SgInputText.meta.ts`. **Confirmado**.
44
+
45
+ ## Composição
46
+
47
+ ```mermaid
48
+ graph TD
49
+ T[SgInputText] --> S[SgInputTextSearch]
50
+ T --> E[SgInputEmail]
51
+ T --> P[SgInputPassword]
52
+ T --> Ph[SgInputPhone]
53
+ T --> CPF[SgInputCPF]
54
+ T --> CNPJ[SgInputCNPJ]
55
+ T --> CC[SgInputCPFCNPJ]
56
+ T --> CEP[SgInputPostalCode]
57
+ T --> D[SgInputDate] --> B[SgInputBirthDate]
58
+ T -.também usado por.-> SEL[SgAutocomplete / SgCombobox / SgMultiSelect]
59
+ ```
60
+
61
+ - Os wrappers usam `Omit<SgInputTextProps, …>`, acrescentam as próprias props e repassam o resto ao `SgInputText`. A integração com o RHF fica no `SgInputText`.
62
+ - Cada wrapper mantém **o próprio erro interno** e o passa como `error` ao `SgInputText`, junto com o erro de `fieldState` via `resolveFieldError`. Como o `SgInputText` também valida (required/maxLength…), uma mensagem do wrapper tem precedência sobre a dele. **Confirmado**.
63
+ - `SgInputTextArea`, `SgInputNumber`, `SgInputCurrency` e `SgInputOTP` repetem o padrão visual do `SgInputText`, mas têm implementação própria.
64
+
65
+ ## Dependências
66
+
67
+ - **Peers obrigatórios do pacote:**
68
+ - `react` `^18.2.0 || ^19.0.0`;
69
+ - `react-hook-form` `^7.0.0`, importado estaticamente (`Controller`) pelos inputs, mesmo sem uso de formulário;
70
+ - `lucide-react` `^0.468.0 || ^1.0.0` (ícone `X` do botão limpar).
71
+
72
+ **Confirmado** em `package.json` e nos imports.
73
+ - **Peers TipTap:** não são usados por este grupo, mas são carregados pela raiz do pacote. Ver [[SeedGrid/SeedGrid-components/editor/Visao-geral|SgTextEditor]].
74
+ - **Rede:** `SgInputCNPJ` (`validateWithPublicaCnpj`) e `SgInputPostalCode` (`validateWithViaCep`) chamam `fetch` para `publica.cnpj.ws` e `viacep.com.br` por padrão. Ambos aceitam uma função de consulta própria (`publicaCnpjFetch`, `viaCepFetch`).
75
+ - **APIs do navegador:** `SgInputPassword` usa `crypto.getRandomValues` para gerar senha.
76
+ - **"use client":** todos os arquivos começam com `"use client"`, o que serve ao Next.js App Router.
77
+
78
+ ## Tema e estilos
79
+
80
+ - O CSS compilado (Tailwind) é **injetado automaticamente** no `<head>` quando o pacote é importado (`ensureSeedgridStylesInjected()` em `src/injectStyles.ts`, chamado no topo de `src/index.ts`). A injeção tem proteção para SSR e para dupla injeção (id `seedgrid-fe-components-styles`). Também existe `@seedgrid/fe-components/style.css` para quem prefere importar o arquivo. **Confirmado**.
81
+ - **Tokens:**
82
+ - Cores via variáveis CSS do tema: `hsl(var(--primary))`, `--destructive`, `--foreground`, `--muted`, `--border`.
83
+ - Variáveis específicas de input, com fallback: `--sg-input-bg`, `--sg-input-fg`, `--sg-input-placeholder`, `--sg-input-disabled-bg`, `--sg-input-disabled-fg`.
84
+
85
+ O pacote `@seedgrid/fe-theme` aparece só como devDependency. A relação exata entre ele e essas variáveis é **Inferência**.
86
+ - **Customização:**
87
+ - Props: `className` (no `SgInputText` **substitui** as classes do input), `labelClassName`, `width`, `borderRadius`, `elevation`, `withBorder`, `filled`.
88
+ - Dark mode do `SgInputDate`: `color-scheme` via `useDarkFlag()`.
89
+
90
+ ## Internacionalização
91
+
92
+ - **Provider:** textos padrão vêm de `useComponentsI18n()` (`src/i18n/index.ts`). Locales embutidos: `pt-BR`, `pt-PT`, `en-US` (alias `en`), `es`, `fr`.
93
+ - **Sem provider:** vale o i18n global, que por padrão é **`en-US`**. Para trocar, use `<SgComponentsI18nProvider locale="pt-BR" messages={…}>` ou `setComponentsI18n(...)`. As mensagens passadas sobrescrevem as embutidas, chave por chave.
94
+ - **Chaves deste grupo:** `components.inputs.*`, `components.password.*`, `components.validators.*` e `components.actions.clear`.
95
+ - **Props `*Message`:** sempre têm precedência sobre a tradução.
96
+
97
+ **Confirmado**.
98
+
99
+ ## Testes existentes (lidos, **não executados**)
100
+
101
+ - `tests/inputs-dom.test.mjs` (jsdom) cobre:
102
+ - `SgInputText` controlado via `inputProps.value` e via RHF;
103
+ - `onChange` do `SgInputPassword` e o tamanho da senha gerada;
104
+ - asterisco do `SgInputPhone`;
105
+ - debounce, `minChars` e "distinct" do `SgInputTextSearch`.
106
+ - `tests/inputs-i18n.test.mjs`: rótulos de acessibilidade do `SgInputOTP`.
107
+ - `tests/rhf.test.mjs` e `tests/rhf-components-contract.test.mjs`: `resolveFieldError`, `mergeRequiredRule` e presença dos caminhos `register`/`control` no `SgInputTextArea`.
108
+ - `tests/i18n-components-contract.test.mjs`: garante que os componentes usam `t(...)` em vez de texto fixo.
109
+
110
+ O script `test` do pacote roda `pnpm run build` antes.
111
+
112
+ ## Limitações e pontos de atenção
113
+
114
+ - `SgInputBirthDate` sem `minAge` nem `maxAge` acusa erro de configuração para qualquer data preenchida. **Confirmado**.
115
+ - `SgInputPassword` tem `maxLength` padrão **15**. `SgInputCPF`, `SgInputCNPJ` e `SgInputCPFCNPJ` têm `maxLength` padrão 18. **Confirmado**.
116
+ - `SgInputCPF`, `SgInputCNPJ`, `SgInputCPFCNPJ`, `SgInputPostalCode`, `SgInputDate` e `SgInputBirthDate` não repassam `required` ao `SgInputText`. Consequências:
117
+ - o rótulo fica sem `*`;
118
+ - as rules do RHF ficam sem `required` automático (a validação interna continua funcionando).
119
+
120
+ `SgInputPhone`, `SgInputEmail` e `SgInputPassword` repassam. **Confirmado** (`required={required}` só aparece nesses três).
121
+ - O erro não é anunciado a leitores de tela no `SgInputText` (sem `aria-invalid`/`aria-describedby`). O `SgToggleSwitch` e o `SgInputOTP` fazem isso. **Confirmado**.
122
+ - Para reagir ao foco, use `onEnter`: o `inputProps.onFocus` não é chamado pelo `SgInputText`. **Confirmado**; ver [[SeedGrid/SeedGrid-components/inputs-texto/API#Contrato base SgInputText|contrato base]].
123
+ - Os tipos de props de `SgInputEmail`, `SgInputPassword`, `SgInputDate` e `SgInputBirthDate` não são reexportados. **Confirmado**.
@@ -480,65 +480,65 @@ export default function Example() {
480
480
  `apps/showcase/src/app/components/sg-wizard/samples/nextdisabled.tsx.sample`
481
481
 
482
482
  ```tsx
483
- import React from "react";
484
- import { SgInputText, SgWizard, SgWizardPage } from "@seedgrid/fe-components";
485
-
486
- /**
487
- * `nextDisabled` — bloqueio JA conhecido.
488
- *
489
- * `onBeforeNext` e `validateStep` so agem no clique: o botao continua com aparencia de habilitado
490
- * e, quando eles recusam, nada acontece na tela. Quando o consumidor JA sabe que a etapa nao pode
491
- * avancar — tipicamente o resultado de uma checagem assincrona que ja terminou —, `nextDisabled`
492
- * deixa isso visivel: botao opaco, cursor de bloqueio e stepper sem oferecer as proximas etapas.
493
- */
494
- export default function Example() {
495
- const [codigo, setCodigo] = React.useState("");
496
- const [checando, setChecando] = React.useState(false);
497
- const [jaUsado, setJaUsado] = React.useState(false);
498
-
499
- // Simula a consulta ao servidor ao sair do campo.
500
- async function verificarCodigo() {
501
- if (!codigo.trim()) return;
502
- setChecando(true);
503
- await new Promise((resolve) => setTimeout(resolve, 600));
504
- setJaUsado(codigo.trim().toUpperCase() === "SG-123");
505
- setChecando(false);
506
- }
507
-
508
- return (
509
- <SgWizard
510
- // Durante a consulta o wizard ja desabilita sozinho enquanto aguarda onBeforeNext; aqui o
511
- // bloqueio PERMANECE depois que a resposta chegou.
512
- nextDisabled={jaUsado}
513
- onFinish={() => undefined}
514
- >
515
- <SgWizardPage title="Convite">
516
- <SgInputText
517
- id="wizard-codigo-convite"
518
- label="Codigo do convite"
519
- error={jaUsado ? "Este codigo ja foi utilizado." : undefined}
520
- onChange={(value) => {
521
- setCodigo(value);
522
- setJaUsado(false); // digitou de novo: reabre o avanco ate a proxima checagem
523
- }}
524
- onExit={() => void verificarCodigo()}
525
- />
526
- <p className="mt-2 text-sm text-muted-foreground">
527
- {checando
528
- ? "Verificando o codigo..."
529
- : 'Digite "SG-123" e saia do campo: o botao Proximo fica desabilitado.'}
530
- </p>
531
- </SgWizardPage>
532
- <SgWizardPage title="Conclusao">
533
- <div className="rounded border border-border bg-foreground/5 p-4">
534
- <div className="text-sm font-semibold">Codigo aceito</div>
535
- <p className="mt-1 text-sm text-muted-foreground">
536
- So se chega aqui com um codigo que a checagem liberou.
537
- </p>
538
- </div>
539
- </SgWizardPage>
540
- </SgWizard>
541
- );
483
+ import React from "react";
484
+ import { SgInputText, SgWizard, SgWizardPage } from "@seedgrid/fe-components";
485
+
486
+ /**
487
+ * `nextDisabled` — bloqueio JA conhecido.
488
+ *
489
+ * `onBeforeNext` e `validateStep` so agem no clique: o botao continua com aparencia de habilitado
490
+ * e, quando eles recusam, nada acontece na tela. Quando o consumidor JA sabe que a etapa nao pode
491
+ * avancar — tipicamente o resultado de uma checagem assincrona que ja terminou —, `nextDisabled`
492
+ * deixa isso visivel: botao opaco, cursor de bloqueio e stepper sem oferecer as proximas etapas.
493
+ */
494
+ export default function Example() {
495
+ const [codigo, setCodigo] = React.useState("");
496
+ const [checando, setChecando] = React.useState(false);
497
+ const [jaUsado, setJaUsado] = React.useState(false);
498
+
499
+ // Simula a consulta ao servidor ao sair do campo.
500
+ async function verificarCodigo() {
501
+ if (!codigo.trim()) return;
502
+ setChecando(true);
503
+ await new Promise((resolve) => setTimeout(resolve, 600));
504
+ setJaUsado(codigo.trim().toUpperCase() === "SG-123");
505
+ setChecando(false);
506
+ }
507
+
508
+ return (
509
+ <SgWizard
510
+ // Durante a consulta o wizard ja desabilita sozinho enquanto aguarda onBeforeNext; aqui o
511
+ // bloqueio PERMANECE depois que a resposta chegou.
512
+ nextDisabled={jaUsado}
513
+ onFinish={() => undefined}
514
+ >
515
+ <SgWizardPage title="Convite">
516
+ <SgInputText
517
+ id="wizard-codigo-convite"
518
+ label="Codigo do convite"
519
+ error={jaUsado ? "Este codigo ja foi utilizado." : undefined}
520
+ onChange={(value) => {
521
+ setCodigo(value);
522
+ setJaUsado(false); // digitou de novo: reabre o avanco ate a proxima checagem
523
+ }}
524
+ onExit={() => void verificarCodigo()}
525
+ />
526
+ <p className="mt-2 text-sm text-muted-foreground">
527
+ {checando
528
+ ? "Verificando o codigo..."
529
+ : 'Digite "SG-123" e saia do campo: o botao Proximo fica desabilitado.'}
530
+ </p>
531
+ </SgWizardPage>
532
+ <SgWizardPage title="Conclusao">
533
+ <div className="rounded border border-border bg-foreground/5 p-4">
534
+ <div className="text-sm font-semibold">Codigo aceito</div>
535
+ <p className="mt-1 text-sm text-muted-foreground">
536
+ So se chega aqui com um codigo que a checagem liberou.
537
+ </p>
538
+ </div>
539
+ </SgWizardPage>
540
+ </SgWizard>
541
+ );
542
542
  }
543
543
  ```
544
544
 
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "schemaVersion": 2,
3
- "contentVersion": "0.3.0",
3
+ "contentVersion": "0.3.1",
4
4
  "toolkitBase": "SeedGrid/Toolkit",
5
5
  "components": [
6
6
  {