@softize/opus 18.1.0 → 18.1.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 (96) hide show
  1. package/CHANGELOG.md +58 -0
  2. package/PROMOTED.md +4 -5
  3. package/README.md +5 -4
  4. package/bin/cli.mjs +4 -0
  5. package/docs/adr/0004-page-content-state-is-composed.md +3 -0
  6. package/docs/adr/0005-structural-surfaces-share-an-explicit-anatomy.md +6 -2
  7. package/docs/adr/0011-page-shell-coordinates-persistent-page-chrome.md +6 -1
  8. package/docs/adr/0014-structural-headers-do-not-carry-description.md +2 -2
  9. package/docs/adr/0015-action-size-follows-interaction-density.md +4 -3
  10. package/docs/adr/{0012-modal-header-only-names-the-surface.md → 0018-modal-header-only-names-the-surface.md} +4 -1
  11. package/docs/adr/{0016-productive-surfaces-use-compact-density.md → 0019-productive-surfaces-use-compact-density.md} +4 -1
  12. package/docs/code-style.md +2 -2
  13. package/docs/consumer-upgrade-propagation.md +1 -1
  14. package/docs/data-products.md +5 -3
  15. package/docs/protocol.md +6 -6
  16. package/docs/releasing.md +28 -4
  17. package/package.json +1 -1
  18. package/registry/skills/build-opus-ui/references/ui-patterns.md +11 -1
  19. package/src/auth/drivers/jwt.ts +2 -1
  20. package/src/core/runtime.ts +25 -4
  21. package/src/core/types.ts +4 -4
  22. package/src/mcp/index.ts +9 -0
  23. package/src/ui/components/patterns/content-header.tsx +1 -1
  24. package/src/ui/components/patterns/form.tsx +1 -1
  25. package/src/ui/components/patterns/sidebar.tsx +1 -1
  26. package/src/ui/components/primitives/card.tsx +1 -1
  27. package/src/ui/components/primitives/detail.tsx +7 -7
  28. package/src/ui/components/primitives/radio-group.tsx +1 -1
  29. package/src/ui/components/primitives/select.tsx +1 -1
  30. package/src/ui/docs/content/action-form-dialog.md +11 -4
  31. package/src/ui/docs/content/action-form.md +7 -16
  32. package/src/ui/docs/content/action-list-dialog.md +4 -6
  33. package/src/ui/docs/content/action-list.md +46 -4
  34. package/src/ui/docs/content/action-trigger.md +9 -5
  35. package/src/ui/docs/content/action-view.md +12 -8
  36. package/src/ui/docs/content/actions.md +36 -13
  37. package/src/ui/docs/content/ai.md +26 -7
  38. package/src/ui/docs/content/alert.md +4 -3
  39. package/src/ui/docs/content/aspect-ratio.md +2 -2
  40. package/src/ui/docs/content/auth.md +25 -10
  41. package/src/ui/docs/content/avatar.md +1 -1
  42. package/src/ui/docs/content/badge.md +2 -2
  43. package/src/ui/docs/content/breadcrumb.md +3 -2
  44. package/src/ui/docs/content/button.md +31 -7
  45. package/src/ui/docs/content/calendar.md +1 -1
  46. package/src/ui/docs/content/card.md +1 -1
  47. package/src/ui/docs/content/carousel.md +14 -3
  48. package/src/ui/docs/content/chat.md +1 -1
  49. package/src/ui/docs/content/cli.md +13 -7
  50. package/src/ui/docs/content/command.md +34 -2
  51. package/src/ui/docs/content/composer.md +1 -1
  52. package/src/ui/docs/content/content.md +5 -4
  53. package/src/ui/docs/content/customization.md +1 -1
  54. package/src/ui/docs/content/cycle.md +7 -5
  55. package/src/ui/docs/content/data-state.md +6 -5
  56. package/src/ui/docs/content/data.md +3 -3
  57. package/src/ui/docs/content/detail.md +3 -2
  58. package/src/ui/docs/content/dialog.md +2 -2
  59. package/src/ui/docs/content/dictionary-value.md +1 -1
  60. package/src/ui/docs/content/dock.md +23 -2
  61. package/src/ui/docs/content/dot.md +0 -2
  62. package/src/ui/docs/content/drawer.md +1 -1
  63. package/src/ui/docs/content/empty.md +1 -4
  64. package/src/ui/docs/content/events.md +1 -1
  65. package/src/ui/docs/content/field.md +20 -11
  66. package/src/ui/docs/content/getting-started.md +4 -2
  67. package/src/ui/docs/content/icon-picker.md +2 -2
  68. package/src/ui/docs/content/input-otp.md +2 -0
  69. package/src/ui/docs/content/input.md +2 -3
  70. package/src/ui/docs/content/item.md +5 -4
  71. package/src/ui/docs/content/kbd.md +2 -1
  72. package/src/ui/docs/content/mcp.md +10 -4
  73. package/src/ui/docs/content/menu.md +27 -0
  74. package/src/ui/docs/content/page.md +19 -5
  75. package/src/ui/docs/content/pagination.md +9 -2
  76. package/src/ui/docs/content/popover.md +2 -2
  77. package/src/ui/docs/content/presentation.md +46 -45
  78. package/src/ui/docs/content/progress.md +2 -6
  79. package/src/ui/docs/content/runtime.md +8 -5
  80. package/src/ui/docs/content/scheduler.md +1 -1
  81. package/src/ui/docs/content/select.md +13 -8
  82. package/src/ui/docs/content/sidebar.md +3 -2
  83. package/src/ui/docs/content/skeleton.md +1 -1
  84. package/src/ui/docs/content/slider.md +4 -4
  85. package/src/ui/docs/content/spinner.md +3 -3
  86. package/src/ui/docs/content/tabs.md +6 -6
  87. package/src/ui/docs/content/testing.md +4 -2
  88. package/src/ui/docs/content/toast.md +3 -5
  89. package/src/ui/docs/content/toggle.md +37 -0
  90. package/src/ui/docs/content/tooltip.md +4 -3
  91. package/src/ui/docs/content/truncate.md +3 -2
  92. package/src/ui/docs/content/ui.md +3 -1
  93. package/src/ui/docs/content/upgrading.md +43 -13
  94. package/src/ui/docs/doc-client.tsx +1 -1
  95. package/src/ui/docs/registry.tsx +30 -5
  96. package/src/ui/meta.ts +4 -4
