@softize/opus 21.0.1 → 22.1.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 (62) hide show
  1. package/CHANGELOG.md +71 -0
  2. package/bin/cli.mjs +9 -1
  3. package/bin/lib/check.mjs +37 -29
  4. package/docs/adr/0004-page-content-state-is-composed.md +3 -2
  5. package/docs/adr/0005-structural-surfaces-share-an-explicit-anatomy.md +3 -0
  6. package/docs/adr/0006-semantic-context-precedes-visual-variant.md +23 -14
  7. package/docs/adr/0011-page-shell-coordinates-persistent-page-chrome.md +5 -0
  8. package/docs/adr/0013-presentation-is-a-portable-action-oriented-artifact.md +7 -4
  9. package/docs/adr/0016-list-collection-header-belongs-to-content.md +13 -8
  10. package/docs/adr/0023-surfaces-share-one-anatomy-and-two-layouts.md +27 -26
  11. package/docs/adr/0025-content-frame-treatment-does-not-change-semantics.md +1 -0
  12. package/docs/adr/0029-page-header-is-the-single-page-introduction.md +71 -0
  13. package/docs/adr/0030-framed-content-can-use-sectioned-anatomy.md +89 -0
  14. package/docs/adr/0031-detail-dividers-own-the-tabular-label-treatment.md +61 -0
  15. package/docs/adr/0032-tab-baseline-respects-the-container-inset.md +59 -0
  16. package/docs/adr/0033-drawer-uses-an-inset-structural-frame.md +72 -0
  17. package/docs/adr/0034-tabs-can-own-a-frame-without-owning-a-surface.md +60 -0
  18. package/docs/adr/0035-button-group-separates-frame-relationship-and-distribution.md +63 -0
  19. package/docs/adr/0036-tabs-declares-trigger-distribution.md +58 -0
  20. package/docs/adr/0037-design-data-lives-outside-the-contract.md +117 -0
  21. package/docs/radius-scale.md +5 -2
  22. package/package.json +5 -1
  23. package/registry/skills/build-opus-ui/SKILL.md +9 -6
  24. package/registry/skills/build-opus-ui/references/evaluations.md +5 -2
  25. package/registry/skills/build-opus-ui/references/ui-patterns.md +14 -16
  26. package/registry/skills/create-opus-action/references/contract-and-binding.md +5 -3
  27. package/registry/skills/create-opus-action/scripts/scaffold.mjs +0 -4
  28. package/registry/skills/test-opus-action/SKILL.md +2 -2
  29. package/registry/skills/test-opus-action/references/harness.md +2 -2
  30. package/registry/templates/app/src/App.tsx +1 -1
  31. package/registry/templates/app/src/domains/tasks/actions/list.test.ts +2 -19
  32. package/registry/templates/app/src/domains/tasks/actions/list.ts +3 -5
  33. package/registry/templates/app/vite.config.ts +3 -2
  34. package/src/core/domain.ts +2 -2
  35. package/src/core/types.ts +6 -20
  36. package/src/design/index.ts +179 -0
  37. package/src/testing/fake.ts +2 -2
  38. package/src/testing/index.ts +7 -3
  39. package/src/ui/components/patterns/content-header.tsx +51 -13
  40. package/src/ui/components/patterns/list.tsx +51 -33
  41. package/src/ui/components/patterns/page.tsx +139 -251
  42. package/src/ui/components/patterns/presentation.tsx +2 -6
  43. package/src/ui/components/primitives/button-group.tsx +80 -8
  44. package/src/ui/components/primitives/button.tsx +85 -60
  45. package/src/ui/components/primitives/detail.tsx +63 -57
  46. package/src/ui/components/primitives/dialog.tsx +8 -11
  47. package/src/ui/components/primitives/drawer.tsx +16 -12
  48. package/src/ui/components/primitives/tabs.tsx +123 -54
  49. package/src/ui/docs/content/actions.md +49 -43
  50. package/src/ui/docs/content/button.md +55 -29
  51. package/src/ui/docs/content/content.md +61 -36
  52. package/src/ui/docs/content/detail.md +28 -19
  53. package/src/ui/docs/content/drawer.md +53 -47
  54. package/src/ui/docs/content/input.md +51 -35
  55. package/src/ui/docs/content/page.md +84 -95
  56. package/src/ui/docs/content/pane.md +83 -63
  57. package/src/ui/docs/content/presentation.md +20 -20
  58. package/src/ui/docs/content/tabs.md +107 -36
  59. package/src/ui/docs/content/testing.md +9 -25
  60. package/src/ui/meta.ts +5 -5
  61. package/src/ui/react.tsx +0 -1
  62. package/src/vite/design.ts +133 -23
