@softize/opus 30.0.0 → 31.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 (64) hide show
  1. package/CHANGELOG.md +123 -0
  2. package/bin/lib/check.mjs +109 -101
  3. package/bin/lib/copy.mjs +2973 -1801
  4. package/docs/adr/0043-neutral-surfaces-and-interactions-use-opaque-role-tokens.md +52 -0
  5. package/docs/adr/0044-neutral-appearance-derives-from-bounded-axes-per-mode.md +27 -2
  6. package/docs/adr/0060-surface-composition-separates-chrome-and-intro.md +142 -0
  7. package/docs/adr/0064-action-list-com-itens-e-fontes-externas.md +47 -0
  8. package/docs/adr/0065-presentation-composes-settings-sections.md +295 -0
  9. package/docs/adr/0066-civil-date-input-and-calendar-list.md +28 -0
  10. package/docs/adr/README.md +6 -0
  11. package/package.json +1 -1
  12. package/registry/skills/build-opus-ui/SKILL.md +21 -19
  13. package/registry/skills/build-opus-ui/references/evaluations.md +13 -11
  14. package/registry/skills/build-opus-ui/references/ui-patterns.md +24 -27
  15. package/src/core/presentation.ts +938 -32
  16. package/src/core/types.ts +2 -0
  17. package/src/ui/components/patterns/form.tsx +22 -1
  18. package/src/ui/components/patterns/grouped-list.ts +2 -2
  19. package/src/ui/components/patterns/list-calendar.tsx +129 -0
  20. package/src/ui/components/patterns/list.tsx +612 -382
  21. package/src/ui/components/patterns/page-heading-context.tsx +12 -5
  22. package/src/ui/components/patterns/page.tsx +227 -197
  23. package/src/ui/components/patterns/presentation-fields.tsx +246 -0
  24. package/src/ui/components/patterns/presentation-sections.tsx +494 -0
  25. package/src/ui/components/patterns/presentation.tsx +1142 -229
  26. package/src/ui/components/patterns/structural-header.tsx +23 -32
  27. package/src/ui/components/patterns/surface-anatomy.ts +27 -217
  28. package/src/ui/components/patterns/surface.tsx +19 -29
  29. package/src/ui/components/patterns/trigger.tsx +10 -2
  30. package/src/ui/components/primitives/calendar.tsx +39 -18
  31. package/src/ui/components/primitives/close-button.tsx +11 -3
  32. package/src/ui/components/primitives/command.tsx +2 -8
  33. package/src/ui/components/primitives/date-input.tsx +276 -0
  34. package/src/ui/components/primitives/detail.tsx +1 -1
  35. package/src/ui/components/primitives/dialog.tsx +19 -81
  36. package/src/ui/components/primitives/drawer.tsx +17 -79
  37. package/src/ui/components/primitives/field.tsx +1 -1
  38. package/src/ui/components/primitives/pagination.tsx +3 -2
  39. package/src/ui/components/primitives/table.tsx +1 -1
  40. package/src/ui/components/primitives/tabs.tsx +13 -2
  41. package/src/ui/docs/content/action-form.md +6 -1
  42. package/src/ui/docs/content/action-list.md +156 -68
  43. package/src/ui/docs/content/action-trigger.md +5 -0
  44. package/src/ui/docs/content/button.md +5 -6
  45. package/src/ui/docs/content/calendar-month-view.md +50 -0
  46. package/src/ui/docs/content/calendar.md +6 -1
  47. package/src/ui/docs/content/command.md +62 -50
  48. package/src/ui/docs/content/compositions.md +129 -459
  49. package/src/ui/docs/content/date-input.md +67 -0
  50. package/src/ui/docs/content/dialog.md +44 -112
  51. package/src/ui/docs/content/drawer.md +44 -103
  52. package/src/ui/docs/content/field.md +2 -1
  53. package/src/ui/docs/content/input.md +3 -0
  54. package/src/ui/docs/content/page.md +204 -412
  55. package/src/ui/docs/content/presentation.md +371 -23
  56. package/src/ui/docs/content/separator.md +1 -1
  57. package/src/ui/docs/content/surface.md +65 -120
  58. package/src/ui/docs/content/tokens.md +18 -4
  59. package/src/ui/docs/registry.tsx +38 -9
  60. package/src/ui/drivers/context.tsx +11 -4
  61. package/src/ui/drivers/react.tsx +27 -7
  62. package/src/ui/meta.ts +17 -6
  63. package/src/ui/react.tsx +41 -8
  64. package/src/ui/theme.css +44 -33
