Ir para o conteúdo principal
WBC - GovBR-DS
Copiar página como Markdown para IA

Anatomia de um componente

Guia para quem cria ou altera um componente no pacote @govbr-ds/webcomponents. As regras completas estão em AGENTS.md, AI-CONTEXT.md e nas instruções em .github/instructions/; aqui está o mapa prático.

Estrutura de arquivos​

Um componente vive em packages/webcomponents/src/components/<nome>/:

ArquivoPapel
<nome>.tsxClasse Stencil: ciclo de vida, estado, DOM e render. Nada de lógica reutilizável pesada aqui.
<nome>.scssEstilos do Shadow DOM. Use tokens do GovBR-DS, baixa especificidade, :focus-visible.
<nome>.types.tsTipos específicos do componente. Tipos compartilhados vão em components/global.types.ts.
<nome>.figma.tsFigma Code Connect (preenchido quando há equivalente visual no DS).
_tests/<nome>.e2e.tsxTestes E2E (Vitest browser mode + @stencil/vitest).
sections/*.mdBlocos editoriais incorporados à página do site: accessibility.md, migrate.md, native-events.md, native-attributes.md, validation.md.
readme.mdGerado a partir do JSDoc — não edite à mão.
<nome>.utils.tsOpcional: helpers locais não triviais. Lógica compartilhável vai para src/shared/utils.

Mantenha a ordem dentro do .tsx: imports/constantes → JSDoc → campos e decorators → ciclo de vida/listeners → métodos públicos → helpers privados → render. Inclua apenas as seções que existirem.

Fluxo​

# 1. Scaffold (cria .tsx/.scss/.types/.figma/_tests, sections/accessibility.md e
# sections/migrate.md, o exemplo default.html, presets.json e a página MDX).
pnpm plop component

# 2. Registrar no manifesto/menu e ver na bancada
pnpm generate:cem
pnpm dev # http://localhost:8001

# 3. Loop rápido de teste (com `pnpm dev` rodando noutro terminal)
pnpm test:watch <nome>

O pnpm plop marca o componente como @status experimental. Promova para beta/stable só quando a API estabilizar.

Convenções​

  • Nomes: tag pública br-<nome>; classe/interface/alias em PascalCase; props e métodos em camelCase.
  • API canônica: siga o vocabulário HTML/IDL (readOnly, tabIndex, disabled). Renomeações mantêm o alias antigo com @deprecated, mesma implementação, mesmo default/reflexão.
  • IDs: sempre generateUniqueId de src/shared/utils/id. Nunca Math.random, Date.now ou contador manual.
  • reflect: true: só quando um atributo, CSS ou consumidor externo exigir.
  • formAssociated + @AttachInternals(): só para controle de formulário nativo (input, select, checkbox…).
  • Estado: cada valor renderizado ou exposto por ARIA/formulário tem um único dono. Derive valores em vez de duplicar props em @State. Pai↔filho por props/eventos; slots por slotchange. Nada de document como barramento.

Eventos​

Antes de criar um evento customizado, confirme que o evento nativo não resolve. Eventos públicos novos: br<ComponentName><Action>, detail tipado, flags (bubbles/composed/cancelable) explícitos. Eventos legados — inclusive os sem esse padrão — não mudam de nome, payload, flags nem timing.

Controles internos em Shadow DOM preservam os eventos nativos aplicáveis (input, change, focus, blur, invalid) e reemitem no host no máximo uma vez por interação. Escrita programática, init e reset não são interação — não emita eventos neles. Documente o evento sintético sem prometer isTrusted.

Acessibilidade (mínimo)​

  • HTML semântico antes de ARIA; todo controle com nome, papel, estado e valor.
  • Operação completa por teclado, :focus-visible, ordem previsível, nenhum tabindex positivo.
  • Em Shadow DOM, teste as relações reais de label/aria-describedby/ aria-controls entre host, controle interno e conteúdo projetado.
  • Movimento estático por padrão; transições só em prefers-reduced-motion: no-preference, com tokens existentes.
  • Preencha sections/accessibility.md com o contrato real (teclas, foco, estados). Veja button/sections/accessibility.md como referência.

Documentação​

  • Documente imediatamente cada @Prop, @State, @Event, @Method (um bloco JSDoc cada) e @slot/@part quando forem contrato público.
  • O JSDoc principal da classe (Visão Geral) define função, papel, quando usar e quando evitar, e a composição com subcomponentes.
  • Valores estruturados, callbacks, Date ou property binding não óbvios pedem @example executável.
  • A página do site é apps/site/docs/components/<nome>/index.mdx — importe só as seções que o gerador emitir (ele só cria as que têm conteúdo).

Testes​

  • Vitest 4 + @stencil/vitest em browser mode (provider Playwright, headless).
  • Use render, userEvent, waitForStable e os helpers de src/shared/test-utils; queryPiercing quando a composição atravessar Shadow DOMs. expectNoAxeViolations é evidência complementar, não substitui teclado e foco.
  • Loop rápido: pnpm test:component <nome> / pnpm test:watch <nome> / pnpm test:changed. Esses atalhos usam www; mudanças compartilhadas selecionam toda a suíte do core. A suíte completa (pnpm tests) usa dist. Nenhum desses comandos inicia build: aguarde o watch da saída escolhida ou compile explicitamente antes de testar. WBC_TEST_BUNDLE=dist|www seleciona outra saída sem fallback.
  • Matriz de navegadores: pnpm exec nx run webcomponents:test:platform.

Antes do MR​

  • Checagem rápida: pnpm lint, pnpm typecheck, pnpm test:contract.
  • Mudança de API pública → .github/review-checklists/component-api.md.
  • Mudança de estado/eventos → .github/review-checklists/state-events.md.
  • pnpm figma:validate:structure e pnpm figma:parse quando houver Code Connect.
  • Não rode pnpm build ou pnpm generate por rotina — só quando o tipo de mudança exigir. Nenhum git commit automático.
Comece aquiComponentesQuickstartsSobre o projetoRepositório GitLabVersõesDiscordGovBR-DSFAQWikiRedefinir cookies