@@ -58,8 +58,8 @@ vertical amplie a área interativa.
58
58
 
59
59
  ## Vertical
60
60
 
61
- Com `orientation="vertical"`, a lista forma uma coluna e a marca da variante `line` passa para a
62
- lateral do gatilho.
61
+ Com `orientation="vertical"`, a lista forma uma coluna. O exemplo usa a variante padrão; com
62
+ `variant="line"`, a marca da aba ativa passa para a lateral do gatilho.
63
63
 
64
64
  ```tsx preview col
65
65
  <Tabs defaultValue="prompt" orientation="vertical">
@@ -87,9 +87,9 @@ lateral do gatilho.
87
87
  ```tsx preview col
88
88
  <Tabs defaultValue="preview" size="sm">
89
89
  <TabsList>
90
- <TabsTrigger value="preview" className="text-xs">Preview</TabsTrigger>
91
- <TabsTrigger value="code" className="text-xs">Código</TabsTrigger>
92
- <TabsTrigger value="ai" className="text-xs">IA</TabsTrigger>
90
+ <TabsTrigger value="preview">Preview</TabsTrigger>
91
+ <TabsTrigger value="code">Código</TabsTrigger>
92
+ <TabsTrigger value="ai">IA</TabsTrigger>
93
93
  </TabsList>
94
94
  </Tabs>
95
95
  ```
@@ -101,7 +101,7 @@ lateral do gatilho.
101
101
  | `defaultValue` | `string` | | Aba inicial no modo não controlado. |
102
102
  | `value` | `string` | | Aba ativa no modo controlado. Use com `onValueChange`. |
103
103
  | `onValueChange` | `(value: string) => void` | | Chamado quando a pessoa seleciona outra aba. |
104
- | `size` | `'default' \| 'sm'` | `'default'` | Altura da lista na escala única dos controles (2.25 e 2rem), aplicada em `TabsList`. |
104
+ | `size` | `'default' \| 'sm'` | `'default'` | Altura da lista na escala única dos controles (2.25 e 2rem), aplicada em `TabsList`. Não altera a altura de `line` horizontal, que acompanha o conteúdo. |
105
105
  | `orientation` | `'horizontal' \| 'vertical'` | `'horizontal'` | Direção da lista de abas. |
106
106
 
107
107
  ## Propriedades de TabsList
@@ -72,10 +72,12 @@ schema zod — matéria-prima do `mockHandler` (modo design) e de fixtures de te
72
72
  url, datetime) e por nome de campo (email, id, `*At`→data, telefone, cpf/cnpj, nome…), sabor pt-BR.
73
73
 
74
74
  ```ts