@@ -0,0 +1,67 @@
1
+ ## Digitar ou escolher uma data
2
+
3
+ Use `DateInput` para preencher uma data civil, como uma entrega ou um feriado. O campo
4
+ exibe `DD/MM/AAAA` e abre o calendário em português ao clicar em qualquer parte do controle.
5
+ O clique mantém o foco na digitação. O ícone é decorativo e não adiciona uma parada de Tab;
6
+ o atalho `Alt` + seta para baixo leva o foco para o calendário.
7
+
8
+ ```tsx preview col md
9
+ function Demo() {
10
+ const [date, setDate] = useState("2026-11-02")
11
+ return (
12
+ <div className="grid gap-2">
13
+ <Label htmlFor="delivery-date">Data de entrega</Label>
14
+ <DateInput id="delivery-date" value={date} onValueChange={setDate} />
15
+ </div>
16
+ )
17
+ }
18
+ render(<Demo />)
19
+ ```
20
+
21
+ A máscara insere as barras durante a digitação: basta informar `02112026`. Também é possível
22
+ digitar `02/11/2026`, colar `2026-11-02` ou escolher o dia no
23
+ calendário. Uma data válida é emitida como `2026-11-02`; apagar o campo emite `''`. O componente
24
+ mantém o dia civil, sem transformá-lo em um instante UTC.
25
+
26
+ Texto incompleto ou uma data impossível permanecem no campo com a máscara, sem conversão para ISO.
27
+ Valide o valor antes de persistir: o componente não troca `31/02/2026` por um dia de março nem
28
+ preserva silenciosamente a data anterior. No `ActionForm`, o schema do contrato mantém essa
29
+ responsabilidade.
30
+
31
+ ## Formulário declarativo
32
+
33
+ Declare `widget: 'date'` no campo do contrato e use um schema de data civil. O
34
+ [`ActionForm`](/ui/action-form) compõe o `DateInput` com rótulo, hint, erro e foco de validação.
35
+
36
+ ```tsx
37
+ const fields = { date: { label: "Data", widget: "date" as const } }
38
+ const input = z.object({ date: z.string().date("Informe uma data válida.") })
39
+ ```
40
+
41
+ ## Teclado e estados
42
+
43
+ Com foco no campo, `Alt` + seta para baixo abre o calendário e leva o foco até ele. As setas navegam pelos dias;
44
+ selecionar uma data fecha o calendário e devolve o foco ao campo. `Escape` fecha o calendário
45
+ sem fechar o diálogo que o contém. É possível substituir trechos selecionados e apagar com
46
+ `Backspace` ou `Delete`, sem ficar preso às barras da máscara. `disabled` e `readOnly` impedem
47
+ a abertura pelo campo e pelo atalho.
48
+ Associe `Label.htmlFor` ao `id` e use `aria-describedby` para ajuda ou erro.
49
+
50
+ Para manter um mês inteiro visível, use [`Calendar`](/ui/calendar). Para um campo com estado
51
+ interno, forneça `defaultValue`; `value` e `onValueChange` tornam o componente controlado.
52
+
53
+ ## Propriedades de DateInput
54
+
55
+ | Propriedade | Tipo | Padrão | Efeito |
56
+ | --- | --- | --- | --- |
57
+ | `value` | `string` | — | Valor controlado: ISO quando válido, texto durante digitação inválida ou incompleta. |
58
+ | `defaultValue` | `string` | `''` | Valor inicial no modo não controlado; restaurado no reset do formulário nativo. |
59
+ | `onValueChange` | `(value: string) => void` | — | Recebe a data civil, o texto em edição ou `''`. |
60
+ | `name` | `string` | — | Envia o valor por um campo oculto no formulário nativo, sem converter para a apresentação brasileira. |
61
+ | `placeholder` | `string` | `DD/MM/AAAA` | Exemplo de formato no campo vazio. |
62
+ | `disabled`, `readOnly` | `boolean` | `false` | Impedem edição e abertura do calendário. |
63
+ | `id`, `ref`, `form`, `onBlur`, `aria-*` | Atributos do input | — | Identificação, foco, vínculo com formulário e descrição acessível do campo visível. |
64
+ | `className` | `string` | — | Classes da moldura do campo, seguindo o Input com adorno. |
65
+
66
+ O componente não aceita `type`, `onChange`, `icon`, `trailing`, `min`, `max` ou `step`.
67
+ O contrato define os limites de negócio; `onValueChange` substitui o evento de alteração nativo.
@@ -52,58 +52,19 @@ Seus filhos diretos recebem o ritmo estrutural de `1rem`. Um grupo compacto, uma
52
52
  linha declara a própria relação em um wrapper filho; `flush` fica reservado ao conteúdo que
53
53
  controla todo o inset.
54
54
  O backdrop escurece a página sem aplicar desfoque.
55
- O fechamento do cabeçalho usa uma ação circular neutra e sutil. `closeSize` escolhe entre `xs` e
56
- `sm`; o padrão é `sm`.
55
+ O fechamento do cabeçalho usa uma ação circular neutra e sutil. `closeSize` escolhe entre `xs`,
56
+ `sm` e `default`; o padrão é `xs` (`1,5rem`).
57
57
  O `ButtonGroup` preserva a largura natural das ações por padrão. Use `distribution="equal"`
58
58
  somente para decisões deliberadamente equivalentes. O `DialogFooter` organiza a faixa, mas não
59
59
  decide a distribuição nem a aparência dos botões.
60
60
  `DialogClose` encerra o modal sem exigir estado controlado. Use `open` e `onOpenChange` quando outra
61
61
  parte da interface também precisar controlar a abertura.
62
62
 
63
- ## Regiões separadas ou contínuas
63
+ ## Regiões com divisores automáticos
64
64
 