@@ -4,11 +4,11 @@ Use `Content` para dar título e estrutura a uma região dentro de `PageBody`, `
4
4
  `DialogBody` ou outra superfície. Ele renderiza uma `section` ligada ao próprio título e mantém o
5
5
  espaçamento entre header e body. `ContentHeader` pertence sempre a essa estrutura; não o use solto.
6
6
 
7
- O `Content` é contínuo por definição e não expõe `layout`: ele é uma região nomeada dentro de outra
8
- superfície, e a escolha entre regiões seccionadas e contínuas pertence a quem a hospeda — o
9
- [`Card`](/ui/card), o [`Dialog`](/ui/dialog), o [`Drawer`](/ui/drawer) ou o [`Pane`](/ui/pane).
10
- Quando a própria região precisar de uma fronteira visível, use `framed`, descrito adiante. Pelo
11
- mesmo motivo o `Content` não tem rodapé: um rodapé pertence à superfície que a hospeda.
7
+ O `Content` é uma região nomeada dentro de outra superfície. Sem moldura, ele mantém a anatomia
8
+ contínua. Com `framed`, pode permanecer contínuo ou separar header e body com
9
+ `layout="sectioned"`. O layout organiza as regiões internas; não transforma `Content` em
10
+ [`Card`](/ui/card), [`Dialog`](/ui/dialog), [`Drawer`](/ui/drawer) ou [`Pane`](/ui/pane). Pelo mesmo
11
+ motivo o `Content` não tem rodapé: um rodapé pertence à superfície que o hospeda.
12
12
 
13
13
  No caso comum, prefira o shorthand. `count` mostra o total de itens ao lado do título:
14
14
 
@@ -36,11 +36,7 @@ do recuo da região.
36
36
 
37
37
  ```tsx preview col