75
+ import { entityRowSchema } from '@softize/opus/schema'
75
76
  import { fake, fakeMany } from '@softize/opus/testing'
76
77
 
77
- const one = fake(EventEntity.zod()) // 1 evento válido (safeParse passa)
78
- const many = fakeMany(EventEntity.zod(), 20) // 20, estáveis entre execuções
78
+ const eventRowSchema = entityRowSchema(EventEntity) // schema da linha da entidade
79
+ const one = fake(eventRowSchema) // 1 evento válido (safeParse passa)
80
+ const many = fakeMany(eventRowSchema, 20) // 20, estáveis entre execuções
79
81
  fake(schema, { seed: 7 }) // seed própria
80
82
  ```
81
83
 
@@ -31,11 +31,9 @@ hierarquia precisar ser diferente. A região fica alinhada ao fim lógico da sup
31
31
  canto usado pelas ações do Alert. O clique fecha o toast, salvo quando o handler chama
32
32
  `event.preventDefault()`.
33
33
 
34
- Na versão 13, `actions` substitui os campos `action` e `cancel` da versão 12. Migre cada controle
35
- para uma entrada da coleção e preserve a ordem visual desejada.
36
-
37
34
  `toast.promise` acompanha uma promessa e atualiza a mesma notificação nos estados de carregamento,
38
- sucesso ou erro.
35
+ sucesso ou erro. Ela não aceita `actions`; use `toast` com `actions` quando a notificação precisar
36
+ oferecer uma ação.
39
37
 
40
38
  ```tsx preview
41
39
  <Button
@@ -88,7 +86,7 @@ Monte um único `Toaster` na raiz do aplicativo. O tema vem da propriedade `them
88
86
  |---|---|---|---|
89
87
  | `description` | `React.ReactNode` | | Complemento exibido abaixo do título. |
90
88
  | `actions` | `ToastAction[]` | | Coleção ordenada de ações; a última recebe destaque primário por padrão. |
91
- | `duration` | `number` | do Sonner | Tempo de permanência da notificação. |
89
+ | `duration` | `number` | `4000` | Tempo de permanência da notificação, em milissegundos. O `Toaster` pode mudar o padrão, e `toast.loading` não expira sozinho. |
92
90
 
93
91
  ## Propriedades de ToastAction
94
92
 
@@ -71,6 +71,7 @@ disabled esmaece e bloqueia o clique — o estado pressed permanece visível.
71
71
  | `defaultPressed` | `boolean` | `false` | Estado inicial no modo não controlado. |
72
72
  | `variant` | `'default' \| 'outline'` | `'default'` | default não tem borda (fundo só quando ativo); outline carrega a borda. |
73
73
  | `size` | `'sm' \| 'default' \| 'lg'` | `'default'` | Altura na escala única dos controles (2 · 2.25 · 2.5rem) — sm para toolbar densa, lg para alvo mais confortável. |
74
+ | `shape` | `'default' \| 'pill'` | `'default'` | Geometria do controle; `pill` arredonda as extremidades. |
74
75
  | `disabled` | `boolean` | `false` | Esmaece e bloqueia o clique, preservando o estado visual. |
75
76
 
76
77
  ## ToggleGroup
@@ -106,6 +107,39 @@ render(
106
107
  )
107
108
  ```
108
109
 