65
- `layout` declara a anatomia da superfície inteira e fica em `DialogContent`; os slots leem esse
66
- valor e não o recebem. O padrão é `sectioned`: as regiões têm o mesmo recuo, o rodapé ganha uma
67
- faixa sutil e as fronteiras entre regiões vizinhas ganham um divisor. É o modal de tarefa, com
68
- cabeçalho, conteúdo e ações claramente separados.
69
-
70
- Use `layout="continuous"` para uma superfície curta, em que o espaço basta para separar as regiões
71
- e a linha seria um ruído — um aviso de uma frase, uma escolha rápida.
72
-
73
- ```tsx preview
74
- <Dialog>
75
- <DialogTrigger asChild>
76
- <Button variant="outline">Publicar contrato</Button>
77
- </DialogTrigger>
78
- <DialogContent layout="continuous">
79
- <DialogHeader>
80
- <DialogTitle>Publicar contrato</DialogTitle>
81
- </DialogHeader>
82
- <DialogBody>
83
- <p className="text-sm text-muted-foreground">
84
- A versão publicada passa a valer para todos os consumidores.
85
- </p>
86
- </DialogBody>
87
- <DialogFooter>
88
- <ButtonGroup mode="spaced">
89
- <DialogClose asChild>
90
- <Button variant="ghost">Cancelar</Button>
91
- </DialogClose>
92
- <Button>Publicar</Button>
93
- </ButtonGroup>
94
- </DialogFooter>
95
- </DialogContent>
96
- </Dialog>
97
- ```
98
-
99
- Os divisores do modo seccionado são derivados da vizinhança: cada região desenha a linha quando há
100
- uma região do outro lado. Um cabeçalho sem corpo não fecha nada, e um cabeçalho seguido direto de um
101
- rodapé produz uma linha só. A tela não escreve `border-b` nem `border-t`.
102
-
103
- A faixa sutil do rodapé é a mesma no `Dialog` e no [`Drawer`](/ui/drawer): as duas famílias
104
- compartilham a anatomia, e um fluxo que troca de superfície não muda de aparência no meio.
105
-
106
- `mode="alert"` mantém a composição centrada da resposta obrigatória e não usa `layout`.
65
+ Cabeçalho, corpo e rodapé usam recuo de `1rem`. Os divisores dependem das regiões presentes:
66
+ um cabeçalho isolado não desenha linha; seguido diretamente pelo rodapé, produz uma linha só.
67
+ A tela não declara uma variante visual nem reconstrói bordas nos slots.
107
68
 
108
69
  ## Ações e navegação no cabeçalho
109
70
 
@@ -126,13 +87,13 @@ fluxo modal encadeado, em que a superfície permanece aberta e troca de etapa.
126
87
  <DialogContent>
127
88
  <DialogHeader>
128
89
  <DialogNavigation>
129
- <Button variant="ghost" size="icon-sm" aria-label="Voltar para a lista">
90
+ <Button variant="ghost" size="icon" aria-label="Voltar para a lista">
130
91
  <ArrowLeft />
131
92
  </Button>
132
93
  </DialogNavigation>
133
94
  <DialogTitle>Evento 4821</DialogTitle>
134
95
  <DialogActions>
135
- <Button variant="ghost" size="icon-sm" aria-label="Mais ações">
96
+ <Button variant="ghost" size="icon" aria-label="Mais ações">
136
97
  <Ellipsis />
137
98
  </Button>
138
99
  </DialogActions>
@@ -146,10 +107,10 @@ fluxo modal encadeado, em que a superfície permanece aberta e troca de etapa.
146
107
  </Dialog>
147
108
  ```
148
109
 
149
- O header compartilha a geometria de Page e Surface delimitada: padding de `1rem` e
150
- linha mínima de `2rem`, nos dois layouts. Declare `size="sm"` nos botões textuais e
151
- `size="icon-sm"` nos de ícone (`2rem`), incluindo o retorno. `CloseButton` já usa
152
- `icon-sm` por padrão. Conteúdo maior pode expandir a linha; rodapés preservam sua escala.
110
+ O header compartilha a geometria de Drawer e Surface delimitada: padding de `1rem` e
111
+ linha mínima de `2,25rem`, na anatomia única. Declare `size="default"` nos botões textuais e
112
+ `size="icon"` nos de ícone (`2,25rem`), incluindo o retorno. O fechamento nativo do modal
113
+ também usa essa escala por padrão. Conteúdo maior pode expandir a linha; rodapés preservam sua escala.
153
114
 
154
115
  O cabeçalho aceita `DialogDescription` como subheading opcional para orientar sobre a finalidade.
155
116
  Omita quando repetir o título. Condições, regras de negócio e consequências necessárias à decisão
@@ -159,7 +120,9 @@ pular o texto compromete a decisão, não sua extensão.
159
120
  ```tsx
160
121
  <DialogHeader>
161
122
  <DialogTitle>Organizar pasta</DialogTitle>
162
- <DialogDescription>Escolha onde a pasta e suas subpastas aparecem.</DialogDescription>
123
+ <DialogDescription>
124
+ Escolha onde a pasta e suas subpastas aparecem.
125
+ </DialogDescription>
163
126
  </DialogHeader>
