# Fieldset

![Status](https://img.shields.io/badge/status-stable-brightgreen)

Componente de agrupamento de campos de formulário com legenda, ícone e suporte a toggle (recolher/expandir) com animação. Aceita templates customizados via `sTemplate="header"` (cabeçalho) e `sTemplate="body"` (conteúdo).

## Quando usar

- Agrupar campos relacionados em formulários longos com separação visual por título
- Seções opcionais que podem ser recolhidas para reduzir a carga visual
- Formulários com múltiplas seções que precisam de diferenciação visual

## Quando não usar

- Agrupamentos sem necessidade de título — use `<div>` simples
- Múltiplos painéis onde apenas um pode estar aberto por vez — use [`Accordion`](../accordion/README.md)

## Instalação

```typescript
import { FieldsetModule } from '@seniorsistemas/angular-components/fieldset';
import { TemplateDirective } from '@seniorsistemas/angular-components/template';

@Component({ standalone: true, imports: [FieldsetModule, TemplateDirective] })
export class MeuComponent {}
```

## Uso básico

```html
<s-fieldset legend="Dados Pessoais">
  <ng-template sTemplate="body">
    <p>Conteúdo do fieldset</p>
  </ng-template>
</s-fieldset>
```

> **Declare o conteúdo em `sTemplate="body"`.** Projetar direto via `ng-content` continua funcionando, mas o conteúdo é instanciado pelo componente pai mesmo com o fieldset recolhido — o que dispara o `ngOnInit` dos componentes filhos prematuramente. O template de corpo só é instanciado quando o fieldset está de fato ativo, e é obrigatório para que `destroyOnHide` funcione (sem ele o componente emite um aviso no console).
>
> Projetos existentes podem ser convertidos automaticamente com `ng update @seniorsistemas/angular-components` — veja [Migração automática](#migração-automática).

## API

### Inputs

| Propriedade | Tipo | Padrão | Obrigatório | Descrição |
|-------------|------|--------|:-----------:|-----------|
| `legend` | `string` | `''` | — | Texto exibido como título do fieldset |
| `icon` | `string` | `''` | — | Classe de ícone exibida ao lado da legenda (ex: `'fas fa-cog'`) |
| `toggleable` | `boolean` | `false` | — | Habilita o botão +/- para recolher e expandir com animação |
| `destroyOnHide` | `boolean` | `false` | — | Remove o conteúdo do DOM ao recolher. Requer o conteúdo declarado em `sTemplate="body"` |
| `active` | `boolean` | `true` | — | Estado aberto/recolhido. Suporta two-way binding via `[(active)]` |

### Slots de conteúdo

| Slot | Descrição |
|------|-----------|
| `sTemplate="header"` | Substitui completamente o cabeçalho padrão (legenda + ícone). O ícone +/- do toggle continua sendo renderizado |
| `sTemplate="body"` | Conteúdo do fieldset, instanciado somente quando o fieldset está ativo |
| `ng-content` (default) | Fallback usado apenas quando não há `sTemplate="body"` |

### Outputs

| Evento | Tipo | Descrição |
|--------|------|-----------|
| `beforeToggle` | `EventEmitter<FieldSetToggle>` | Emitido antes da animação de toggle iniciar |
| `afterToggle` | `EventEmitter<FieldSetToggle>` | Emitido após a animação de toggle concluir |

### Tipos

```typescript
type FieldSetToggle = {
  originalEvent: PointerEvent | KeyboardEvent;
  collapsed: boolean; // true = estava aberto e vai fechar; false = estava fechado e vai abrir
};
```

## Exemplos

### Fieldset básico

```html
<s-fieldset legend="Dados Pessoais">
  <ng-template sTemplate="body">
    <div style="display: flex; flex-direction: column; gap: 12px;">
      <input type="text" placeholder="Nome completo" />
      <input type="text" placeholder="CPF" />
    </div>
  </ng-template>
</s-fieldset>
```

### Fieldset colapsável com ícone

```html
<s-fieldset
  legend="Informações de Contato"
  icon="fas fa-phone"
  [toggleable]="true"
  (beforeToggle)="onBeforeToggle($event)"
  (afterToggle)="onAfterToggle($event)"
>
  <ng-template sTemplate="body">
    <input type="tel" placeholder="(00) 00000-0000" />
    <input type="email" placeholder="email@empresa.com" />
  </ng-template>
</s-fieldset>
```

### Colapsável preservando estado do formulário

Com `destroyOnHide=false` (padrão) o conteúdo permanece no DOM ao recolher, apenas oculto:

```html
<s-fieldset legend="Dados Opcionais" [toggleable]="true">
  <ng-template sTemplate="body">
    <input formControlName="complemento" placeholder="Complemento" />
  </ng-template>
</s-fieldset>
```

### Colapsável destruindo o conteúdo ao recolher

Use `destroyOnHide=true` para adiar a construção dos componentes filhos até a primeira abertura e liberá-los ao recolher. **Requer** o conteúdo em `sTemplate="body"`:

```html
<s-fieldset legend="Relatório Pesado" [toggleable]="true" [destroyOnHide]="true" [active]="false">
  <ng-template sTemplate="body">
    <app-relatorio-pesado></app-relatorio-pesado>
  </ng-template>
</s-fieldset>
```

### Controlando o estado por código

```html
<s-fieldset legend="Filtros" [toggleable]="true" [(active)]="filtrosAbertos">
  <ng-template sTemplate="body">
    <input formControlName="busca" />
  </ng-template>
</s-fieldset>
```

### Com cabeçalho customizado via template

```html
<s-fieldset [toggleable]="true">
  <ng-template sTemplate="header">
    <div style="display: flex; align-items: center; gap: 8px;">
      <span style="background: #fee2e2; width: 8px; height: 8px; border-radius: 50%;"></span>
      <span>Dados Bancários</span>
      <span style="font-size: 0.75rem; color: #dc2626;">(campos obrigatórios)</span>
    </div>
  </ng-template>
  <ng-template sTemplate="body">
    <input type="text" placeholder="Banco" />
  </ng-template>
</s-fieldset>
```

### Múltiplos fieldsets em um formulário

```html
<div style="display: flex; flex-direction: column; gap: 16px;">
  <s-fieldset legend="Dados Pessoais" icon="fas fa-user" [toggleable]="true">
    <ng-template sTemplate="body">
      <!-- campos -->
    </ng-template>
  </s-fieldset>
  <s-fieldset legend="Endereço" icon="fas fa-map-marker-alt" [toggleable]="true">
    <ng-template sTemplate="body">
      <!-- campos -->
    </ng-template>
  </s-fieldset>
</div>
```

## Migração automática

Projetos que declaram o conteúdo via `ng-content` podem ser convertidos para `sTemplate="body"` automaticamente:

```bash
ng update @seniorsistemas/angular-components
```

A migration `migration-v19-9-3-fieldset-body-template` envolve o conteúdo projetado de cada `<s-fieldset>` em `<ng-template sTemplate="body">`, mantém os templates de slot já existentes (como `sTemplate="header"`) fora do corpo e adiciona o `TemplateDirective` ao escopo do componente quando ele ainda não estiver disponível — inclusive verificando se já vem reexportado por um `SharedModule`. Fieldsets que já usam `sTemplate="body"` são ignorados, então a execução é idempotente.

## Acessibilidade

- O botão de toggle é ativável por teclado (Enter e Space)
- A animação de recolher/expandir tem duração de 300ms (respeitando `prefers-reduced-motion` via CSS)
- O ícone decorativo não possui texto alternativo obrigatório

## Componentes relacionados

- [`Accordion`](../accordion/README.md) — painéis expansíveis onde apenas um pode estar aberto por vez
- [`DynamicForm`](../dynamic-form/README.md) — usa fieldset internamente para estruturar formulários dinâmicos