110
+ ### Itens só com ícone e tooltip
111
+
112
+ Quando o item mostra somente um ícone, mantenha o `aria-label` e acrescente uma dica visual. Envolva o
113
+ `ToggleGroupItem` em `TooltipTrigger asChild`: o item preserva o estado selecionado e seus atributos,
114
+ e a dica aparece sem criar outro botão. O `TooltipProvider` da raiz do aplicativo continua necessário.
115
+
116
+ ```tsx preview
117
+ const [align, setAlign] = useState('left')
118
+
119
+ render(
120
+ <ToggleGroup type="single" value={align} onValueChange={(v) => v && setAlign(v)}>
121
+ <Tooltip>
122
+ <TooltipTrigger asChild>
123
+ <ToggleGroupItem value="left" aria-label="Alinhar à esquerda"><AlignLeft /></ToggleGroupItem>
124
+ </TooltipTrigger>
125
+ <TooltipContent>Alinhar à esquerda</TooltipContent>
126
+ </Tooltip>
127
+ <Tooltip>
128
+ <TooltipTrigger asChild>
129
+ <ToggleGroupItem value="center" aria-label="Centralizar"><AlignCenter /></ToggleGroupItem>
130
+ </TooltipTrigger>
131
+ <TooltipContent>Centralizar</TooltipContent>
132
+ </Tooltip>
133
+ <Tooltip>
134
+ <TooltipTrigger asChild>
135
+ <ToggleGroupItem value="right" aria-label="Alinhar à direita"><AlignRight /></ToggleGroupItem>
136
+ </TooltipTrigger>
137
+ <TooltipContent>Alinhar à direita</TooltipContent>
138
+ </Tooltip>
139
+ </ToggleGroup>,
140
+ )
141
+ ```
142
+
109
143
  ### Variante e espaçamento
110
144
 
111
145
  `variant`, `size` e `shape` definidos no grupo chegam aos itens por contexto. `spacing` separa os
@@ -138,3 +172,6 @@ itens; com zero, eles formam um bloco contínuo.
138
172
  |---|---|---|---|
139
173
  | `value` | `string` | | Identificador que entra no valor do grupo quando o item é ativado. |
140
174
  | `disabled` | `boolean` | `false` | Bloqueia somente este item e preserva seu estado visual. |
175
+ | `variant` | `'default' \| 'outline'` | `'default'` | Tratamento do item quando o grupo não declara `variant`; o valor do grupo prevalece. |
176
+ | `size` | `'default' \| 'sm' \| 'lg'` | `'default'` | Tamanho do item quando o grupo não declara `size`; o valor do grupo prevalece. |
177
+ | `shape` | `'default' \| 'pill'` | shape do grupo | Geometria deste item; quando informada, prevalece sobre a do grupo. |
@@ -24,17 +24,18 @@ precisando de `aria-label`.
24
24
  </Tooltip>
25
25
  <Tooltip>
26
26
  <TooltipTrigger asChild><Button variant="ghost">Direita</Button></TooltipTrigger>
27
- <TooltipContent side="right">side=&quot;right&quot;.</TooltipContent>
27
+ <TooltipContent side="right">Abre à direita do botão.</TooltipContent>
28
28
  </Tooltip>
29
29
  <Tooltip>
30
30
  <TooltipTrigger asChild><Button variant="ghost">Embaixo</Button></TooltipTrigger>
31
- <TooltipContent side="bottom">side=&quot;bottom&quot;.</TooltipContent>
31
+ <TooltipContent side="bottom">Abre abaixo do botão.</TooltipContent>
32
32
  </Tooltip>
33
33
  ```
34
34
 
35
35
  ## Provider na raiz
36
36
 
37
- Monte um único `TooltipProvider` na raiz para compartilhar o atraso de exibição. Cada `Tooltip` não
37
+ Monte um único `TooltipProvider` na raiz do aplicativo. Ele é obrigatório: um `Tooltip` fora de um
38
+ provider lança erro. O provider também compartilha o atraso de exibição, então cada `Tooltip` não
38
39
  precisa de um provider próprio.
39
40
 
40
41
  ```tsx
@@ -59,7 +59,8 @@ quando o texto completo ainda não oferecer contexto suficiente.
59
59
  ```
60
60
 
61
61
  Requer `TooltipProvider` na raiz (o esqueleto do `opus create` já monta). Largura vem do
62
- container ou de `className` (`max-w-*`) — o span é `block truncate`.
62
+ container ou de `className` (`max-w-*`) — o span é `block` e corta em reticências (`truncate`); com
63
+ `fade`, esmaece o fim da linha em vez das reticências.
63
64
 
64
65
  ## Propriedades de Truncate
65
66
 
@@ -67,4 +68,4 @@ container ou de `className` (`max-w-*`) — o span é `block truncate`.
67
68
  |---|---|---|---|
68
69
  | `tooltip` | `ReactNode` | os próprios `children` | Conteúdo da dica quando o texto transborda. |
69
70
  | `fade` | `boolean` | `false` | Sinaliza o corte esmaecendo o fim da linha, no lugar das reticências. |
70
- | `className` | `string` | | Largura (`max-w-*`) e demais ajustes; o span é `block truncate`. |
71
+ | `className` | `string` | | Largura (`max-w-*`) e demais ajustes; o span é `block`, com `truncate` fora do modo `fade`. |
@@ -24,10 +24,12 @@ para o aplicativo quando a API pública já atender ao caso.
24
24
  ```tsx