164
127
  ```
165
128
 
@@ -469,20 +432,22 @@ reservado à orientação textual breve. Os itens quebram em várias linhas quan
469
432
  ```tsx
470
433
  <Dialog defaultOpen>
471
434
  <DialogContent>
472
- <DialogHeader />
435
+ <DialogHeader>
436
+ <DialogTitle>Manual de atendimento</DialogTitle>
437
+ <DialogDescription>Orientações para a equipe.</DialogDescription>
438
+ <DialogMeta>
439
+ <Badge>Publicado</Badge>
440
+ <span>Por Ana</span>
441
+ </DialogMeta>
442
+ </DialogHeader>
473
443
  <DialogBody>
474
- <DialogIntro>
475
- <DialogTitle>Manual de atendimento</DialogTitle>
476
- <DialogDescription>Orientações para a equipe.</DialogDescription>
477
- <DialogMeta><Badge>Publicado</Badge><span>Por Ana</span></DialogMeta>
478
- </DialogIntro>
479
444
  <p>Conteúdo do manual.</p>
480
445
  </DialogBody>
481
446
  </DialogContent>
482
447
  </Dialog>
483
448
  ```
484
449
 
485
- A composição aceita um único `DialogMeta` e exige um `DialogTitle`. Na forma explícita, coloque-o em `DialogIntro` ou no `DialogHeader` compacto. Não coloque o slot solto no corpo.
450
+ A composição aceita um único `DialogMeta` e exige um `DialogTitle`. Coloque-o em `DialogHeader`. Não coloque o slot solto no corpo.
486
451
 
487
452
  O modo `alert` conserva sua composição especializada e não recebe `DialogMeta`.
488
453
 
@@ -506,19 +471,19 @@ O modo `alert` conserva sua composição especializada e não recebe `DialogMeta
506
471
 
507
472
  ## Propriedades de DialogContent
508
473
 
509
- | Propriedade | Tipo | Padrão | Descrição |
510
- | ----------------- | ----------------------------- | ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
511
- | `showCloseButton` | `boolean` | `true` | No modo padrão, inclui a ação de fechamento no cabeçalho; o modo de alerta exige uma resposta identificável. |
512
- | `closeDisabled` | `boolean` | `false` | Mantém o botão de fechar visível e desabilitado e impede que Esc e o clique externo fechem a superfície. Handlers como `onEscapeKeyDown` e `onPointerDownOutside` continuam sendo chamados antes do bloqueio. |
513
- | `closeSize` | `"xs" \| "sm"` | `"sm"` | Define o tamanho da ação circular de fechar. |
514
- | `layout` | `'continuous' \| 'sectioned'` | `'sectioned'` | Anatomia da superfície inteira; os slots leem esse valor e não o recebem. Ignorado em `mode="alert"`. |
515
- | `className` | `string` | | Ajusta a superfície. A largura máxima é `32rem` no modo padrão e `20rem` no alerta; amplie o alerta com `max-w-lg` quando o rodapé tiver três ações. |
516
- | `children` | `ReactNode` | | Cabeçalho, corpo, rodapé ou conteúdo próprio. |
474
+ | Propriedade | Tipo | Padrão | Descrição |
475
+ | ----------------- | --------------------------- | ----------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
476
+ | `showCloseButton` | `boolean` | `true` | No modo padrão, inclui a ação de fechamento no cabeçalho; o modo de alerta exige uma resposta identificável. |
477
+ | `closeDisabled` | `boolean` | `false` | Mantém o botão de fechar visível e desabilitado e impede que Esc e o clique externo fechem a superfície. Handlers como `onEscapeKeyDown` e `onPointerDownOutside` continuam sendo chamados antes do bloqueio. |
478
+ | `closeSize` | `"xs" \| "sm" \| "default"` | `"xs"` | Define o tamanho da ação circular de fechar. |
479
+ | `className` | `string` | | Ajusta a superfície. A largura máxima é `32rem` no modo padrão e `20rem` no alerta; amplie o alerta com `max-w-lg` quando o rodapé tiver três ações. |
480
+ | `children` | `ReactNode` | | Cabeçalho, corpo, rodapé ou conteúdo próprio. |
517
481
 
518
482
  ## Propriedades de DialogHeader
519
483
 
520
484
  | Propriedade | Tipo | Padrão | Descrição |
521
485
  | ----------- | ----------- | ------ | ----------------------------------------------------------------------------------------------------------------------------------------- |
486
+ | `tabs` | `ReactNode` | | `TabsList` sob o título, controlado por um `Tabs` ancestral. Não disponível no modo alert. |
522
487
  | `className` | `string` | | Ajusta a faixa superior sobre o recuo do layout. |
523
488
  | `children` | `ReactNode` | | Somente `DialogNavigation`, `DialogMedia`, `DialogTitle` e `DialogActions`, no máximo um de cada; o fechamento padrão entra depois deles. |
524
489
 
@@ -644,63 +609,30 @@ imperativa.
644
609
  | `variant` | `ButtonVariant` | Última ação: `solid`; demais: `outline` | Define o tratamento visual. |
645
610
  | `disabled` | `boolean` | `false` | Impede a escolha desta ação. |
646
611
 
