@softize/opus 14.0.0 → 15.0.1

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 (32) hide show
  1. package/CHANGELOG.md +95 -0
  2. package/bin/cli.mjs +2 -0
  3. package/bin/lib/check.mjs +44 -6
  4. package/bin/lib/cli-shared.mjs +30 -1
  5. package/bin/lib/copy.mjs +3 -0
  6. package/bin/lib/db.mjs +2 -0
  7. package/docs/adr/0004-page-content-state-is-composed.md +46 -5
  8. package/docs/adr/0005-structural-surfaces-share-an-explicit-anatomy.md +9 -3
  9. package/docs/adr/0009-page-title-does-not-carry-a-counter.md +57 -0
  10. package/docs/adr/0010-page-header-owns-page-chrome.md +73 -0
  11. package/docs/data-layer.md +9 -0
  12. package/package.json +1 -1
  13. package/registry/skills/build-opus-ui/SKILL.md +3 -2
  14. package/registry/skills/build-opus-ui/references/ui-patterns.md +18 -6
  15. package/src/ui/components/patterns/list.tsx +67 -26
  16. package/src/ui/components/patterns/page-state.tsx +48 -6
  17. package/src/ui/components/patterns/page.tsx +224 -55
  18. package/src/ui/components/patterns/state-surface.tsx +137 -23
  19. package/src/ui/components/patterns/surface-header.tsx +110 -17
  20. package/src/ui/components/patterns/trigger.tsx +7 -6
  21. package/src/ui/components/primitives/button-group.tsx +34 -8
  22. package/src/ui/components/primitives/control.ts +12 -3
  23. package/src/ui/docs/content/action-list-dialog.md +1 -1
  24. package/src/ui/docs/content/action-list.md +34 -3
  25. package/src/ui/docs/content/action-trigger.md +4 -3
  26. package/src/ui/docs/content/alert.md +16 -4
  27. package/src/ui/docs/content/button.md +20 -5
  28. package/src/ui/docs/content/content.md +3 -3
  29. package/src/ui/docs/content/data-state.md +4 -4
  30. package/src/ui/docs/content/page.md +160 -44
  31. package/src/ui/meta.ts +6 -6
  32. package/src/ui/react.tsx +8 -2