25
25
  // Componentes e hooks — tudo do mesmo barrel.
26
26
  import { Button, Dialog, useAction } from '@softize/opus/ui/react'
27
+ ```
27
28
 
29
+ ```css
28
30
  /* index.css — o tema canônico + os componentes do Opus no scan do Tailwind. */
29
31
  @import '@softize/opus/ui/theme.css';
30
- @source '../node_modules/@softize/opus/src/ui';
32
+ @source '../node_modules/@softize/opus/src/ui/**/*.{ts,tsx}';
31
33
  ```
32
34
 
33
35
  ## Prebundle do Vite
@@ -10,10 +10,23 @@ gates apontam as adaptações necessárias no projeto.
10
10
  ## 1. Identificar a versão disponível
11
11
 
12
12
  O **Maestro** compara o pin (`opus.json`) com a versão instalada e com a fonte a cada
13
- sessão — o alerta no rodapé diz a distância (`v2.9.0v2.15.2`) e o **Atualizar** faz
13
+ sessão — o alerta no rodapé diz a distância (`v18.0.1v18.1.0`) e o **Atualizar** faz
14
14
  a parte mecânica: bump da dependência, re-materialização da camada de IA (skills,
15
- hooks, agentes) e re-sync do bloco gerenciado do CLAUDE.md. Fora do Maestro:
16
- `pnpm outdated @softize/opus`.
15
+ hooks, agentes) e re-sync do bloco gerenciado do CLAUDE.md.
16
+
17
+ Fora do Maestro, faça essa parte à mão:
18
+
19
+ ```bash
20
+ pnpm outdated @softize/opus # distância até a versão publicada
21
+ pnpm -r up @softize/opus@<versão> # em todo workspace que declara o Opus
22
+ pnpm run setup # opus setup && base setup: re-materializa base.json e skills
23
+ ```
24
+
25
+ Rode `setup` no diretório de cada app que tem `opus.json`; num monorepo criado por
26
+ `opus create --monorepo`, a raiz não tem esse script, e `pnpm -r run setup` alcança todos os apps.
27
+ O postinstall do pacote tenta materializar sozinho, mas é best-effort; se a camada materializada
28
+ ainda corresponder à versão anterior, o `opus check` aborta com
29
+ `base.json: Opus aplicado X, instalado Y`.
17
30
 
18
31
  ## 2. Ler as mudanças acumuladas
19
32
 
@@ -22,19 +35,36 @@ O changelog **viaja no pacote** — depois do bump, está em
22
35
  a seção **Breaking** diz a migração (o que renomeou, o que fazer no seu código).
23
36
  A esteira de release **recusa** publicar versão sem entrada — o arquivo não defasa.
24
37
 
25
- - **minor** (2.92.10): compatível; leia por curiosidade.
26
- - **major** (2.x 3.0): pare nas seções Breaking de cada versão pulada, na ordem.
38
+ - **minor e patch** (18.018.1): leia todas as entradas intermediárias. Minors podem pedir ação,
39
+ como a troca de `PageHeader` por `PageIntro` no `PageShell` (17.2.0) ou o layout desktop fixo (18.1.0).
40
+ - **major** (17.x → 18.0): além disso, aplique as seções Breaking de cada versão pulada, na ordem.
27
41
 
28
42
  ## 3. Executar as verificações
29
43
 
30
- O Opus ship source: o que quebrou aparece com arquivo e linha. Rode, na ordem:
44
+ O Opus é publicado como código-fonte TypeScript: o que quebrou aparece com arquivo e linha.
45
+ Rode, na ordem:
46
+
47
+ ```bash
48
+ pnpm typecheck # a API nova cobra os tipos
49
+ pnpm exec opus check # convenções (regras novas inclusas)
50
+ pnpm exec opus copy --check # inventário de copy em dia
51
+ pnpm exec base copy check # política de copy da base
52
+ pnpm test # comportamento
53
+ pnpm manifest:check # a spec projetada ficou fresca?
54
+ ```
55
+
56
+ Num monorepo, `typecheck` e `test` existem na raiz, mas `manifest:check` é script de cada app:
57
+ rode-o no diretório do app ou com `pnpm -r run manifest:check`. Nenhum desses comandos migra o
58
+ banco. Se o projeto tiver testes de integração, eles usam o banco que o próprio projeto configurar.
59
+
60
+ ## 4. Migrar o banco, se houver
61
+
62
+ Se o `opus.config.ts` declara `database`, confira o schema e aplique a migração como uma etapa
63
+ separada, contra o banco do ambiente que você pretende alterar:
31
64
 
32
65
  ```bash