647
- ## Intro separada do chrome
648
-
649
- Quando o cabeçalho contém apenas navegação, ações globais e o fechamento, coloque o título do
650
- conteúdo no primeiro bloco de `DialogBody`. `DialogIntro` exige um `DialogTitle` e aceita um
651
- `DialogIntroActions`; o body continua responsável pelo espaço antes, entre e depois dos blocos.
652
-
653
- ```tsx
654
- <Dialog>
655
- <DialogContent>
656
- <DialogHeader>
657
- <DialogActions>
658
- <Button variant="ghost">Ajuda</Button>
659
- </DialogActions>
660
- </DialogHeader>
661
- <DialogBody>
662
- <DialogIntro>
663
- <DialogTitle>Editar evento</DialogTitle>
664
- <DialogIntroActions>
665
- <Button variant="outline">Revisar</Button>
666
- </DialogIntroActions>
667
- </DialogIntro>
668
- <form>…</form>
669
- </DialogBody>
670
- <DialogFooter>…</DialogFooter>
671
- </DialogContent>
672
- </Dialog>
673
- ```
674
-
675
- No formato compacto, mantenha `DialogTitle` e `DialogActions` no próprio `DialogHeader`. Para
676
- comparar as duas formas em cada `layout`, abra [Composições](/ui/compositions).
677
-
678
612
  ## Propriedades de DialogDescription
679
613
 
680
- | Propriedade | Tipo | Padrão | Descrição |
681
- | --- | --- | --- | --- |
682
- | `children` | `ReactNode` | | Orientação opcional sob o título em `DialogHeader` ou `DialogIntro`. |
683
- | `id` | `string` | | Identificador para associação acessível explícita. |
684
- | `className` | `string` | | Ajusta a apresentação do parágrafo. |
685
- | `…props` | `ComponentProps<"p">` | | Atributos nativos. |
614
+ | Propriedade | Tipo | Padrão | Descrição |
615
+ | ----------- | --------------------- | ------ | --------------------------------------------------- |
616
+ | `children` | `ReactNode` | | Orientação opcional sob o título em `DialogHeader`. |
617
+ | `id` | `string` | | Identificador para associação acessível explícita. |
618
+ | `className` | `string` | | Ajusta a apresentação do parágrafo. |
619
+ | `…props` | `ComponentProps<"p">` | | Atributos nativos. |
686
620
 
687
621
  ## Espaçamento do corpo
688
622
 
689
623
  O body separa os blocos diretos por `1rem`. Dialog e Drawer são superfícies delimitadas:
690
624
  o conteúdo mantém `1rem` até a borda inferior, mesmo sem uma propriedade `framed`.
691
- Em `sectioned`, o corpo tem `1rem` entre o conteúdo e cada divisória. Em `continuous`,
692
- o cabeçalho fornece o intervalo superior; sem cabeçalho, o próprio corpo abre esse recuo.
625
+ O corpo mantém `1rem` entre o conteúdo e cada divisória.
693
626
  Use `flush` quando o conteúdo controlar seus próprios recuos.
694
627
 
695
- Na intro, `DialogTitle` usa a mesma escala de `PageTitle` (`1.875rem`). No header
696
- compacto, o título conserva a escala de `1.125rem`. O nível semântico não altera essas medidas.
628
+ `DialogTitle` usa `1,125rem`, como PageTitle. O nível semântico não altera a escala visual.
697
629
 
698
630
  ## Propriedades de DialogMeta
699
631
 
700
- | Propriedade | Tipo | Descrição |
701
- | --- | --- | --- |
702
- | `children` | `ReactNode` | Badges, datas, autoria ou outros metadados do registro. |
703
- | `className` | `string` | Ajusta a faixa de metadados. |
632
+ | Propriedade | Tipo | Descrição |
633
+ | ----------- | ----------- | ------------------------------------------------------- |
634
+ | `children` | `ReactNode` | Badges, datas, autoria ou outros metadados do registro. |
635
+ | `className` | `string` | Ajusta a faixa de metadados. |
704
636
 
705
637
  Aceita atributos nativos de `div`. O intervalo superior é de 0,75rem; os itens têm
706
638
  0,75rem entre colunas e 0,5rem entre linhas. O componente não insere separadores nem
@@ -33,7 +33,7 @@ cantos, em qualquer valor de `side`.
33
33
  `side` aceita `top`, `right`, `bottom` e `left`. `DrawerFooter` mantém as ações no rodapé e
34
34
  `DrawerClose` fecha o painel sem exigir controle manual de estado. O corpo preserva o mesmo
35
35
  alinhamento horizontal do cabeçalho e do rodapé. O fechamento do cabeçalho usa uma ação circular
36
- neutra e sutil; `closeSize` escolhe entre `xs` e `sm`, com `sm` como padrão.
36
+ neutra e sutil; `closeSize` escolhe entre `xs`, `sm` e `default`, com `xs` como padrão.
37
37
 
