# React – @govbr-ds/webcomponents-react

Este é um wrapper React que encapsula os [Web Components GovBR-DS](https://gov.br/ds/webcomponents), permitindo seu uso como componentes nativos do React.

## Compatibilidade

- **Faixa declarada:** `react` e `react-dom` conforme as `peerDependencies` do pacote, com `react-dom` na mesma major de `react`.
- **Núcleo de Web Components:** `@govbr-ds/webcomponents` na mesma versão deste wrapper.
- **Navegadores:** A mesma política Baseline Widely Available dos Web Components. Internet Explorer não é suportado.

> [!NOTE]
> React 18 e React 19 continuam suportados no cliente (CSR). O caminho SSR assíncrono do wrapper React (`@govbr-ds/webcomponents-react/ssr`) é verificado a partir do React 19 Server Components. No React 18, use a entrada principal para SSR clássico.
> O wrapper não faz requisições HTTP, autenticação, cache ou transporte de dados — essas responsabilidades permanecem na aplicação consumidora.

## Por que usar este wrapper? 🤔

- **Bindings JSX** para props/eventos.
- **Tipagens e autocomplete** nos IDEs.
- **Soluciona limitações** de passagem de objetos/arrays e captura de eventos em custom elements no React.

Para mais detalhes, consulte a [documentação oficial do Stencil](https://stenciljs.com/docs/react) e o [Custom Elements Everywhere](https://custom-elements-everywhere.com/#react).

## Instalação 📦

```bash
npm install @govbr-ds/webcomponents-react
# ou
pnpm add @govbr-ds/webcomponents-react
# ou
yarn add @govbr-ds/webcomponents-react
```

### peerDependencies

`peerDependencies` são pacotes que este wrapper **não instala automaticamente** — o seu projeto precisa tê-los instalados.

Observe que algumas peerDependencies podem ter suas próprias peerDependencies que também precisam ser atendidas. Consulte a documentação de cada pacote para garantir que todas as dependências necessárias estejam presentes.

**Por que existem:** Garantem que o seu app e o wrapper compartilhem a **mesma instância** do React e dos Web Components. Versões duplicadas podem causar erros em tempo de execução ou comportamentos inesperados.

**O que isso implica:** Se as peers não estiverem instaladas ou forem incompatíveis, componentes podem não funcionar.

As peers declaradas neste pacote são:

- `react`
- `react-dom`
- `@govbr-ds/webcomponents`

As versões aceitas estão em `peerDependencies` no `package.json` publicado deste pacote (também exibidas na página do npm e na [política de compatibilidade](https://gov.br/ds/webcomponents)). O peer `@govbr-ds/webcomponents` exige exatamente a mesma versão deste wrapper.

## Nota importante: pnpm e tree-shaking

Se ao consumir estes pacotes você notar que o bundler não está removendo código não utilizado (tree‑shaking), pode haver uma incompatibilidade com o layout padrão do pnpm.

Solução rápida (opcional, somente se precisar): crie um arquivo `.npmrc` na raiz do seu projeto com:

```properties
node-linker=hoisted
```

Por que isso ajuda: por padrão, o pnpm organiza as dependências em pastas isoladas com symlinks. Alguns bundlers/otimizadores se baseiam na estrutura de `node_modules` e no campo `sideEffects` para decidir o que pode ser eliminado. O layout hoisted aproxima o formato “achatado” (similar ao npm/yarn), facilitando essa análise e, em muitos casos, restaurando o tree‑shaking.
Observações:

- Use apenas se o tree‑shaking realmente não estiver funcionando.
- Pode aumentar o uso de disco e alterar a resolução de dependências do seu projeto.

## Quickstart React

Use o quickstart React como referência para configuração de projeto:

- Repositório: [govbr-ds-wbc-quickstart-react](https://gitlab.com/govbr-ds/bibliotecas/wbc/govbr-ds-wbc-quickstart-react)
- Servidor local: `pnpm dev`
- Formulários: estado controlado, FormData não controlado e React Hook Form
- Testes headless: `pnpm test:e2e`
- Porta padrão: `http://localhost:5173/`

## Uso 📚

### Exemplo

```tsx
import { BrButton } from '@govbr-ds/webcomponents-react';

export default function App() {
  return (
    <BrButton emphasis="primary" onClick={() => console.log('Ação solicitada')}>
      Clique aqui
    </BrButton>
  );
}
```

Eventos nativos usam props React como `onInput`, `onChange` e `onClick`; leia o estado em `event.currentTarget`. Somente eventos customizados documentados, como `onBrSelectSearch`, usam `event.detail`.

| Componentes | Propriedade controlada | Evento de usuário | Valor no state |
| --- | --- | --- | --- |
| input textual e textarea | `value` | `onInput` | `string` |
| slider simples | `value` | `onInput` | `number` |
| datas simples | `value` | `onInput` | `Date \| null` |
| select e radio group | `value` | `onChange` | seleção |
| checkbox e switch | `checked` | `onChange` | `boolean` |
| upload | `files` | `onChange` | `FileList \| null` |
| tag selecionável | `selected` | `onChange` | seleção |

Inclua `name` em todo campo que deve participar de `FormData`. Não tente controlar `FileList`: leia `files` por evento/ref e use o reset nativo para limpar o upload.

Em datas simples, passe uma instância válida de `Date` ou `null` para `value` e leia o mesmo tipo em `event.currentTarget.value`. `FormData` recebe a representação textual serializada pelo componente. Se o estado vier de `localStorage` ou de uma API, converta a string para `Date` antes de renderizar o campo.

### Validação e Acessibilidade (React Hook Form)

Use `Controller` para adaptar explicitamente a propriedade e o evento da tabela. Para sinalizar erros, atualize `state`, mostre um `BrMessage` textual e preserve o vínculo acessível do campo.

```tsx
import { Controller, useForm } from 'react-hook-form';
import { BrButton, BrInput, BrMessage } from '@govbr-ds/webcomponents-react';

type LoginFormData = {
  email: string;
};

function LoginForm() {
  const initialValues: LoginFormData = { email: '' };
  const {
    control,
    handleSubmit,
    reset,
  } = useForm<LoginFormData>({ defaultValues: initialValues, mode: 'onBlur' });

  const onSubmit = (data: LoginFormData) => console.log(data);

  return (
    <form onSubmit={handleSubmit(onSubmit)} onReset={() => reset(initialValues)} noValidate>
      <Controller
        name="email"
        control={control}
        rules={{
          required: 'E-mail é obrigatório.',
          pattern: { value: /^[^\s@]+@[^\s@]+\.[^\s@]+$/, message: 'Informe um e-mail válido.' },
        }}
        render={({ field, fieldState: { error } }) => (
          <>
            <BrInput
              name="email"
              type="email"
              label="E-mail"
              value={field.value}
              required
              onInput={(event) => field.onChange(event.currentTarget.value)}
              onBlur={field.onBlur}
              state={error ? 'danger' : undefined}
              aria-invalid={Boolean(error)}
            />
            {error && <BrMessage state="danger" isFeedback message={error.message} />}
          </>
        )}
      />

      <BrButton type="reset" emphasis="secondary">Limpar</BrButton>
      <BrButton type="submit">Entrar</BrButton>
    </form>
  );
}
```

Em formulários controlados, o reset tem duas partes: o botão `type="reset"` restaura os controles associados e `reset(initialValues)` restaura o estado da biblioteca. Escritas programáticas em props não emitem eventos; atualize o estado React diretamente.

## Dependências de Build 🛠️

Este pacote é um wrapper gerado automaticamente e depende dos artefatos produzidos pelo núcleo de Web Components.

| Pacote                          | Dependência de Build  | Motivo                                                                                                                          |
| :------------------------------ | :-------------------- | :------------------------------------------------------------------------------------------------------------------------------ |
| `@govbr-ds/webcomponents-react` | `webcomponents:build` | Necessita dos proxies gerados em `src/stencil-generated` e do build de `hydrate` para suporte a SSR em `ssr/stencil-generated`. |

---

## Desenvolvimento 👨‍💻

### Estrutura do projeto

```plaintext
├── 📁 src
│   ├── 📁 stencil-generated
│   └── 📄 index.ts
├── 📁 ssr
│   ├── 📁 stencil-generated
│   └── 📄 index.ts
```

> [!WARNING]
> Tudo dentro de `stencil-generated` é sobrescrito ao gerar o build de Web Components.

### Scripts/Build

Gere os Web Components antes de compilar o wrapper:

```bash
nx build webcomponents
nx build react
```

### SSR (Server-Side Rendering)

O wrapper React possui suporte a SSR via o subpath `ssr/`. Essa entrada usa o
Server Component assíncrono gerado pelo Stencil e deve ser usada em frameworks
que suportem essa fronteira (por exemplo, Server Components do React 19):

```tsx
import { BrButton } from '@govbr-ds/webcomponents-react/ssr';
```

Componentes importados pelo subpath `ssr` são renderizados de forma segura no
servidor, sem dependência de APIs do navegador durante o build. Em React 18 com
`react-dom/server` clássico, use a entrada principal; ela gera o custom element
no HTML e o comportamento do componente é ativado quando o cliente carrega os
Web Components.

## Formatos do build 📦

A tarefa `nx build react` compila o wrapper e gera a saída em `dist/react/`. Abaixo estão os artefatos produzidos e quando utilizá-los.

### Estrutura do `dist/react/`

```plaintext
dist/react/
├── src/
│   ├── index.js          ← Entrada principal (ESM)
│   ├── index.d.ts        ← Tipos TypeScript
│   └── stencil-generated/
│       └── components.js ← Componentes proxy (gerados pelo Stencil)
├── ssr/
│   ├── index.js          ← Entrada SSR (ESM)
│   └── stencil-generated/
│       └── components.server.js ← Componentes SSR (hydrate)
├── package.json
└── README.md
```

### Quando usar cada formato

| Artefato         | Quando usar                                              | Observações                                                                                    |
| ---------------- | -------------------------------------------------------- | ---------------------------------------------------------------------------------------------- |
| `src/index.js`   | Aplicações React CSR (client-side)                       | Importação padrão via `@govbr-ds/webcomponents-react`                                          |
| `ssr/index.js`   | Server Components/SSR assíncrono compatível com React 19 | Importação via `@govbr-ds/webcomponents-react/ssr`; usa `dist/hydrate` do pacote webcomponents |
| `src/index.d.ts` | Autocomplete e tipagem TypeScript                        | Resolvido automaticamente pelo campo `types` do `package.json`                                 |

### CSR vs SSR

- **CSR (Client-Side Rendering)**: importação padrão. Os componentes são registrados e renderizados no browser.
- **SSR (Server-Side Rendering)**: os componentes são pré-renderizados no servidor usando o script `hydrate` do pacote `@govbr-ds/webcomponents`. No cliente, o Stencil faz a hidratação do HTML pré-renderizado.

```tsx
// CSR — uso padrão
import { BrButton } from '@govbr-ds/webcomponents-react';

// SSR assíncrono — Server Components/React 19
import { BrButton } from '@govbr-ds/webcomponents-react/ssr';
```

Para SSR clássico com React 18, mantenha a importação principal:

```tsx
import { BrButton } from '@govbr-ds/webcomponents-react';
```

> [!NOTE]
> O subpath `ssr/` depende de `@govbr-ds/webcomponents/dist/hydrate`. Certifique-se de que o pacote `@govbr-ds/webcomponents` está instalado.

## Documentações Complementares 📖

- Wiki: [gov.br/ds/wiki/desenvolvimento/web-components](https://gov.br/ds/wiki/desenvolvimento/web-components)
- MDN Web Components: [developer.mozilla.org/Web_Components](https://developer.mozilla.org/pt-BR/docs/Web/Web_Components)

## Contribuindo 🤝

- Padrões e boas práticas: [gov.br/ds/wiki](https://gov.br/ds/wiki/)
- Como contribuir: [contribuindo com o DS](https://gov.br/ds/wiki/comunidade/contribuindo-com-o-ds/)

## Reportar Bugs/Problemas 🐛

Abra uma issue: [gitlab.com/.../issues/new](https://gitlab.com/govbr-ds/bibliotecas/wbc/govbr-ds-wbc/-/issues/new)

## Commits 📝

Padrões de branches e commits: [gov.br/ds/wiki](https://gov.br/ds/wiki/)

## Precisa de ajuda? 🆘

- Site: [gov.br/ds](http://gov.br/ds)
- Web Components: [gov.br/ds/webcomponents](https://gov.br/ds/webcomponents)
- Discord: [discord.gg/U5GwPfqhUP](https://discord.gg/U5GwPfqhUP)

## Créditos 🎉

Desenvolvido pelo [SERPRO](https://www.serpro.gov.br/) com a comunidade.