38
38
  render(
39
- <Content
40
- framed
41
- title="Cliente"
42
- media={<UserRound aria-hidden="true" />}
43
- >
39
+ <Content framed title="Cliente" media={<UserRound aria-hidden="true" />}>
44
40
  <DetailGroup columns={2}>
45
41
  <DetailField label="Nome" value="Carla Souza" />
46
42
  <DetailField label="Telefone" value="+55 11 97333-4455" />
@@ -93,6 +89,34 @@ render(
93
89
  );
94
90
  ```
95
91
 
92
+ ## Header e body seccionados
93
+
94
+ Use `layout="sectioned"` quando o filho do body já controlar o recuo de suas células, linhas ou
95
+ itens. O header recebe `p-3` e divisor inferior; o body fica sem padding para que a estrutura interna
96
+ alcance a moldura. Esse layout exige `framed`.
97
+
98
+ ```tsx preview col
99
+ render(
100
+ <Content
101
+ framed
102
+ layout="sectioned"
103
+ title="Veículo"
104
+ media={<CarFront aria-hidden="true" />}
105
+ >
106
+ <DetailGroup dividers columns={2} orientation="horizontal">
107
+ <DetailField label="Marca" value="Toyota" />
108
+ <DetailField label="Modelo" value="Yaris XLS" />
109
+ <DetailField label="Ano/modelo" value="2021" />
110
+ <DetailField label="Placa" value="EVT0012" />
111
+ </DetailGroup>
112
+ </Content>,
113
+ );
114
+ ```
115
+
116
+ Conteúdo livre que não possui recuo próprio continua no layout `continuous`. Não combine
117
+ `layout="sectioned"` com `frameVariant="legend"`: `sectioned` coloca o header dentro da moldura;
118
+ `legend` integra o header ao traço externo.
119
+
96
120
  ## Grupo de campos
97
121
 
98
122
  Quando a região nomear um conjunto de campos relacionados, use `as="fieldset"`. O `Content`
@@ -129,12 +153,7 @@ decisão semântica, e não uma forma de obter esse desenho.
129
153
 
130
154
  ```tsx preview col
131
155
  render(
132
- <Content
133
- as="fieldset"
134
- framed
135
- frameVariant="legend"
136
- title="Dados do veículo"
137
- >
156
+ <Content as="fieldset" framed frameVariant="legend" title="Dados do veículo">
138
157
  <FieldGroup>
139
158
  <Field>
140
159
  <FieldLabel htmlFor="vehicle-plate">Placa</FieldLabel>
@@ -192,7 +211,12 @@ extremo oposto ao título, como em qualquer variante.
192
211
 
193
212
  ```tsx preview col
194
213
  render(
195
- <Content level={1} variant="page" title="Clientes" actions={<Button>Criar cliente</Button>}>
214
+ <Content
215
+ level={1}
216
+ variant="page"
217
+ title="Clientes"
218
+ actions={<Button>Criar cliente</Button>}
219
+ >
196
220
  <div className="rounded-lg border border-border p-4 text-sm text-muted-foreground">
197
221
  A lista de clientes ocupa o corpo.
198
222
  </div>
@@ -211,19 +235,20 @@ classes adicionais; um `Content` irmão, sem lista, mantém a altura do próprio
211
235
 
212
236
  ## Propriedades de Content
213
237
 
214
- | Propriedade | Tipo | Padrão | Descrição |
215
- | -------------- | ---------------------------- | ----------- | ----------------------------------------------------------------------------------------------------------------------- |
216
- | `title` | `ReactNode` | | Forma curta: título da região (vira o heading ligado à `section`). |
217
- | `media` | `ReactNode` | | Forma curta: ícone ou imagem que identifica a região antes do título. |
218
- | `count` | `number` | | Forma curta: total de itens ao lado do título da região. |
219
- | `description` | `ReactNode` | | Forma curta: frase de apoio sob o título. |
220
- | `actions` | `ReactNode` | | Forma curta: ações sobre a região inteira, no extremo oposto ao título. |
221
- | `level` | `1 \| 2 \| 3 \| 4 \| 5 \| 6` | `2` | Nível semântico do heading, independente do destaque visual. |
222
- | `variant` | `'page' \| 'section'` | `'section'` | Hierarquia visual: `page` reproduz o cabeçalho de `Page`; `section` é a região dentro de uma superfície. |
223
- | `as` | `'section' \| 'fieldset'` | `'section'` | Usa uma região com heading ou um grupo de campos cujo título é a legenda nativa. |
224
- | `framed` | `boolean` | `false` | Envolve o header e o body com a moldura estrutural da região. |
225
- | `frameVariant` | `'default' \| 'legend'` | `'default'` | Mantém a borda contínua ou integra visualmente o header à moldura. Não altera o elemento nem sua semântica. |
226
- | `children` | `ReactNode` | | Corpo da região na forma curta, ou `ContentHeader` e `ContentBody` na composição explícita. |
238
+ | Propriedade | Tipo | Padrão | Descrição |
239
+ | -------------- | ----------------------------- | -------------- | ----------------------------------------------------------------------------------------------------------------- |
240
+ | `title` | `ReactNode` | | Forma curta: título da região (vira o heading ligado à `section`). |
241
+ | `media` | `ReactNode` | | Forma curta: ícone ou imagem que identifica a região antes do título. |
242
+ | `count` | `number` | | Forma curta: total de itens ao lado do título da região. |
243
+ | `description` | `ReactNode` | | Forma curta: frase de apoio sob o título. |
244
+ | `actions` | `ReactNode` | | Forma curta: ações sobre a região inteira, no extremo oposto ao título. |
245
+ | `level` | `1 \| 2 \| 3 \| 4 \| 5 \| 6` | `2` | Nível semântico do heading, independente do destaque visual. |
246
+ | `variant` | `'page' \| 'section'` | `'section'` | Hierarquia visual: `page` reproduz o cabeçalho de `Page`; `section` é a região dentro de uma superfície. |
247
+ | `as` | `'section' \| 'fieldset'` | `'section'` | Usa uma região com heading ou um grupo de campos cujo título é a legenda nativa. |
248
+ | `framed` | `boolean` | `false` | Envolve o header e o body com a moldura estrutural da região. |
249
+ | `layout` | `'continuous' \| 'sectioned'` | `'continuous'` | Mantém header e body contínuos ou os separa com divisor e body sem recuo. `sectioned` exige `framed`. |
250
+ | `frameVariant` | `'default' \| 'legend'` | `'default'` | Mantém a borda contínua ou integra visualmente o header à moldura. `legend` não combina com `layout="sectioned"`. |
251
+ | `children` | `ReactNode` | | Corpo da região na forma curta, ou `ContentHeader` e `ContentBody` na composição explícita. |
227
252
 
228
253
  As demais propriedades são as nativas de `section` ou, com `as="fieldset"`, de `fieldset`.
229
254
 
@@ -235,12 +260,12 @@ hierarquia é declarada em `Content`. `ContentHeader` não existe fora de `Conte
235
260
 
236
261
  ## Propriedades de ContentMedia
237
262
 
238
- | Propriedade | Tipo | Padrão | Descrição |
239
- | ----------- | ------------------------------------------------------------------------ | ----------- | --------------------------------------------------------------------------------------------------------------------------- |
240
- | `size` | `'xs' \| 'sm' \| 'default' \| 'lg'` | `'xs'` | Tamanho da moldura e do glifo na escala compartilhada dos controles. |
241
- | `context` | `'neutral' \| 'primary' \| 'info' \| 'success' \| 'warning' \| 'danger'` | `'neutral'` | Declara o significado da cor. |
242
- | `variant` | `'subtle' \| 'outline'` | `'subtle'` | Usa preenchimento tonal ou acrescenta borda. |
243
- | `className` | `string` | | Ajusta a moldura sem substituir a escala. |
263
+ | Propriedade | Tipo | Padrão | Descrição |
264
+ | ----------- | ------------------------------------------------------------------------ | ----------- | -------------------------------------------------------------------------------------------------------------------------- |
265
+ | `size` | `'xs' \| 'sm' \| 'default' \| 'lg'` | `'xs'` | Tamanho da moldura e do glifo na escala compartilhada dos controles. |
266
+ | `context` | `'neutral' \| 'primary' \| 'info' \| 'success' \| 'warning' \| 'danger'` | `'neutral'` | Declara o significado da cor. |
267
+ | `variant` | `'subtle' \| 'outline'` | `'subtle'` | Usa preenchimento tonal ou acrescenta borda. |
268
+ | `className` | `string` | | Ajusta a moldura sem substituir a escala. |
244
269
  | `asChild` | `boolean` | `false` | Cede o elemento para uma marca com visual próprio — um orbe, um logotipo — que ocupa o slot sem ganhar a moldura por cima. |
245
270
 
246
271
  `ContentMedia` já é a moldura. Passe só o glifo e escolha `size`, `context` e `variant` no slot. Um
@@ -9,7 +9,14 @@ validação, use [`Field`](/ui/field).
9
9
  label="Estágio"
10
10
  value={
11
11
  <DictionaryValue
12
- dict={{ keys: ['prospect', 'customer'], entries: { prospect: { label: 'Prospecto' }, customer: { label: 'Cliente', context: 'success' } }, presentation: 'stage' }}
12
+ dict={{
13
+ keys: ["prospect", "customer"],
14
+ entries: {
15
+ prospect: { label: "Prospecto" },
16
+ customer: { label: "Cliente", context: "success" },
17
+ },
18
+ presentation: "stage",
19
+ }}
13
20
  value="prospect"
14
21
  />
15
22
  }
@@ -39,12 +46,14 @@ React substitui a apresentação. `0` e `false` seguem como valores. A regra é
39
46
 
40
47
  ## Moldura e divisórias internas
41
48
 
42
- `variant="framed"` adiciona a borda externa sem preencher o fundo; na orientação horizontal, só a
43
- coluna de rótulos recebe um fundo sutil. `dividers` desenha apenas as
44
- divisórias internas; as duas opções são independentes e podem ser combinadas. `orientation`
45
- define se a chave fica sobre o valor ou ao lado dele. Na orientação horizontal, todos os valores
46
- começam depois da mesma coluna de rótulo, com largura padrão de `7rem` em grupos simples e
47
- `8.5rem` na moldura horizontal. Quando a superfície exigir mais espaço para os rótulos, ajuste a variável no grupo, por exemplo com
49
+ `variant="framed"` adiciona somente a borda externa, sem preencher o fundo. `dividers` desenha as
50
+ divisórias internas; na orientação horizontal, também forma a grade tabular com fundo sutil e
51
+ padding próprio na coluna de rótulos. As duas opções são independentes e podem ser combinadas.
52
+ `orientation` define se a chave fica sobre o valor ou ao lado dele.
53
+
54
+ Na orientação horizontal, todos os valores começam depois da mesma coluna de rótulo, com largura
55
+ padrão de `7rem` em grupos simples e `8.5rem` quando `dividers` está ativo. Quando a superfície
56
+ exigir mais espaço para os rótulos, ajuste a variável no grupo, por exemplo com
48
57
  `className="[--detail-label-width:9rem]"`.
49
58
 
50
59
  ```tsx preview col
@@ -62,24 +71,24 @@ começam depois da mesma coluna de rótulo, com largura padrão de `7rem` em gru
62
71
 
63
72
  ## Propriedades de DetailGroup
64
73
 
65
- | Propriedade | Tipo | Padrão | Descrição |
66
- |---|---|---|---|
67
- | `variant` | `'plain' \| 'framed'` | `'plain'` | `framed` aplica a moldura canônica ao conjunto, com fundo transparente; na orientação horizontal, a coluna de rótulos recebe fundo sutil. |
68
- | `dividers` | `boolean` | `false` | Linhas finas somente entre os campos, sem exigir moldura externa. |
69
- | `columns` | `1 \| 2 \| 3 \| 4 \| 'auto'` | `1` | Número fixo de colunas ou distribuição automática por largura mínima. |
70
- | `orientation` | `'vertical' \| 'horizontal'` | `'vertical'` | Chave sobre o valor ou ao lado dele em cada campo. |
74
+ | Propriedade | Tipo | Padrão | Descrição |
75
+ | ------------- | ---------------------------- | ------------ | --------------------------------------------------------------------------------------------------------- |
76
+ | `variant` | `'plain' \| 'framed'` | `'plain'` | `framed` aplica somente a moldura canônica ao conjunto, com fundo transparente. |
77
+ | `dividers` | `boolean` | `false` | Linhas finas entre os campos; na orientação horizontal, aplica fundo sutil e padding próprio aos rótulos. |
78
+ | `columns` | `1 \| 2 \| 3 \| 4 \| 'auto'` | `1` | Número fixo de colunas ou distribuição automática por largura mínima. |
79
+ | `orientation` | `'vertical' \| 'horizontal'` | `'vertical'` | Chave sobre o valor ou ao lado dele em cada campo. |
71
80
 
72
81
  O grupo renderiza uma lista de definições (`<dl>`); os demais atributos, como `className`, vão para
73
82
  ela.
74
83
 
75
84
  ## Propriedades de DetailField
76
85
 
77
- | Propriedade | Tipo | Padrão | Descrição |
78
- |---|---|---|---|
79
- | `label` | `ReactNode` | obrigatório | A chave do par. |
80
- | `value` | `ReactNode` | obrigatório | O valor; `null`, `undefined` e string vazia renderizam a ausência, `0` e `false` seguem como valores. |
81
- | `icon` | `ReactNode` | | Ícone decorativo antes do par chave/valor. |
82
- | `empty` | `ReactNode` | `“Não informado”` | Uma string dá significado acessível ao travessão; um nó próprio substitui a apresentação. |
86
+ | Propriedade | Tipo | Padrão | Descrição |
87
+ | ----------- | ----------- | ----------------- | ----------------------------------------------------------------------------------------------------- |
88
+ | `label` | `ReactNode` | obrigatório | A chave do par. |
89
+ | `value` | `ReactNode` | obrigatório | O valor; `null`, `undefined` e string vazia renderizam a ausência, `0` e `false` seguem como valores. |
90
+ | `icon` | `ReactNode` | | Ícone decorativo antes do par chave/valor. |
91
+ | `empty` | `ReactNode` | `“Não informado”` | Uma string dá significado acessível ao travessão; um nó próprio substitui a apresentação. |
83
92
 
84
93
  Os demais atributos, como `className`, vão para o contêiner do par. `DetailField` não aceita
85
94
  `children`: o conteúdo entra por `value`.
@@ -5,6 +5,10 @@ tela ao fundo. Para conteúdo curto e centralizado, prefira [`Dialog`](/ui/dialo
5
5
  `side="right"`, o painel entra pela direita e pode ser fechado por Esc, pelo overlay ou pelo botão
6
6
  de fechamento.
7
7
 
8
+ A moldura fica `0.25rem` afastada da viewport e usa borda completa, fundo base e raio `xl`, o mesmo
9
+ tratamento das superfícies estruturais do shell. O recorte mantém as faixas internas dentro dos
10
+ cantos, em qualquer valor de `side`.
11
+
8
12
  ```tsx preview
9
13
  <Drawer>
10
14
  <DrawerTrigger asChild>
@@ -125,7 +129,9 @@ em que o painel permanece aberto e troca de etapa.
125
129
  </DrawerActions>
126
130
  </DrawerHeader>
127
131
  <DrawerBody>
128
- <p className="text-sm text-muted-foreground">Histórico de passagens na oficina.</p>
132
+ <p className="text-sm text-muted-foreground">
133
+ Histórico de passagens na oficina.
134
+ </p>
129
135
  </DrawerBody>
130
136
  </DrawerContent>
131
137
  </Drawer>
@@ -162,12 +168,12 @@ de continuar, use [`Dialog mode="alert"`](/ui/dialog), que não fecha pelo cliqu
162
168
 
163
169
  ## Propriedades de Drawer
164
170
 
165
- | Propriedade | Tipo | Padrão | Descrição |
166
- | -------------- | ------------------------- | ------- | ---------------------------------------------------------------------------- |
167
- | `open` | `boolean` | | Estado no modo controlado. |
168
- | `defaultOpen` | `boolean` | `false` | Abertura inicial no modo não controlado. |
169
- | `onOpenChange` | `(open: boolean) => void` | | Recebe as mudanças de abertura, inclusive Esc, overlay e botão de fechar. |
170
- | `modal` | `boolean` | `true` | Mantém foco e interação restritos ao painel aberto e exibe o overlay. |
171
+ | Propriedade | Tipo | Padrão | Descrição |
172
+ | -------------- | ------------------------- | ------- | ------------------------------------------------------------------------- |
173
+ | `open` | `boolean` | | Estado no modo controlado. |
174
+ | `defaultOpen` | `boolean` | `false` | Abertura inicial no modo não controlado. |
175
+ | `onOpenChange` | `(open: boolean) => void` | | Recebe as mudanças de abertura, inclusive Esc, overlay e botão de fechar. |
176
+ | `modal` | `boolean` | `true` | Mantém foco e interação restritos ao painel aberto e exibe o overlay. |
171
177
 
172
178
  ## Propriedades de DrawerTrigger
173
179
 
@@ -178,61 +184,61 @@ de continuar, use [`Dialog mode="alert"`](/ui/dialog), que não fecha pelo cliqu
178
184
 
179
185
  ## Propriedades de DrawerClose
180
186
 
181
- | Propriedade | Tipo | Padrão | Descrição |
182
- | ----------- | ----------- | ------- | ----------------------------------------------------------- |
183
- | `asChild` | `boolean` | `false` | Aplica o fechamento ao filho; use com `Button`. |
184
- | `children` | `ReactNode` | | Controle que fecha o painel, como o `Cancelar` do rodapé. |
187
+ | Propriedade | Tipo | Padrão | Descrição |
188
+ | ----------- | ----------- | ------- | --------------------------------------------------------- |
189
+ | `asChild` | `boolean` | `false` | Aplica o fechamento ao filho; use com `Button`. |
190
+ | `children` | `ReactNode` | | Controle que fecha o painel, como o `Cancelar` do rodapé. |
185
191
 
186
192
  ## Propriedades de DrawerContent
187
193
 
188
- | Propriedade | Tipo | Padrão | Descrição |
189
- | ----------------- | ---------------------------------------- | --------- | ------------------------------------------------------------------------------------------ |
190
- | `side` | `'top' \| 'right' \| 'bottom' \| 'left'` | `'right'` | Borda de onde o painel aparece. |
191
- | `layout` | `'continuous' \| 'sectioned'` | `'sectioned'` | Anatomia da superfície inteira; os slots leem esse valor e não o recebem. |
192
- | `showCloseButton` | `boolean` | `true` | Inclui o botão de fechar no cabeçalho. Sem ele, Esc e o overlay continuam fechando o painel. |
193
- | `closeDisabled` | `boolean` | `false` | Mantém o botão de fechar visível e desabilitado e impede que Esc e o clique no overlay fechem o painel. |
194
- | `closeSize` | `"xs" \| "sm"` | `"sm"` | Define o tamanho da ação circular de fechar. |
195
- | `className` | `string` | | Ajusta o painel, como a largura. |
196
- | `children` | `ReactNode` | | Cabeçalho, corpo e rodapé. |
194
+ | Propriedade | Tipo | Padrão | Descrição |
195
+ | ----------------- | ---------------------------------------- | ------------- | ------------------------------------------------------------------------------------------------------- |
196
+ | `side` | `'top' \| 'right' \| 'bottom' \| 'left'` | `'right'` | Borda de onde o painel aparece. |
197
+ | `layout` | `'continuous' \| 'sectioned'` | `'sectioned'` | Anatomia da superfície inteira; os slots leem esse valor e não o recebem. |
198
+ | `showCloseButton` | `boolean` | `true` | Inclui o botão de fechar no cabeçalho. Sem ele, Esc e o overlay continuam fechando o painel. |
199
+ | `closeDisabled` | `boolean` | `false` | Mantém o botão de fechar visível e desabilitado e impede que Esc e o clique no overlay fechem o painel. |
200
+ | `closeSize` | `"xs" \| "sm"` | `"sm"` | Define o tamanho da ação circular de fechar. |
201
+ | `className` | `string` | | Ajusta o painel, como a largura. |
202
+ | `children` | `ReactNode` | | Cabeçalho, corpo e rodapé. |
197
203
 
198
204
  ## Propriedades de DrawerHeader
199
205
 
200
- | Propriedade | Tipo | Padrão | Descrição |
201
- | ----------- | ----------- | ------ | ------------------------------------------------------------------------------------------ |
202
- | `className` | `string` | | Ajusta a faixa superior sobre o recuo do layout. |
206
+ | Propriedade | Tipo | Padrão | Descrição |
207
+ | ----------- | ----------- | ------ | ----------------------------------------------------------------------------------------------------------------------------------------- |
208
+ | `className` | `string` | | Ajusta a faixa superior sobre o recuo do layout. |
203
209
  | `children` | `ReactNode` | | Somente `DrawerNavigation`, `DrawerMedia`, `DrawerTitle` e `DrawerActions`, no máximo um de cada; o fechamento padrão entra depois deles. |
204
210
 
205
211
  ## Propriedades de DrawerMedia
206
212
 
207
- | Propriedade | Tipo | Padrão | Descrição |
208
- | ----------- | ------------------------------------------------------------------------ | ----------- | ------------------------------------------------------------- |
209
- | `size` | `'xs' \| 'sm' \| 'default' \| 'lg'` | `'sm'` | Tamanho da moldura e do glifo na escala compartilhada. |
210
- | `context` | `'neutral' \| 'primary' \| 'info' \| 'success' \| 'warning' \| 'danger'` | `'neutral'` | Declara o significado da cor. |
211
- | `variant` | `'subtle' \| 'outline'` | `'subtle'` | Usa preenchimento tonal ou acrescenta borda. |
212
- | `className` | `string` | | Ajusta a moldura sem substituir a escala. |
213
- | `asChild` | `boolean` | `false` | Cede o elemento para uma marca com visual próprio — um orbe, um logotipo — que ocupa o slot sem ganhar a moldura por cima. |
213
+ | Propriedade | Tipo | Padrão | Descrição |
214
+ | ----------- | ------------------------------------------------------------------------ | ----------- | -------------------------------------------------------------------------------------------------------------------------- |
215
+ | `size` | `'xs' \| 'sm' \| 'default' \| 'lg'` | `'sm'` | Tamanho da moldura e do glifo na escala compartilhada. |
216
+ | `context` | `'neutral' \| 'primary' \| 'info' \| 'success' \| 'warning' \| 'danger'` | `'neutral'` | Declara o significado da cor. |
217
+ | `variant` | `'subtle' \| 'outline'` | `'subtle'` | Usa preenchimento tonal ou acrescenta borda. |
218
+ | `className` | `string` | | Ajusta a moldura sem substituir a escala. |
219
+ | `asChild` | `boolean` | `false` | Cede o elemento para uma marca com visual próprio — um orbe, um logotipo — que ocupa o slot sem ganhar a moldura por cima. |
214
220
 
215
221
  ## Propriedades de DrawerNavigation
216
222
 
217
- | Propriedade | Tipo | Padrão | Descrição |
218
- | ----------- | ----------- | ------ | ----------------------------------------------------- |
219
- | `className` | `string` | | Ajusta a região introdutória da linha. |
220
- | `children` | `ReactNode` | | Retorno de um fluxo encadeado, antes do título. |
223
+ | Propriedade | Tipo | Padrão | Descrição |
224
+ | ----------- | ----------- | ------ | ----------------------------------------------- |
225
+ | `className` | `string` | | Ajusta a região introdutória da linha. |
226
+ | `children` | `ReactNode` | | Retorno de um fluxo encadeado, antes do título. |
221
227
 
222
228
  ## Propriedades de DrawerActions
223
229
 
224
- | Propriedade | Tipo | Padrão | Descrição |
225
- | ----------- | ----------- | ------ | -------------------------------------------------------- |
226
- | `className` | `string` | | Ajusta o agrupamento das ações. |
227
- | `children` | `ReactNode` | | Ações da tela no cabeçalho, antes do botão de fechar. |
230
+ | Propriedade | Tipo | Padrão | Descrição |
231
+ | ----------- | ----------- | ------ | ----------------------------------------------------- |
232
+ | `className` | `string` | | Ajusta o agrupamento das ações. |
233
+ | `children` | `ReactNode` | | Ações da tela no cabeçalho, antes do botão de fechar. |
228
234
 
229
235
  ## Propriedades de DrawerTitle
230
236
 
231
- | Propriedade | Tipo | Padrão | Descrição |
232
- | ----------- | ----------- | ------ | ------------------------------------------------------------------- |
233
- | `level` | `1 \| 2 \| 3 \| 4 \| 5 \| 6` | `h2` da primitiva | Hierarquia do documento. O tamanho vem do `layout`, nunca do nível. |
234
- | `className` | `string` | | Ajusta o título, que trunca quando não cabe na linha. |
235
- | `children` | `ReactNode` | | Nome do recurso ou da tarefa; nomeia a superfície para leitores de tela. |
237
+ | Propriedade | Tipo | Padrão | Descrição |
238
+ | ----------- | ---------------------------- | ----------------- | ------------------------------------------------------------------------ |
239
+ | `level` | `1 \| 2 \| 3 \| 4 \| 5 \| 6` | `h2` da primitiva | Hierarquia do documento. O tamanho vem do `layout`, nunca do nível. |
240
+ | `className` | `string` | | Ajusta o título, que trunca quando não cabe na linha. |
241
+ | `children` | `ReactNode` | | Nome do recurso ou da tarefa; nomeia a superfície para leitores de tela. |
236
242
 
237
243
  ## Propriedades de DrawerBody
238
244
 
@@ -242,7 +248,7 @@ do corpo como texto ou `Alert`.
242
248
 
243
249
  ## Propriedades de DrawerFooter
244
250
 
245
- | Propriedade | Tipo | Padrão | Descrição |
246
- | ----------- | ----------- | ------ | ---------------------------------------------------------------------- |
247
- | `className` | `string` | | Ajusta a faixa do rodapé, inclusive a distribuição das ações. |
248
- | `children` | `ReactNode` | | Ações persistentes, normalmente dentro de um `ButtonGroup`. |
251
+ | Propriedade | Tipo | Padrão | Descrição |
252
+ | ----------- | ----------- | ------ | ------------------------------------------------------------- |
253
+ | `className` | `string` | | Ajusta a faixa do rodapé, inclusive a distribuição das ações. |
254
+ | `children` | `ReactNode` | | Ações persistentes, normalmente dentro de um `ButtonGroup`. |
@@ -28,7 +28,7 @@ senha. Diferentemente de `icon`, essa região pode ser interativa.
28
28
 
29
29
  ```tsx preview col md
30
30
  function Demo() {
31
- const [q, setQ] = useState('preview pipeline')
31
+ const [q, setQ] = useState("preview pipeline");
32
32
  return (
33
33
  <Input
34
34
  icon={<Search />}
@@ -36,15 +36,20 @@ function Demo() {
36
36
  onChange={(e) => setQ(e.target.value)}
37
37
  trailing={
38
38
  q ? (
39
- <Button variant="ghost" size="icon-xs" aria-label="Limpar busca" onClick={() => setQ('')}>
39
+ <Button
40
+ variant="ghost"
41
+ size="icon-xs"
42
+ aria-label="Limpar busca"
43
+ onClick={() => setQ("")}
44
+ >
40
45
  <X />
41
46
  </Button>
42
47
  ) : undefined
43
48
  }
44
49
  />
45
- )
50
+ );
46
51
  }
47
- render(<Demo />)
52
+ render(<Demo />);
48
53
  ```
49
54
 
50
55
  Para combinar mais de um adorno, use `InputGroup`.
@@ -85,11 +90,11 @@ aplica o tratamento visual correspondente.
85
90
 
86
91
  Além das props abaixo, `Input` aceita os atributos nativos de `<input>`.
87
92
 
88
- | Propriedade | Tipo | Padrão | Descrição |
89
- |---|---|---|---|
90
- | `icon` | `ReactNode` | | Ícone decorativo no início do campo. |
91
- | `trailing` | `ReactNode` | | Ação interativa no fim do campo. |
92
- | `type` | `string` | | Tipo nativo do campo, como `text`, `email`, `password` ou `number`. |
93
+ | Propriedade | Tipo | Padrão | Descrição |
94
+ | ----------- | ----------- | ------ | ------------------------------------------------------------------- |
95
+ | `icon` | `ReactNode` | | Ícone decorativo no início do campo. |
96
+ | `trailing` | `ReactNode` | | Ação interativa no fim do campo. |
97
+ | `type` | `string` | | Tipo nativo do campo, como `text`, `email`, `password` ou `number`. |
93
98
 
94
99
  ## InputGroup
95
100
 
@@ -104,10 +109,14 @@ dos botões, transfere o foco para o campo, seja `InputGroupInput` ou `InputGrou
104
109
 
105
110
  ```tsx preview col
106
111
  <InputGroup>
107
- <InputGroupAddon><Search /></InputGroupAddon>
112
+ <InputGroupAddon>
113
+ <Search />
114
+ </InputGroupAddon>
108
115
  <InputGroupInput placeholder="Buscar agente" defaultValue="reviewer" />
109
116
  <InputGroupAddon align="inline-end">
110
- <InputGroupButton size="icon-xs" aria-label="Limpar filtro"><X /></InputGroupButton>
117
+ <InputGroupButton size="icon-xs" aria-label="Limpar filtro">
118
+ <X />
119
+ </InputGroupButton>
111
120
  </InputGroupAddon>
112
121
  </InputGroup>
113
122
  ```
@@ -123,7 +132,9 @@ dos botões, transfere o foco para o campo, seja `InputGroupInput` ou `InputGrou
123
132
  <InputGroupText>github.com/softize/</InputGroupText>
124
133
  </InputGroupAddon>
125
134
  <InputGroupInput placeholder="empresa-x-api" />
126
- <InputGroupAddon align="inline-end"><InputGroupText>.git</InputGroupText></InputGroupAddon>
135
+ <InputGroupAddon align="inline-end">
136
+ <InputGroupText>.git</InputGroupText>
137
+ </InputGroupAddon>
127
138
  </InputGroup>
128
139
  ```
129
140
 
@@ -133,9 +144,14 @@ Com `InputGroupTextarea`, um addon em `block-end` forma uma região de ações a
133
144
 
134
145
  ```tsx preview col
135
146
  <InputGroup>
136
- <InputGroupTextarea placeholder="Descreva a tarefa para o agente developer" rows={3} />
147
+ <InputGroupTextarea
148
+ placeholder="Descreva a tarefa para o agente developer"
149
+ rows={3}
150
+ />
137
151
  <InputGroupAddon align="block-end">
138
- <InputGroupText><Sparkles /> Título gerado pela IA</InputGroupText>
152
+ <InputGroupText>
153
+ <Sparkles /> Título gerado pela IA
154
+ </InputGroupText>
139
155
  <InputGroupButton
140
156
  size="sm"
141
157
  context="primary"
@@ -169,39 +185,39 @@ controle ativo, declare `data-disabled="true"` no `InputGroup`.
169
185
 
170
186
  ### Propriedades de InputGroup
171
187
 
172
- | Propriedade | Tipo | Padrão | Descrição |
173
- |---|---|---|---|
174
- | `shape` | `'default' \| 'pill'` | `'default'` | Geometria da moldura compartilhada. |
175
- | `data-disabled` | `'true' \| 'false'` | | Com `true`, esmaece os addons mesmo com o controle ativo. Com o controle desabilitado, os addons já esmaecem sem ele. |
188
+ | Propriedade | Tipo | Padrão | Descrição |
189
+ | --------------- | --------------------- | ----------- | --------------------------------------------------------------------------------------------------------------------- |
190
+ | `shape` | `'default' \| 'pill'` | `'default'` | Geometria da moldura compartilhada. |
191
+ | `data-disabled` | `'true' \| 'false'` | | Com `true`, esmaece os addons mesmo com o controle ativo. Com o controle desabilitado, os addons já esmaecem sem ele. |
176
192
 
177
193
  ### Propriedades de InputGroupAddon
178
194
 
179
- | Propriedade | Tipo | Padrão | Descrição |
180
- |---|---|---|---|
181
- | `align` | `'inline-start' \| 'inline-end' \| 'block-start' \| 'block-end'` | `'inline-start'` | Posição do addon nas laterais ou acima/abaixo do controle. |
195
+ | Propriedade | Tipo | Padrão | Descrição |
196
+ | ----------- | ---------------------------------------------------------------- | ---------------- | ---------------------------------------------------------- |
197
+ | `align` | `'inline-start' \| 'inline-end' \| 'block-start' \| 'block-end'` | `'inline-start'` | Posição do addon nas laterais ou acima/abaixo do controle. |
182
198
 
183
199
  ### Propriedades de InputGroupButton
184
200
 
185
- | Propriedade | Tipo | Padrão | Descrição |
186
- |---|---|---|---|
187
- | `size` | `'xs' \| 'sm' \| 'icon-xs' \| 'icon-sm'` | `'xs'` | O subconjunto da escala única que cabe em um campo (1.5 · 2 · 1.5 · 1.75rem); os `icon-*` são quadrados. |
188
- | `context` | `'neutral' \| 'primary' \| 'danger'` | `'neutral'` | Contexto semântico herdado de Button. Com `variant` `solid` ou `subtle` sem contexto declarado, o padrão passa a `'primary'`. |
189
- | `variant` | `'solid' \| 'subtle' \| 'outline' \| 'ghost' \| 'link'` | `'ghost'` | Tratamento visual; use `solid` quando a ação precisar de ênfase. |
201
+ | Propriedade | Tipo | Padrão | Descrição |
202
+ | ----------- | ------------------------------------------------------- | ----------- | ----------------------------------------------------------------------------------------------------------------------------- |
203
+ | `size` | `'xs' \| 'sm' \| 'icon-xs' \| 'icon-sm'` | `'xs'` | O subconjunto da escala única que cabe em um campo (1.5 · 2 · 1.5 · 1.75rem); os `icon-*` são quadrados. |
204
+ | `context` | `'neutral' \| 'primary' \| 'warning' \| 'danger'` | `'neutral'` | Contexto semântico herdado de Button. Com `variant` `solid` ou `subtle` sem contexto declarado, o padrão passa a `'primary'`. |
205
+ | `variant` | `'solid' \| 'subtle' \| 'outline' \| 'ghost' \| 'link'` | `'ghost'` | Tratamento visual; use `solid` quando a ação precisar de ênfase. |
190
206
 
191
207
  ### Propriedades de InputGroupInput
192
208
 
193
- | Propriedade | Tipo | Padrão | Descrição |
194
- |---|---|---|---|
195
- | `value` / `defaultValue` | `string` | | Valor controlado ou inicial do `<input>`. |
196
- | `placeholder` | `string` | | Exemplo ou formato esperado quando o campo está vazio. |
209
+ | Propriedade | Tipo | Padrão | Descrição |
210
+ | ------------------------ | -------- | ------ | ------------------------------------------------------ |
211
+ | `value` / `defaultValue` | `string` | | Valor controlado ou inicial do `<input>`. |
212
+ | `placeholder` | `string` | | Exemplo ou formato esperado quando o campo está vazio. |
197
213
 
198
214
  ### Propriedades de InputGroupTextarea
199
215
 
200
- | Propriedade | Tipo | Padrão | Descrição |
201
- |---|---|---|---|
202
- | `value` / `defaultValue` | `string` | | Valor controlado ou inicial do `<textarea>`. |
203
- | `placeholder` | `string` | | Exemplo ou orientação exibida quando o campo está vazio. |
204
- | `rows` | `number` | | Número inicial de linhas visíveis. |
216
+ | Propriedade | Tipo | Padrão | Descrição |
217
+ | ------------------------ | -------- | ------ | -------------------------------------------------------- |
218
+ | `value` / `defaultValue` | `string` | | Valor controlado ou inicial do `<textarea>`. |
219
+ | `placeholder` | `string` | | Exemplo ou orientação exibida quando o campo está vazio. |
220
+ | `rows` | `number` | | Número inicial de linhas visíveis. |
205
221
 
206
222
  ### Propriedades de InputGroupText
207
223