38
38
  ```tsx preview
39
39
  <Drawer>
@@ -66,37 +66,11 @@ O rodapé usa a mesma faixa sutil do [`Dialog`](/ui/dialog). As duas famílias c
66
66
  anatomia, então um fluxo que começa em um modal e continua em um painel não muda de aparência no
67
67
  meio.
68
68
 
69
- ## Regiões separadas ou contínuas
69
+ ## Regiões com divisores automáticos
70
70
 
71
- `layout` declara a anatomia da superfície inteira e fica em `DrawerContent`; os slots leem esse
72
- valor e não o recebem. O padrão é `sectioned`: recuo igual nas três regiões, faixa no rodapé e
73
- divisor entre as regiões vizinhas. É o painel de trabalho, em que o corpo rola sob um cabeçalho e um
74
- rodapé fixos.
75
-
76
- Use `layout="continuous"` quando o painel apresentar um único bloco de leitura e a linha virar
77
- ruído.
78
-
79
- ```tsx preview
80
- <Drawer>
81
- <DrawerTrigger asChild>
82
- <Button variant="outline">Ver resumo</Button>
83
- </DrawerTrigger>
84
- <DrawerContent layout="continuous">
85
- <DrawerHeader>
86
- <DrawerTitle>Resumo da revisão</DrawerTitle>
87
- </DrawerHeader>
88
- <DrawerBody>
89
- <p className="text-sm text-muted-foreground">
90
- Concluída em 2 horas, sem pendências registradas.
91
- </p>
92
- </DrawerBody>
93
- </DrawerContent>
94
- </Drawer>
95
- ```
96
-
97
- Os divisores do modo seccionado são derivados da vizinhança: cada região desenha a linha quando há
98
- uma região do outro lado. Um cabeçalho sem corpo não fecha nada, e um cabeçalho seguido direto de um
99
- rodapé produz uma linha só. A tela não escreve `border-b` nem `border-t`.
71
+ Cabeçalho, corpo e rodapé usam recuo de `1rem`. Os divisores dependem das regiões presentes:
72
+ um cabeçalho isolado não desenha linha; seguido diretamente pelo rodapé, produz uma linha só.
73
+ A tela não declara uma variante visual nem reconstrói bordas nos slots.
100
74
 
101
75
  ## Mídia, ações e navegação no cabeçalho
102
76
 
@@ -119,7 +93,7 @@ retorno de um fluxo encadeado, em que o painel permanece aberto e troca de etapa
119
93
  <DrawerContent side="right">
120
94
  <DrawerHeader>
121
95
  <DrawerNavigation>
122
- <Button variant="ghost" size="icon-sm" aria-label="Voltar para a lista">
96
+ <Button variant="ghost" size="icon" aria-label="Voltar para a lista">
123
97
  <ArrowLeft />
124
98
  </Button>
125
99
  </DrawerNavigation>
@@ -130,7 +104,7 @@ retorno de um fluxo encadeado, em que o painel permanece aberto e troca de etapa
130
104
  </DrawerMedia>
131
105
  <DrawerTitle>ABC-1D23</DrawerTitle>
132
106
  <DrawerActions>
133
- <Button variant="ghost" size="icon-sm" aria-label="Mais ações">
107
+ <Button variant="ghost" size="icon" aria-label="Mais ações">
134
108
  <Ellipsis />
135
109
  </Button>
136
110
  </DrawerActions>
@@ -144,10 +118,10 @@ retorno de um fluxo encadeado, em que o painel permanece aberto e troca de etapa
144
118
  </Drawer>
145
119
  ```
146
120
 
147
- O header compartilha a geometria de Page e Surface delimitada: padding de `1rem` e
148
- linha mínima de `2rem`, nos dois layouts. Declare `size="sm"` nos botões textuais e
149
- `size="icon-sm"` nos de ícone (`2rem`), incluindo o retorno. `CloseButton` já usa
150
- `icon-sm` por padrão. Conteúdo maior pode expandir a linha; rodapés preservam sua escala.
121
+ O header compartilha a geometria de Dialog e Surface delimitada: padding de `1rem` e
122
+ linha mínima de `2,25rem`, na anatomia única. Declare `size="default"` nos botões textuais e
123
+ `size="icon"` nos de ícone (`2,25rem`), incluindo o retorno. O fechamento nativo do modal
124
+ também usa essa escala por padrão. Conteúdo maior pode expandir a linha; rodapés preservam sua escala.
151
125
 
152
126
  O cabeçalho aceita `DrawerDescription` como subheading opcional para orientar sobre a finalidade.
153
127
  Omita quando repetir o título. Condições, regras de negócio e consequências necessárias à decisão
@@ -157,7 +131,9 @@ pular o texto compromete a decisão, não sua extensão.
157
131
  ```tsx
158
132
  <DrawerHeader>
159
133
  <DrawerTitle>Organizar pasta</DrawerTitle>
160
- <DrawerDescription>Escolha onde a pasta e suas subpastas aparecem.</DrawerDescription>
134
+ <DrawerDescription>
135
+ Escolha onde a pasta e suas subpastas aparecem.
136
+ </DrawerDescription>
161
137
  </DrawerHeader>
162
138
  ```
163
139
 