33
- pnpm typecheck # a API nova cobra os tipos
34
- pnpm exec opus check # convenções (regras novas inclusas)
35
- pnpm test # comportamento
36
- pnpm manifest:check # a spec projetada ficou fresca?
37
- opus db migrate # schema em dia (drift-check embutido)
66
+ pnpm exec opus db check # compara entidades e banco, sem escrever
67
+ pnpm exec opus db migrate # aplica o schema idempotente; escreve no banco
38
68
  ```
39
69
 
40
70
  Com todas as verificações verdes, revise a atualização como qualquer outra mudança de código antes
@@ -42,6 +72,6 @@ de entregá-la.
42
72
 
43
73
  ## Pulou muitas versões?
44
74
 
45
- O ritual não muda, só o volume: leia as seções Breaking acumuladas (o changelog é
46
- uma lista, não um diff), aplique na ordem e deixe os gates validarem o conjunto.
75
+ O ritual não muda, só o volume: leia todas as entradas acumuladas, não as seções Breaking
76
+ (o changelog é uma lista, não um diff), aplique na ordem e deixe os gates validarem o conjunto.
47
77
  Não há caminho especial — é o mesmo laço, com mais iterações.
@@ -105,7 +105,7 @@ export const docWorkspaceList = defineContract({
105
105
  ],
106
106
  },
107
107
  },
108
- client: { label: 'Cliente', type: 'text', advanced: true },
108
+ client: { label: 'Cliente', type: 'text', placement: 'advanced' },
109
109
  },
110
110
  text: { fields: ['name'] },
111
111
  sort: { fields: ['name'] },
@@ -11,6 +11,10 @@
11
11
  * helper `comp`; páginas conceituais renderizam o markdown direto (o próprio md traz o H1/lead).
12
12
  */
13
13
  import { useEffect } from "react";
14
+ import {
15
+ definePresentation,
16
+ definePresentationInvocation,
17
+ } from "../../core/presentation.ts";
14
18
  import * as lucideIcons from "lucide-react";
15
19
  import * as opusUi from "../react.tsx";
16
20
  import { componentMeta } from "../meta.ts";
@@ -154,7 +158,7 @@ export interface DocSection {
154
158
  // o scope injetado entra POR CIMA do default no DocMarkdown, e `<Badge>` num exemplo
155
159
  // tem que ser o COMPONENTE (chip), não o selo do lucide. Ícone colidido, se um exemplo
156
160
  // precisar, entra por alias no scope do chamador.
157
- const iconScope: Record<string, unknown> = Object.fromEntries(
161
+ export const iconScope: Record<string, unknown> = Object.fromEntries(
158
162
  Object.entries(lucideIcons).filter(([name]) => !(name in opusUi)),
159
163
  );
160
164
 
@@ -177,7 +181,7 @@ const comp =
177
181
  );
178
182
 
179
183
  /** O palco dos patterns no scope dos previews: ícones, cliente simulado e contratos de exemplo. */
180
- const patternScope = {
184
+ export const patternScope = {
181
185
  ...iconScope,
182
186
  DocBrowserActionProvider,
183
187
  docWorkspaceCreate,
@@ -188,12 +192,28 @@ const patternScope = {
188
192
  docSessionDelete,
189
193
  };
190
194
 
195
+ /**
196
+ * Palco da página de Presentation: o exemplo declara a própria Presentation sobre um contrato do
197
+ * palco, então precisa das funções de declaração além do palco dos patterns. Fora daqui elas não
198
+ * entram no scope — os demais previews consomem definições já prontas.
199
+ */
200
+ export const presentationScope = {
201
+ ...patternScope,
202
+ definePresentation,
203
+ definePresentationInvocation,
204
+ };
205
+
191
206
  /** Página de pattern: igual ao `comp`, mas os previews enxergam o palco doc-client no scope. */
192
207
  const pattern =
193
- (title: string, key: keyof typeof componentMeta, content: string) =>
208
+ (
209
+ title: string,
210
+ key: keyof typeof componentMeta,
211
+ content: string,
212
+ scope: Record<string, unknown> = patternScope,
213
+ ) =>
194
214
  (): React.ReactElement => (
195
215
  <DocPage title={title} meta={componentMeta[key]}>
196
- <DocMarkdown content={content} scope={patternScope} />
216
+ <DocMarkdown content={content} scope={scope} />
197
217
  </DocPage>
198
218
  );
199
219
 
@@ -406,7 +426,12 @@ export const UI_SECTIONS: DocSection[] = [
406
426
  {
407
427
  slug: "presentation",
408
428
  title: "Presentation",
409
- render: pattern("Presentation", "presentation", presentationMd),
429
+ render: pattern(
430
+ "Presentation",
431
+ "presentation",
432
+ presentationMd,
433
+ presentationScope,
434
+ ),
410
435
  },
411
436
  {
412
437
  slug: "content",
package/src/ui/meta.ts CHANGED
@@ -15,7 +15,7 @@ export const componentMeta = {
15
15
  name: "content",
16
16
  ancestry: "opus",
17
17
  whenToUse:
18
- "Organize uma região nomeada dentro de uma página ou de outra superfície. Use as propriedades de Content no caso comum e componha seus slots quando precisar controlar a estrutura. Para o cabeçalho principal da tela, use Page.",
18
+ "Organize uma região nomeada dentro de uma página ou de outra superfície. Use as propriedades de Content no caso comum e componha seus slots quando precisar controlar a estrutura. Numa página centrada em uma coleção, `level={1}` faz do Content o heading principal; nas demais, ele vem de PageTitle.",
19
19
  },
20
20
  ask: {
21
21
  name: "ask",
@@ -153,7 +153,7 @@ export const componentMeta = {
153
153
  name: "menu",
154
154
  ancestry: "opus",
155
155
  whenToUse:
156
- 'O menu de ações da casa: lista flutuante ancorada em um gatilho (Radix DropdownMenu). Compõe Menu > MenuTrigger + MenuContent e seus itens. `context="danger"` sinaliza item com consequência perigosa; `destructive` permanece alias de migração. Para escolher um valor, use Select; para busca por teclado, Command; para conteúdo livre ancorado, Popover.',
156
+ 'O menu de ações da casa: lista flutuante ancorada em um gatilho (Radix DropdownMenu). Compõe Menu > MenuTrigger + MenuContent e seus itens. `context="danger"` sinaliza item com consequência perigosa. Para escolher um valor, use Select; para busca por teclado, Command; para conteúdo livre ancorado, Popover.',
157
157
  },
158
158
  popover: {
159
159
  name: "popover",
@@ -189,7 +189,7 @@ export const componentMeta = {
189
189
  name: "table",
190
190
  ancestry: "shadcn",
191
191
  whenToUse:
192
- 'Tabela de dados. Compõe Table > (TableHeader > TableRow > TableHead, TableBody > TableRow > TableCell). `variant="plain"` vem sem borda externa; `variant="framed"` aplica a moldura canônica, recorta o scroll e destaca o cabeçalho. Para listagem tabular para o pattern de search use ActionList.',
192
+ 'Tabela de dados. Compõe Table > (TableHeader > TableRow > TableHead, TableBody > TableRow > TableCell). `variant="plain"` vem sem borda externa; `variant="framed"` aplica a moldura canônica, recorta o scroll e destaca o cabeçalho. Para uma coleção com busca, filtros e paginação, use ActionList.',
193
193
  },
194
194
  tabs: {
195
195
  name: "tabs",
@@ -279,7 +279,7 @@ export const componentMeta = {
279
279
  name: "field",
280
280
  ancestry: "shadcn",
281
281
  whenToUse:
282
- "Componha rótulo, controle, ajuda e erro com espaçamento consistente. Use a orientação vertical no caso comum e as orientações horizontal ou responsiva quando controle e texto precisarem ficar lado a lado. Field cuida do layout; o formulário continua responsável por estado e validação.",
282
+ "Componha rótulo, controle, ajuda e erro com espaçamento consistente. Use a orientação vertical no caso comum e a horizontal quando controle e texto precisarem ficar lado a lado; `responsive` continua aceito como alias da horizontal. Field cuida do layout; o formulário continua responsável por estado e validação.",
283
283
  },
284
284
  "input-otp": {
285
285
  name: "input-otp",