@@ -37,8 +37,9 @@ confirm: {
37
37
 
38
38
  ## Ação somente com ícone
39
39
 
40
- Com `icon`, o botão exibe somente o ícone no quadrado `icon-sm` da escala (1.75rem, a ação que mora
41
- dentro de uma linha ou card) e usa `label`, ou `action.label`, no tooltip e no nome acessível. O clique
40
+ Com `icon`, o botão exibe somente o ícone no quadrado `icon-xs` da escala (1.5rem, a ação que mora
41
+ dentro de uma linha ou card) e usa `label`, ou `action.label`, no tooltip e no nome acessível. Uma
42
+ composição que peça mais presença, como a barra do `PageHeader`, declara `size="icon-sm"`. O clique
42
43
  não aciona o item clicável ao redor. `itemLabel` identifica o registro na mensagem de confirmação.
43
44
 
44
45
  ```tsx
@@ -83,4 +84,4 @@ um atalho, um arrastar, um item de menu.
83
84
  | `onSuccess` | `(data: TData) => void` | | Pós-sucesso (cache já invalidado pelo action.invalidates). |
84
85
  | `icon` | `React.ReactNode` | | Torna o botão icon-only: rótulo no tooltip e no `aria-label`, clique que não vaza para o item. |
85
86
  | `itemLabel` | `string` | | Nome do alvo na pergunta (sai entre aspas, em destaque, antes da mensagem do contrato). |
86
- | `className` | `string` | | Classes do botão. O tamanho vem de `size` (escala única); com `icon` é sempre `icon-sm`. |
87
+ | `className` | `string` | | Classes do botão. O tamanho vem de `size` (escala única); com `icon`, o default é `icon-xs`. |
@@ -54,6 +54,11 @@ Quando a mensagem precisa de conteúdo rico, componha os slots da família. `Ale
54
54
  `AlertDescription` pertencem ao header. As ações ficam no fim lógico da superfície e centralizadas
55
55
  verticalmente na mesma linha do conteúdo — a mesma posição usada pelas ações do Toast.
56
56
 
57
+ Use `ghost` como tratamento padrão para ações dentro do alert: a mensagem já fornece a superfície e
58
+ o botão não precisa desenhar outra moldura. Mantenha texto quando a ação expressa um resultado
59
+ específico. Para tentar novamente, recarregar ou repetir a operação descrita pelo aviso, prefira um
60
+ botão só com ícone, nome acessível e tooltip.
61
+
57
62
  ```tsx preview col
58
63
  <Alert context="danger">
59
64
  <AlertMedia>
@@ -67,9 +72,16 @@ verticalmente na mesma linha do conteúdo — a mesma posição usada pelas aç
67
72
  </AlertDescription>
68
73
  </AlertHeader>
69
74
  <AlertActions>
70
- <Button size="sm">
71
- Tentar novamente
72
- </Button>
75
+ <TooltipProvider>
76
+ <Tooltip>
77
+ <TooltipTrigger asChild>
78
+ <Button variant="ghost" size="icon" aria-label="Tentar novamente">
79
+ <RefreshCw />
80
+ </Button>
81
+ </TooltipTrigger>
82
+ <TooltipContent>Tentar novamente</TooltipContent>
83
+ </Tooltip>
84
+ </TooltipProvider>
73
85
  </AlertActions>
74
86
  </Alert>
75
87
  ```
@@ -83,7 +95,7 @@ ação.
83
95
  title="Sessão presa"
84
96
  description="O ambiente não subiu no tempo esperado."
85
97
  >
86
- <Button size="sm">
98
+ <Button variant="ghost">
87
99
  Reiniciar
88
100
  </Button>
89
101
  </Alert>
@@ -27,8 +27,8 @@ há texto visível. O glifo dentro do controle acompanha o tamanho (0.875rem em
27
27
  | `sm` | 2rem | Toolbar e cabeçalho densos, ao lado de `Select` e `Tabs` `sm`. |
28
28
  | `default` | 2.25rem | A linha padrão, a mesma de `Input`. |
29
29
  | `lg` | 2.5rem | Chamada principal com mais área de toque. |
30
- | `icon-xs` | 1.5rem | Ação só de ícone dentro de um campo, como o `trailing` de Input ou Select. |
31
- | `icon-sm` | 1.75rem | Ação só de ícone dentro de uma linha ou card; é o quadrado de `ActionTrigger` com `icon` e das setas do pager de `ActionList`. |
30
+ | `icon-xs` | 1.5rem | Ação só de ícone dentro de um campo ou de uma linha densa; é o quadrado de `ActionTrigger` com `icon`. |
31
+ | `icon-sm` | 1.75rem | Ação só de ícone em composições compactas que precisam de mais presença; também é o quadrado das setas do pager de `ActionList`. |
32
32
  | `icon` | 2.25rem | Ação só de ícone na linha padrão. |
33
33
  | `icon-lg` | 2.5rem | Ação só de ícone ao lado de um `lg`. |
34
34
 
@@ -80,9 +80,9 @@ buttonVariants serve para o caso sem filho único.
80
80
 
81
81
  ## ButtonGroup
82
82
 
83
- Use `ButtonGroup` quando ações relacionadas precisarem formar um bloco contínuo. As bordas internas
84
- colapsam e somente as pontas externas permanecem arredondadas. Mantenha a mesma variante nos filhos
85
- para preservar a unidade visual.
83
+ Use `ButtonGroup` para manter ações relacionadas juntas. No modo `connected`, que permanece como
84
+ padrão, as bordas internas colapsam e somente as pontas externas ficam arredondadas. Mantenha a
85
+ mesma variante nos filhos para preservar a unidade visual.
86
86
 
87
87
  ```tsx preview
88
88
  <ButtonGroup>
@@ -92,6 +92,20 @@ para preservar a unidade visual.
92
92
  </ButtonGroup>
93
93
  ```
94
94
 
95
+ ### Ações espaçadas
96
+
97
+ Use `mode="spaced"` quando os controles pertencem ao mesmo conjunto, mas cada um precisa preservar
98
+ sua própria forma e superfície de hover. O grupo aplica o intervalo compacto de `0.25rem` sem
99
+ conectar bordas. Esse modo atende ações icon-only em barras e linhas de listagem.
100
+
101
+ ```tsx preview
102
+ <ButtonGroup mode="spaced">
103
+ <Button variant="ghost" size="icon" aria-label="Recarregar"><RotateCw /></Button>
104
+ <Button variant="ghost" size="icon" aria-label="Exibição"><SlidersHorizontal /></Button>
105
+ <Button context="primary" size="icon" aria-label="Novo item"><Plus /></Button>
106
+ </ButtonGroup>
107
+ ```
108
+
95
109
  ### Ação dividida
96
110
 
97
111
  Combine a ação principal, um separador e um botão de ícone quando o mesmo comando oferecer
@@ -139,6 +153,7 @@ semântica de outro elemento, como `label`.
139
153
  | Propriedade | Tipo | Padrão | Descrição |
140
154
  |---|---|---|---|
141
155
  | `orientation` | `'horizontal' \| 'vertical'` | `'horizontal'` | Direção do bloco e do colapso das bordas. |
156
+ | `mode` | `'connected' \| 'spaced'` | `'connected'` | Conecta as bordas dos controles ou preserva cada controle com intervalo compacto. |
142
157
  | `shape` | `'default' \| 'pill'` | `'default'` | Geometria das extremidades externas do grupo. |
143
158
 
144
159
  ### Propriedades de ButtonGroupSeparator
@@ -22,8 +22,8 @@ render(
22
22
 
23
23
  Use os slots quando o header precisar de composição própria. A árvore aceita exatamente um
24
24
  `ContentHeader` e um `ContentBody` como filhos diretos. O header exige um `ContentTitle` e aceita
25
- uma descrição, um contador (`ContentMeta`) e uma região de ações a mesma anatomia de `PageHeader`,
26
- com os mesmos slots e o mesmo layout; só o nível do heading e a hierarquia visual mudam.
25
+ uma descrição, um contador (`ContentMeta`) e uma região de ações. O contador é próprio de
26
+ `Content`; `PageHeader` reconhece somente título, descrição e ações.
27
27
 
28
28
  ```tsx preview col
29
29
  render(
@@ -49,7 +49,7 @@ do pai correto, filhos estruturais indiretos e a mistura de shorthand com compos
49
49
  | Propriedade | Tipo | Padrão | Descrição |
50
50
  |---|---|---|---|
51
51
  | `title` | `ReactNode` | | Forma curta: título da região (vira o heading ligado à `section`). |
52
- | `count` | `number` | | Forma curta: total de itens ao lado do título o mesmo `count` de `Page`. |
52
+ | `count` | `number` | | Forma curta: total de itens ao lado do título da região. |
53
53
  | `description` | `ReactNode` | | Forma curta: frase de apoio sob o título. |
54
54
  | `actions` | `ReactNode` | | Forma curta: ações alinhadas à direita do header. |
55
55
  | `level` | `1 \| 2 \| 3 \| 4 \| 5 \| 6` | herdado | Nível semântico do heading, independente do destaque visual. |
@@ -4,8 +4,8 @@ Use `DataState` para apresentar carregamento, erro, vazio e conteúdo de uma mes
4
4
  superfícies são as mesmas de `PageState`, na escala de uma seção: o carregamento é um contêiner
5
5
  `role="status"` com o `Spinner`; o vazio compõe `Empty` com moldura sólida e `emptyMessage` como
6
6
  título; o erro é um `Alert` de contexto `danger` com uma mensagem segura, sem expor detalhes
7
- técnicos, e o botão de recuperação quando há `onRetry`. Para uma ação em andamento depois do
8
- clique, use `busy` em `Button`.
7
+ técnicos, e uma ação `ghost` com ícone quando há `onRetry`. `retryLabel` fornece o nome acessível
8
+ e o tooltip dessa ação. Para uma ação em andamento depois do clique, use `busy` em `Button`.
9
9
 
10
10
  ```tsx preview col
11
11
  <div className="w-full space-y-3">
@@ -48,6 +48,6 @@ disponível para criação ou vínculo, use `Empty` diretamente, com a moldura t
48
48
  | `emptyMessage` | `string` | `'Nada por aqui.'` | Frase do vazio (ex.: "Nenhum papel."). |
49
49
  | `error` | `{ message?: string } \| null` | | Erro da carga — aviso calmo. A mensagem técnica não vai para tela (use `errorMessage`). |
50
50
  | `errorMessage` | `string` | `'Não foi possível carregar.'` | Título do aviso de erro, orientado à pessoa. |
51
- | `onRetry` | `() => void \| Promise<void>` | | Recuperação: mostra o botão de tentar de novo no estado de erro. |
52
- | `retryLabel` | `string` | `'Tentar de novo'` | Rótulo do botão de recuperação. |
51
+ | `onRetry` | `() => void \| Promise<void>` | | Recuperação: mostra a ação de tentar de novo somente com ícone no estado de erro. |
52
+ | `retryLabel` | `string` | `'Tentar de novo'` | Nome acessível e tooltip da ação de recuperação. |
53
53
  | `colSpan` | `number` | | Em tabela: renderiza o estado como `<tr><td colSpan>` (cabe direto no tbody). |
@@ -1,22 +1,22 @@
1
1
  ## Esqueleto de página
2
2
 
3
- Use `Page` para manter título, contexto, ações e conteúdo no mesmo ritmo visual nas telas do
4
- back-office. Em larguras amplas, as ações ficam no extremo oposto e acompanham a base do conjunto
5
- formado pelo título e pela descrição; em larguras estreitas, passam para uma linha abaixo do
6
- contexto. O container é centralizado e ocupa a largura disponível até `80rem` (`max-w-7xl`). Use
7
- `className` somente quando a composição pedir explicitamente outro teto ou largura total. A área
8
- abaixo do cabeçalho permanece livre para tabelas, cards ou outras composições.
3
+ Use `Page` para manter navegação contextual, título, ações e conteúdo na mesma anatomia. O
4
+ `PageHeader` padrão acompanha o conteúdo dentro do container; `variant="bar"` transforma o mesmo
5
+ cabeçalho em uma faixa compacta no topo. Não monte um chrome paralelo para repetir essas regiões.
6
+
7
+ Em larguras amplas, as ações ficam no extremo oposto e acompanham a base do título e da descrição;
8
+ em larguras estreitas, passam para uma linha abaixo. O container é centralizado e ocupa a largura
9
+ disponível até `80rem` (`max-w-7xl`). Use `className` somente quando a composição pedir outro teto
10
+ ou largura total.
9
11
 
10
12
  A forma curta é o padrão para páginas comuns. Ela cria internamente `PageHeader` e `PageBody`;
11
13
  portanto, não produz uma estrutura visual ou semântica diferente da forma explícita. O cabeçalho é a
12
- mesma anatomia de `Content` (título, contador, descrição e ações): o que muda entre os dois é o nível
13
- do heading e a hierarquia visual.
14
+ mesma base estrutural de `Content`, mas reconhece somente título, descrição e ações. Contadores e
15
+ outros indicadores pertencem ao conteúdo que os explica.
14
16
 
15
- `Page` é o esqueleto de páginas e recursos delimitados. Ele também pode ocupar o painel principal
16
- de um shell com sidebar; a navegação lateral não exige remover o teto nem reconstruir o cabeçalho.
17
- Uma navegação contextual para outra página pode ocupar `actions`, e tabs ficam reservados a
17
+ `Page` também pode ocupar o painel principal de um shell com sidebar. Tabs ficam reservados a
18
18
  recortes da mesma superfície. Canvas e outros workspaces espaciais imersivos podem usar um shell
19
- próprio quando o cabeçalho reduzir a área útil ou duplicar controles persistentes da superfície.
19
+ próprio quando o cabeçalho reduzir a área útil ou duplicar controles persistentes.
20
20
 
21
21
  Estados integrais de carregamento, falha ou ausência são compostos no body com `PageState`,
22
22
  detalhado abaixo. `Page` não recebe flags de dados: uma página pode agregar fontes independentes e
@@ -27,7 +27,6 @@ render(
27
27
  <div className="w-full overflow-hidden rounded-lg border border-border">
28
28
  <Page
29
29
  title="Workspaces"
30
- count={3}
31
30
  description="Ambientes compartilhados pela equipe."
32
31
  actions={
33
32
  <Button>
@@ -40,16 +39,58 @@ render(
40
39
  </div>
41
40
  </Page>
42
41
  </div>,
43
- )
42
+ );
44
43
  ```
45
44
 
46
- ## Ações no chrome do shell
45
+ ## Retorno para a página pai
46
+
47
+ Use `PageBack` em uma subpágina simples. O destino é explícito para continuar correto após refresh ou
48
+ acesso por link direto; não derive esse retorno do histórico do navegador. No header padrão, o
49
+ controle aparece acima do título com ícone e rótulo.
47
50
 
48
- Quando o shell reserva uma barra própria para contexto e ações, envolva sua região de conteúdo com
49
- `PageActionsTarget` e passe o elemento de destino em `target`. As ações declaradas em `Page`
50
- continuam pertencendo semanticamente ao cabeçalho da página, mas são projetadas nesse elemento.
51
- Com `target={null}`, elas permanecem na posição padrão; isso permite montar o alvo por `ref` sem
52
- uma renderização intermediária inconsistente.
51
+ ```tsx preview col
52
+ <Page>
53
+ <PageHeader>
54
+ <PageBack href="/customers">Clientes</PageBack>
55
+ <PageTitle>Qualidade da base</PageTitle>
56
+ <PageDescription>Revise conflitos e canais de contato.</PageDescription>
57
+ </PageHeader>
58
+ <PageBody>Conteúdo da análise.</PageBody>
59
+ </Page>
60
+ ```
61
+
62
+ Não combine `PageBack` com breadcrumb. Use o retorno para um único pai conhecido. Quando houver
63
+ mais de um ancestral relevante, envolva o `Breadcrumb` em `PageNavigation`; ele ocupa a mesma
64
+ posição introdutória sem transformar a trilha em ação.
65
+
66
+ ## Cabeçalho em barra
67
+
68
+ Use `variant="bar"` quando título, retorno e ações precisarem formar uma faixa compacta e persistente
69
+ no topo da página. `Page` estende a borda por toda a largura e mantém o conteúdo da barra alinhado ao
70
+ mesmo teto do body. Nesse modo, `PageBack` vira icon-only e recebe tooltip e nome acessível “Voltar
71
+ para {destino}”. Mantenha também as ações compactas: use `sm` em botões com texto e `icon-sm` em
72
+ botões que exibem somente um ícone.
73
+
74
+ ```tsx preview col
75
+ <Page className="max-w-none">
76
+ <PageHeader variant="bar">
77
+ <PageBack href="/customers">Clientes</PageBack>
78
+ <PageTitle>Qualidade da base</PageTitle>
79
+ <PageActions>
80
+ <Button variant="ghost" size="icon-sm" aria-label="Mais ações">
81
+ <Ellipsis />
82
+ </Button>
83
+ </PageActions>
84
+ </PageHeader>
85
+ <PageBody>Conteúdo da análise.</PageBody>
86
+ </Page>
87
+ ```
88
+
89
+ Uma página comum não ganha a barra apenas por estar dentro de um shell. Escolha essa variante quando
90
+ a faixa acrescentar contexto ou ações persistentes; sem isso, mantenha o header padrão.
91
+
92
+ `PageActionsTarget` continua disponível para um workspace imersivo que já possua um chrome próprio.
93
+ Ele projeta somente `PageActions` no elemento informado; não cria uma segunda região de cabeçalho.
53
94
 
54
95
  ## Composição explícita
55
96
 
@@ -61,9 +102,12 @@ render(
61
102
  <Page>
62
103
  <PageHeader>
63
104
  <PageTitle>Workspaces</PageTitle>
64
- <PageMeta>3</PageMeta>
65
105
  <PageDescription>Ambientes compartilhados pela equipe.</PageDescription>
66
- <PageActions><Button><Plus /> Novo workspace</Button></PageActions>
106
+ <PageActions>
107
+ <Button>
108
+ <Plus /> Novo workspace
109
+ </Button>
110
+ </PageActions>
67
111
  </PageHeader>
68
112
  <PageBody>
69
113
  <div className="rounded-lg border border-dashed border-border p-10 text-center">
@@ -71,15 +115,19 @@ render(
71
115
  </div>
72
116
  </PageBody>
73
117
  </Page>,
74
- )
118
+ );
75
119
  ```
76
120
 
77
121
  ## Estados integrais
78
122
 
79
123
  Use `PageState` quando carregamento, falha ou ausência substituírem todo o conteúdo principal. Na
80
124
  forma curta ele pode ser escrito como filho direto de `Page`, que cria o `PageBody`; na forma
81
- explícita, coloque-o dentro de `PageBody`. O cabeçalho continua visível e o estado recebe composição,
82
- altura e semântica acessível consistentes.
125
+ explícita, coloque-o sozinho dentro de `PageBody`. Enquanto `status` for `loading`, `error` ou
126
+ `empty`, `Page` oculta o cabeçalho inteiro — incluindo o `PageBack` — e o estado ocupa a altura
127
+ disponível. Uma subpágina que dependa desse retorno oferece a saída pelo `action` do próprio
128
+ `PageState`. O título do estado assume o heading principal. Esse registro também funciona quando um
129
+ componente intermediário decide qual `PageState` renderizar. Em `ready`, o cabeçalho e o conteúdo
130
+ voltam à composição normal.
83
131
 
84
132
  ```tsx preview col
85
133
  <Page title="Relatório">
@@ -87,15 +135,18 @@ altura e semântica acessível consistentes.
87
135
  status="error"
88
136
  title="Não foi possível carregar o relatório"
89
137
  description="Tente novamente. Se o problema continuar, volte mais tarde."
90
- action={<Button>Tentar novamente</Button>}
138
+ onRetry={() => {}}
139
+ retryLabel="Tentar novamente"
91
140
  />
92
141
  </Page>
93
142
  ```
94
143
 
95
- `loading` centraliza o `Spinner` num contêiner `role="status"`; `error` compõe `Alert` com o botão
96
- de recuperação quando `onRetry`; `empty` compõe `Empty`; e `ready` entrega os filhos sem
97
- acrescentar uma superfície. São as mesmas superfícies de `DataState`, na escala da página: `title`
98
- e `description` nomeiam a situação e, sem `title`, valem `errorMessage` e `emptyMessage`.
144
+ `loading` centraliza o `Spinner` num contêiner `role="status"`; `error` usa a mesma anatomia visual
145
+ centralizada dos outros estados, conserva `role="alert"` e oferece uma ação `outline` textual quando
146
+ `onRetry`; `empty` centraliza `Empty` sem moldura; e `ready` entrega os filhos sem
147
+ acrescentar uma superfície. A moldura tracejada continua reservada ao `Empty` usado diretamente para
148
+ representar uma região disponível para criar ou vincular. `title` e `description` nomeiam a situação
149
+ e, sem `title`, valem `errorMessage` e `emptyMessage`.
99
150
 
100
151
  ```tsx preview col
101
152
  <Page title="Relatórios">
@@ -115,24 +166,89 @@ estado na própria seção com `DataState`, `ActionView`, `ActionList` ou `Alert
115
166
 
116
167
  | Propriedade | Tipo | Padrão | Descrição |
117
168
  | ------------- | ----------- | ----------- | ----------------------------------------------------------------------------------------------- |
118
- | `title` | `string` | | O h1 da página. |
119
- | `count` | `number` | | Total de itens ao lado do título (mono, esmaecido). |
169
+ | `title` | `ReactNode` | | O h1 da página. |
120
170
  | `description` | `ReactNode` | | Linha de contexto sob o título (ex.: "N no total · X ativos"). |
121
171
  | `actions` | `ReactNode` | | Ações contextuais no extremo oposto do cabeçalho; em telas estreitas, ficam abaixo do contexto. |
122
172
  | `className` | `string` | `max-w-7xl` | Classes do container para substituir o teto padrão de `80rem`. |
123
173
  | `children` | `ReactNode` | | O body da página — espaçamento e diagramação são seus. |
124
174
 
175
+ ## Propriedades de PageHeader
176
+
177
+ | Propriedade | Tipo | Padrão | Descrição |
178
+ | ----------- | ---------------------- | ----------- | ---------------------------------------------------------------- |
179
+ | `variant` | `'default' \| 'bar'` | `'default'` | Apresentação no container ou como faixa compacta no topo. |
180
+ | `className` | `string` | | Classes adicionais da região externa do cabeçalho. |
181
+ | `children` | `ReactNode` | | Um `PageTitle` e, opcionalmente, `PageBack` ou `PageNavigation`, descrição e ações. |
182
+
183
+ ## Propriedades de PageBack
184
+
185
+ | Propriedade | Tipo | Padrão | Descrição |
186
+ | ------------ | ---------------------------- | ------------------------- | ----------------------------------------------------------------------- |
187
+ | `href` | `string` | obrigatório | Destino explícito da página pai. Sem ele o retorno não é tabulável nem tem nome acessível. |
188
+ | `children` | `ReactNode` | | Nome visível do destino no header padrão e conteúdo do tooltip na barra. |
189
+ | `aria-label` | `string` | `Voltar para {children}` | Nome acessível; informe-o quando `children` não for texto simples. |
190
+ | `onClick` | `MouseEventHandler<HTMLAnchorElement>` | | Integração opcional com o roteador do consumidor, junto do `href`, nunca no lugar dele. |
191
+ | `className` | `string` | | Classes adicionais do link renderizado como botão `ghost`. |
192
+
193
+ ## Propriedades de PageNavigation
194
+
195
+ | Propriedade | Tipo | Descrição |
196
+ | ----------- | ----------------------------- | ----------------------------------------------- |
197
+ | `children` | `ReactNode` | Trilha estrutural, normalmente um `Breadcrumb`. |
198
+ | `className` | `string` | Classes adicionais do container introdutório. |
199
+ | demais | Atributos de `HTMLDivElement` | Atributos nativos repassados ao container. |
200
+
201
+ ## Propriedades de PageTitle
202
+
203
+ | Propriedade | Tipo | Descrição |
204
+ | ----------- | --------------------------------- | ------------------------------------------------------ |
205
+ | `children` | `ReactNode` | Título principal `h1`; compacto na variante `bar`. |
206
+ | `className` | `string` | Classes adicionais do título. |
207
+ | demais | Atributos de `HTMLHeadingElement` | Atributos nativos repassados ao heading. |
208
+
209
+ ## Propriedades de PageDescription
210
+
211
+ | Propriedade | Tipo | Descrição |
212
+ | ----------- | ----------------------------------- | ---------------------------------------- |
213
+ | `children` | `ReactNode` | Contexto apresentado abaixo do título. |
214
+ | `className` | `string` | Classes adicionais da descrição. |
215
+ | demais | Atributos de `HTMLParagraphElement` | Atributos nativos repassados ao parágrafo. |
216
+
217
+ ## Propriedades de PageActions
218
+
219
+ | Propriedade | Tipo | Descrição |
220
+ | ----------- | ------------------------------ | -------------------------------------------- |
221
+ | `children` | `ReactNode` | Ações no extremo oposto do cabeçalho. |
222
+ | `className` | `string` | Classes adicionais da região de ações. |
223
+ | demais | Atributos de `HTMLDivElement` | Atributos nativos repassados ao container. |
224
+
225
+ ## Propriedades de PageBody
226
+
227
+ | Propriedade | Tipo | Descrição |
228
+ | ----------- | ----------------------------- | ----------------------------------------------------- |
229
+ | `children` | `ReactNode` | Conteúdo principal; recebe o container na barra. |
230
+ | `className` | `string` | Classes adicionais da região principal. |
231
+ | demais | Atributos de `HTMLDivElement` | Atributos nativos repassados ao container. |
232
+
233
+ ## Propriedades de PageActionsTarget
234
+
235
+ | Propriedade | Tipo | Descrição |
236
+ | ----------- | -------------------- | ----------------------------------------------------------------------- |
237
+ | `target` | `HTMLElement \| null` | Destino externo das ações; `null` mantém as ações no header. |
238
+ | `children` | `ReactNode` | Árvore de página que poderá declarar `PageActions`. |
239
+
125
240
  ## Propriedades de PageState
126
241
 
127
- | Propriedade | Tipo | Padrão | Descrição |
128
- |---|---|---|---|
129
- | `status` | `'loading' \| 'error' \| 'empty' \| 'ready'` | | Estado integral do conteúdo. |
130
- | `title` | `ReactNode` | Texto seguro por estado | Situação reconhecível pela pessoa. |
131
- | `description` | `ReactNode` | | Impacto ou próximo passo aplicável. |
132
- | `icon` | `ReactNode` | Alerta no erro | Ícone decorativo do estado. |
133
- | `action` | `ReactNode` | | Seleção ou criação aplicável ao estado. |
134
- | `emptyMessage` | `string` | `'Nada por aqui'` | Título do vazio quando `title` não é informado. |
135
- | `errorMessage` | `string` | `'Não foi possível carregar esta página'` | Título do erro quando `title` não é informado. |
136
- | `onRetry` | `() => void \| Promise<void>` | | Recuperação do erro: acrescenta o botão de tentar de novo ao lado de `action`. |
137
- | `retryLabel` | `string` | `'Tentar de novo'` | Rótulo do botão de recuperação. |
138
- | `children` | `ReactNode` | | Conteúdo renderizado somente em `ready`. |
242
+ | Propriedade | Tipo | Padrão | Descrição |
243
+ | -------------- | -------------------------------------------- | ----------------------------------------- | ----------------------------------------------------------------------------------------------- |
244
+ | `status` | `'loading' \| 'error' \| 'empty' \| 'ready'` | | Estado integral do conteúdo. |
245
+ | `title` | `ReactNode` | Texto seguro por estado | Situação reconhecível pela pessoa. |
246
+ | `description` | `ReactNode` | | Impacto ou próximo passo aplicável. |
247
+ | `icon` | `ReactNode` | Alerta no erro | Ícone decorativo do estado. |
248
+ | `action` | `ReactNode` | | Seleção, criação ou saída aplicável ao estado — inclusive o retorno ao pai, já que o cabeçalho está oculto. |
249
+ | `emptyMessage` | `string` | `'Nada por aqui'` | Título do vazio quando `title` não é informado. |
250
+ | `errorMessage` | `string` | `'Não foi possível carregar esta página'` | Título do erro quando `title` não é informado. |
251
+ | `onRetry` | `() => void \| Promise<void>` | | Recuperação do erro: acrescenta um botão `outline` textual ao lado de `action`. |
252
+ | `retryLabel` | `string` | `'Tentar de novo'` | Texto do botão de recuperação. |
253
+ | `children` | `ReactNode` | | Conteúdo renderizado somente em `ready`. |
254
+ | `className` | `string` | | Classes da superfície de estado. |
package/src/ui/meta.ts CHANGED
@@ -27,7 +27,7 @@ export const componentMeta = {
27
27
  name: "alert",
28
28
  ancestry: "opus",
29
29
  whenToUse:
30
- "Aviso inline no fluxo da página — `context` declara neutral/info/success/warning/danger e `variant` escolhe subtle/outline (ADR 0006). Forma curta: `<Alert title description icon context />`; para conteúdo rico, componha AlertMedia + AlertHeader (AlertTitle e AlertDescription) + AlertActions. A mídia mantém uma moldura tonal quadrada, mesmo com descrição multilinha. O texto comunica o significado sem depender só da cor. Para interromper cobrando decisão, use `dialog.confirm()`; para recado passageiro, `toast`.",
30
+ "Aviso inline no fluxo da página — `context` declara neutral/info/success/warning/danger e `variant` escolhe subtle/outline (ADR 0006). Forma curta: `<Alert title description icon context />`; para conteúdo rico, componha AlertMedia + AlertHeader (AlertTitle e AlertDescription) + AlertActions. Ações usam Button ghost como ponto de partida; tentativas repetidas podem usar somente o ícone, com nome acessível e tooltip. A mídia mantém uma moldura tonal quadrada, mesmo com descrição multilinha. O texto comunica o significado sem depender só da cor. Para interromper cobrando decisão, use `dialog.confirm()`; para recado passageiro, `toast`.",
31
31
  },
32
32
  badge: {
33
33
  name: "badge",
@@ -69,7 +69,7 @@ export const componentMeta = {
69
69
  name: "button",
70
70
  ancestry: "shadcn",
71
71
  whenToUse:
72
- "Inicie uma ação com um controle clicável. Use `context` para o significado, `variant` para o tratamento visual e `size` para a escala compartilhada (`xs`…`lg` e os quadrados `icon-*`); `icon` recebe um nó e `busy` comunica o andamento e impede um novo acionamento. Para ações relacionadas, use ButtonGroup.",
72
+ "Inicie uma ação com um controle clicável. Use `context` para o significado, `variant` para o tratamento visual e `size` para a escala compartilhada (`xs`…`lg` e os quadrados `icon-*`); `icon` recebe um nó e `busy` comunica o andamento e impede um novo acionamento. Para ações relacionadas, use ButtonGroup conectado ou espaçado.",
73
73
  },
74
74
  card: {
75
75
  name: "card",
@@ -117,7 +117,7 @@ export const componentMeta = {
117
117
  name: "content-header",
118
118
  ancestry: "opus",
119
119
  whenToUse:
120
- "Estruture o cabeçalho de um Content com título, contador, descrição e ações — a mesma anatomia de PageHeader. No caso comum, declare esses valores diretamente em Content; componha ContentHeader apenas quando precisar controlar a anatomia.",
120
+ "Estruture uma região de conteúdo com título, contador, descrição e ações. No caso comum, declare esses valores diretamente em Content; componha ContentHeader apenas quando precisar controlar a anatomia. Contadores pertencem a Content e não ao título da Page.",
121
121
  },
122
122
  copyable: {
123
123
  name: "copyable",
@@ -129,7 +129,7 @@ export const componentMeta = {
129
129
  name: "dialog",
130
130
  ancestry: "opus",
131
131
  whenToUse:
132
- "Abra conteúdo ou uma tarefa em uma janela modal com foco contido. Use o modo padrão quando a superfície puder ser dispensada e `mode=\"alert\"` quando exigir resposta explícita. Para o caso imperativo comum, use `dialog.alert`, `dialog.confirm`, `dialog.prompt` ou `dialog.choose`. Distribua conteúdo próprio entre cabeçalho, corpo rolável e rodapé de ações.",
132
+ 'Abra conteúdo ou uma tarefa em uma janela modal com foco contido. Use o modo padrão quando a superfície puder ser dispensada e `mode="alert"` quando exigir resposta explícita. Para o caso imperativo comum, use `dialog.alert`, `dialog.confirm`, `dialog.prompt` ou `dialog.choose`. Distribua conteúdo próprio entre cabeçalho, corpo rolável e rodapé de ações.',
133
133
  },
134
134
  input: {
135
135
  name: "input",
@@ -183,7 +183,7 @@ export const componentMeta = {
183
183
  name: "spinner",
184
184
  ancestry: "shadcn",
185
185
  whenToUse:
186
- "Indique uma espera sem progresso determinado, como uma ação ou consulta em andamento. O ícone é decorativo: o contêiner (`role=\"status\"`) ou o texto ao lado nomeia a espera. Para reservar a forma do conteúdo, use Skeleton.",
186
+ 'Indique uma espera sem progresso determinado, como uma ação ou consulta em andamento. O ícone é decorativo: o contêiner (`role="status"`) ou o texto ao lado nomeia a espera. Para reservar a forma do conteúdo, use Skeleton.',
187
187
  },
188
188
  table: {
189
189
  name: "table",
@@ -400,7 +400,7 @@ export const componentMeta = {
400
400
  name: "page",
401
401
  ancestry: "opus",
402
402
  whenToUse:
403
- "O esqueleto de página do back-office: <main> + container centralizado com teto padrão de 80rem (`max-w-7xl`). O shorthand com title, description, count e actions cria a mesma anatomia de PageHeader(PageTitle/PageDescription/PageMeta/PageActions) + PageBody disponível na forma explícita. PageActionsTarget projeta as ações no chrome reservado pelo shell sem retirar sua declaração da Page. `className` substitui o teto quando a composição pede outra largura. Quando todo o body estiver carregando, falhar ou estiver vazio, use PageState. Para listagem em modal, ActionListDialog.",
403
+ "O esqueleto de página do back-office: <main> + container centralizado com teto padrão de 80rem (`max-w-7xl`). O shorthand cobre título, descrição e ações; a forma explícita acrescenta PageBack para retorno simples ou PageNavigation para uma trilha e permite `PageHeader variant=\"bar\"` quando a mesma anatomia precisar virar uma faixa compacta. No header padrão, PageBack fica acima do título; na barra, vira icon-only com tooltip. PageActionsTarget fica restrito a workspaces imersivos com chrome próprio. Quando todo o body estiver carregando, falhar ou estiver vazio, use PageState: ele oculta o header e ocupa a área disponível, centralizado e sem moldura. Para uma região disponível à criação ou vínculo, use Empty.",
404
404
  },
405
405
  router: {
406
406
  name: "router",
package/src/ui/react.tsx CHANGED
@@ -423,14 +423,20 @@ export type { DataStateProps } from "./components/patterns/data-state.tsx";
423
423
  export {
424
424
  Page,
425
425
  PageHeader,
426
+ PageNavigation,
427
+ PageBack,
426
428
  PageTitle,
427
429
  PageDescription,
428
- PageMeta,
429
430
  PageActions,
430
431
  PageActionsTarget,
431
432
  PageBody,
432
433
  } from "./components/patterns/page.tsx";
433
- export type { PageProps } from "./components/patterns/page.tsx";
434
+ export type {
435
+ PageProps,
436
+ PageBackProps,
437
+ PageHeaderProps,
438
+ PageHeaderVariant,
439
+ } from "./components/patterns/page.tsx";
434
440
 
435
441
  // Estado integral do conteúdo de Page (loading/error/empty/ready), sem acoplar Page a dados.
436
442
  export { PageState } from "./components/patterns/page-state.tsx";