@@ -199,20 +175,22 @@ reservado à orientação textual breve. Os itens quebram em várias linhas quan
199
175
  ```tsx
200
176
  <Drawer defaultOpen>
201
177
  <DrawerContent>
202
- <DrawerHeader />
178
+ <DrawerHeader>
179
+ <DrawerTitle>Manual de atendimento</DrawerTitle>
180
+ <DrawerDescription>Orientações para a equipe.</DrawerDescription>
181
+ <DrawerMeta>
182
+ <Badge>Publicado</Badge>
183
+ <span>Por Ana</span>
184
+ </DrawerMeta>
185
+ </DrawerHeader>
203
186
  <DrawerBody>
204
- <DrawerIntro>
205
- <DrawerTitle>Manual de atendimento</DrawerTitle>
206
- <DrawerDescription>Orientações para a equipe.</DrawerDescription>
207
- <DrawerMeta><Badge>Publicado</Badge><span>Por Ana</span></DrawerMeta>
208
- </DrawerIntro>
209
187
  <p>Conteúdo do manual.</p>
210
188
  </DrawerBody>
211
189
  </DrawerContent>
212
190
  </Drawer>
213
191
  ```
214
192
 
215
- A composição aceita um único `DrawerMeta` e exige um `DrawerTitle`. Na forma explícita, coloque-o em `DrawerIntro` ou no `DrawerHeader` compacto. Não coloque o slot solto no corpo.
193
+ A composição aceita um único `DrawerMeta` e exige um `DrawerTitle`. Coloque-o em `DrawerHeader`. Não coloque o slot solto no corpo.
216
194
 
217
195
  ## Propriedades de Drawer
218
196
 
@@ -239,20 +217,20 @@ A composição aceita um único `DrawerMeta` e exige um `DrawerTitle`. Na forma
239
217
 
240
218
  ## Propriedades de DrawerContent
241
219
 
242
- | Propriedade | Tipo | Padrão | Descrição |
243
- | ----------------- | ---------------------------------------- | ------------- | ------------------------------------------------------------------------------------------------------- |
244
- | `side` | `'top' \| 'right' \| 'bottom' \| 'left'` | `'right'` | Borda de onde o painel aparece. |
245
- | `layout` | `'continuous' \| 'sectioned'` | `'sectioned'` | Anatomia da superfície inteira; os slots leem esse valor e não o recebem. |
246
- | `showCloseButton` | `boolean` | `true` | Inclui o botão de fechar no cabeçalho. Sem ele, Esc e o overlay continuam fechando o painel. |
247
- | `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. |
248
- | `closeSize` | `"xs" \| "sm"` | `"sm"` | Define o tamanho da ação circular de fechar. |
249
- | `className` | `string` | | Ajusta o painel, como a largura. |
250
- | `children` | `ReactNode` | | Cabeçalho, corpo e rodapé. |
220
+ | Propriedade | Tipo | Padrão | Descrição |
221
+ | ----------------- | ---------------------------------------- | ----------- | ------------------------------------------------------------------------------------------------------- |
222
+ | `side` | `'top' \| 'right' \| 'bottom' \| 'left'` | `'right'` | Borda de onde o painel aparece. |
223
+ | `showCloseButton` | `boolean` | `true` | Inclui o botão de fechar no cabeçalho. Sem ele, Esc e o overlay continuam fechando o painel. |
224
+ | `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. |
225
+ | `closeSize` | `"xs" \| "sm" \| "default"` | `"xs"` | Define o tamanho da ação circular de fechar. |
226
+ | `className` | `string` | | Ajusta o painel, como a largura. |
227
+ | `children` | `ReactNode` | | Cabeçalho, corpo e rodapé. |
251
228
 
252
229
  ## Propriedades de DrawerHeader
253
230
 
254
231
  | Propriedade | Tipo | Padrão | Descrição |
255
232
  | ----------- | ----------- | ------ | ----------------------------------------------------------------------------------------------------------------------------------------- |
233
+ | `tabs` | `ReactNode` | | `TabsList` sob o título, controlado por um `Tabs` ancestral. |
256
234
  | `className` | `string` | | Ajusta a faixa superior sobre o recuo do layout. |
257
235
  | `children` | `ReactNode` | | Somente `DrawerNavigation`, `DrawerMedia`, `DrawerTitle` e `DrawerActions`, no máximo um de cada; o fechamento padrão entra depois deles. |
258
236
 
@@ -305,67 +283,30 @@ o conteúdo controlar o próprio inset e um wrapper filho para relações intern
305
283
  | `className` | `string` | | Ajusta a faixa do rodapé, inclusive a distribuição das ações. |
306
284
  | `children` | `ReactNode` | | Ações persistentes, normalmente dentro de um `ButtonGroup`. |
307
285
 
308
- ## Intro separada do chrome
309
-
310
- Quando o cabeçalho contém apenas o recolhimento, ações globais e o fechamento, use `DrawerIntro`
311
- como primeiro bloco de `DrawerBody`. Ele exige um `DrawerTitle` e aceita `DrawerIntroActions`.
312
- Assim o título acompanha o conteúdo rolável enquanto o chrome permanece estável.
313
-
314
- ```tsx
315
- <Drawer>
316
- <DrawerContent showCloseButton={false}>
317
- <DrawerHeader>
318
- <DrawerNavigation>
319
- <DrawerClose asChild>
320
- <Button>Recolher</Button>
321
- </DrawerClose>
322
- </DrawerNavigation>
323
- <DrawerActions>
324
- <Button variant="ghost">Conversa</Button>
325
- </DrawerActions>
326
- </DrawerHeader>
327
- <DrawerBody>
328
- <DrawerIntro>
329
- <DrawerTitle>Editar evento</DrawerTitle>
330
- <DrawerIntroActions>
331
- <Button variant="outline">Revisar</Button>
332
- </DrawerIntroActions>
333
- </DrawerIntro>
334
- <form>…</form>
335
- </DrawerBody>
336
- </DrawerContent>
337
- </Drawer>
338
- ```
339
-
340
- No formato compacto, mantenha `DrawerTitle` e `DrawerActions` no próprio `DrawerHeader`. Para
341
- comparar as duas formas em cada `layout`, abra [Composições](/ui/compositions).
342
-
343
286
  ## Propriedades de DrawerDescription
344
287
 
345
- | Propriedade | Tipo | Padrão | Descrição |
346
- | --- | --- | --- | --- |
347
- | `children` | `ReactNode` | | Orientação opcional sob o título em `DrawerHeader` ou `DrawerIntro`. |
348
- | `id` | `string` | | Identificador para associação acessível explícita. |
349
- | `className` | `string` | | Ajusta a apresentação do parágrafo. |
350
- | `…props` | `ComponentProps<"p">` | | Atributos nativos. |
288
+ | Propriedade | Tipo | Padrão | Descrição |
289
+ | ----------- | --------------------- | ------ | --------------------------------------------------- |
290
+ | `children` | `ReactNode` | | Orientação opcional sob o título em `DrawerHeader`. |
291
+ | `id` | `string` | | Identificador para associação acessível explícita. |
292
+ | `className` | `string` | | Ajusta a apresentação do parágrafo. |
293
+ | `…props` | `ComponentProps<"p">` | | Atributos nativos. |
351
294
 
352
295
  ## Espaçamento do corpo
353
296
 
354
297
  O body separa os blocos diretos por `1rem`. Dialog e Drawer são superfícies delimitadas:
355
298
  o conteúdo mantém `1rem` até a borda inferior, mesmo sem uma propriedade `framed`.
356
- Em `sectioned`, o corpo tem `1rem` entre o conteúdo e cada divisória. Em `continuous`,
357
- o cabeçalho fornece o intervalo superior; sem cabeçalho, o próprio corpo abre esse recuo.
299
+ O corpo mantém `1rem` entre o conteúdo e cada divisória.
358
300
  Use `flush` quando o conteúdo controlar seus próprios recuos.
359
301
 
360
- Na intro, `DrawerTitle` usa a mesma escala de `PageTitle` (`1.875rem`). No header
361
- compacto, o título conserva a escala de `1.125rem`. O nível semântico não altera essas medidas.
302
+ `DrawerTitle` usa `1,125rem`, como PageTitle. O nível semântico não altera a escala visual.
362
303
 
363
304
  ## Propriedades de DrawerMeta
364
305
 
365
- | Propriedade | Tipo | Descrição |
366
- | --- | --- | --- |
367
- | `children` | `ReactNode` | Badges, datas, autoria ou outros metadados do registro. |
368
- | `className` | `string` | Ajusta a faixa de metadados. |
306
+ | Propriedade | Tipo | Descrição |
307
+ | ----------- | ----------- | ------------------------------------------------------- |
308
+ | `children` | `ReactNode` | Badges, datas, autoria ou outros metadados do registro. |
309
+ | `className` | `string` | Ajusta a faixa de metadados. |
369
310
 
370
311
  Aceita atributos nativos de `div`. O intervalo superior é de 0,75rem; os itens têm
371
312
  0,75rem entre colunas e 0,5rem entre linhas. O componente não insere separadores nem
@@ -5,7 +5,8 @@ montado à mão. Quando o formulário executa uma action, prefira [`ActionForm`]
5
5
  monta os mesmos campos a partir do contrato. Na orientação vertical, `FieldLabel` e o controle ficam
6
6
  empilhados. A ajuda fica junto ao rótulo, com [`LabelHelp`](/ui/action-form), o mesmo ícone que o
7
7
  `ActionForm` usa para `FieldSpec.help`. Use `FieldDescription` somente quando a frase precisar
8
- ficar visível o tempo todo abaixo do controle.
8
+ ficar visível o tempo todo abaixo do controle. Essa orientação usa `text-xs` (`0,75rem`),
9
+ enquanto o rótulo mantém `text-sm`.
9
10
 
10
11
  ```tsx preview col md
11
12
  <Field>
@@ -70,6 +70,9 @@ Associe `htmlFor` no `Label` ao `id` do campo para que o clique no rótulo mova
70
70
  `type` é repassado ao `<input>` nativo, permitindo que o navegador escolha teclado e validação
71
71
  adequados.
72
72
 
73
+ Para datas com digitação em formato brasileiro e calendário do Opus, use
74
+ [`DateInput`](/ui/date-input).
75
+
73
76
  ```tsx preview col md
74
77
  <Input type="email" placeholder="Ex.: joao@softize.com.br" />
75
78
  <Input type="password" placeholder="Token de serviço" />