@softize/opus 15.2.2 → 16.0.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 (37) hide show
  1. package/CHANGELOG.md +51 -18
  2. package/bin/lib/check.mjs +98 -15
  3. package/bin/lib/copy.mjs +811 -314
  4. package/bin/lib/gen-manifest.mjs +24 -23
  5. package/bin/lib/gen-runner.mjs +188 -148
  6. package/docs/adr/0010-page-header-owns-page-chrome.md +3 -4
  7. package/docs/adr/0011-page-shell-coordinates-persistent-page-chrome.md +5 -3
  8. package/docs/adr/0012-modal-header-only-names-the-surface.md +45 -0
  9. package/docs/adr/0013-presentation-is-a-portable-action-oriented-artifact.md +92 -0
  10. package/docs/code-style.md +24 -19
  11. package/package.json +5 -1
  12. package/registry/skills/build-opus-ui/references/ui-patterns.md +43 -26
  13. package/src/core/presentation.ts +512 -0
  14. package/src/presentation/index.ts +1 -0
  15. package/src/ui/components/patterns/action-list-dialog.tsx +26 -9
  16. package/src/ui/components/patterns/confirm.tsx +34 -29
  17. package/src/ui/components/patterns/form-dialog.tsx +20 -8
  18. package/src/ui/components/patterns/list.tsx +26 -9
  19. package/src/ui/components/patterns/page.tsx +99 -139
  20. package/src/ui/components/patterns/presentation.tsx +316 -0
  21. package/src/ui/components/patterns/sidebar.tsx +3 -3
  22. package/src/ui/components/patterns/trigger.tsx +38 -17
  23. package/src/ui/components/primitives/button-group.tsx +53 -43
  24. package/src/ui/components/primitives/command.tsx +30 -72
  25. package/src/ui/components/primitives/dialog.tsx +23 -89
  26. package/src/ui/components/primitives/drawer.tsx +8 -34
  27. package/src/ui/docs/content/action-form-dialog.md +12 -10
  28. package/src/ui/docs/content/action-list-dialog.md +22 -17
  29. package/src/ui/docs/content/button.md +52 -35
  30. package/src/ui/docs/content/communication.md +26 -26
  31. package/src/ui/docs/content/dialog.md +173 -154
  32. package/src/ui/docs/content/drawer.md +12 -11
  33. package/src/ui/docs/content/page.md +72 -91
  34. package/src/ui/docs/content/presentation.md +158 -0
  35. package/src/ui/docs/registry.tsx +6 -0
  36. package/src/ui/meta.ts +8 -2
  37. package/src/ui/react.tsx +10 -3
@@ -21,16 +21,16 @@ altura da linha; os `icon-*` são quadrados para botões só de ícone, que exig
21
21
  há texto visível. O glifo dentro do controle acompanha o tamanho (0.875rem em `xs` e `sm`, 1rem em
22
22
  `default`, 1.25rem em `lg`), a menos que o ícone traga um `size-*` próprio.
23
23
 
24
- | Nome | Medida | Uso |
25
- |---|---|---|
26
- | `xs` | 1.5rem | Ação dentro de um campo (`InputGroupButton`). |
27
- | `sm` | 2rem | Toolbar e cabeçalho densos, ao lado de `Select` e `Tabs` `sm`. |
28
- | `default` | 2.25rem | A linha padrão, a mesma de `Input`. |
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 ou de uma linha densa; é o quadrado de `ActionTrigger` com `icon`. |
24
+ | Nome | Medida | Uso |
25
+ | --------- | ------- | -------------------------------------------------------------------------------------------------------------------------------- |
26
+ | `xs` | 1.5rem | Ação dentro de um campo (`InputGroupButton`). |
27
+ | `sm` | 2rem | Toolbar e cabeçalho densos, ao lado de `Select` e `Tabs` `sm`. |
28
+ | `default` | 2.25rem | A linha padrão, a mesma de `Input`. |
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 ou de uma linha densa; é o quadrado de `ActionTrigger` com `icon`. |
31
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
- | `icon` | 2.25rem | Ação só de ícone na linha padrão. |
33
- | `icon-lg` | 2.5rem | Ação só de ícone ao lado de um `lg`. |
32
+ | `icon` | 2.25rem | Ação só de ícone na linha padrão. |
33
+ | `icon-lg` | 2.5rem | Ação só de ícone ao lado de um `lg`. |
34
34
 
35
35
  ```tsx preview
36
36
  <Button size="xs">Mínimo</Button>
@@ -63,20 +63,22 @@ buttonVariants serve para o caso sem filho único.
63
63
 
64
64
  ```tsx preview
65
65
  <Button asChild variant="outline">
66
- <a href="#" onClick={(e) => e.preventDefault()}>Abrir documentação</a>
66
+ <a href="#" onClick={(e) => e.preventDefault()}>
67
+ Abrir documentação
68
+ </a>
67
69
  </Button>
68
70
  ```
69
71
 
70
72
  ## Propriedades de Button
71
73
 
72
- | Propriedade | Tipo | Padrão | Descrição |
73
- |---|---|---|---|
74
- | `context` | `'neutral' \| 'primary' \| 'danger'` | `'primary'` | A hierarquia ou o risco comunicado pela ação. |
75
- | `variant` | `'solid' \| 'subtle' \| 'outline' \| 'ghost' \| 'link'` | `'solid'` | O tratamento visual aplicado ao contexto. |
76
- | `size` | `'xs' \| 'sm' \| 'default' \| 'lg' \| 'icon-xs' \| 'icon-sm' \| 'icon' \| 'icon-lg'` | `'default'` | A medida na escala única dos controles (tabela acima). Os `icon-*` são quadrados para botões só de ícone, com `aria-label`. |
77
- | `asChild` | `boolean` | `false` | Renderiza como o filho (Radix Slot) em vez de `<button>` — para âncoras e afins. |
78
- | `busy` | `boolean` | `false` | Ação em andamento (depois do clique): mostra Spinner + desabilita. Não é "carregando" de conteúdo (que é Spinner/Skeleton em um nível de página). |
79
- | `icon` | `React.ReactNode` | | Ícone à esquerda, como nó (ex.: `icon={<Plus />}`); o glifo segue o `size`. No busy é trocado pelo Spinner — não soma. |
74
+ | Propriedade | Tipo | Padrão | Descrição |
75
+ | ----------- | ------------------------------------------------------------------------------------ | ----------- | ------------------------------------------------------------------------------------------------------------------------------------------------- |
76
+ | `context` | `'neutral' \| 'primary' \| 'danger'` | `'primary'` | A hierarquia ou o risco comunicado pela ação. |
77
+ | `variant` | `'solid' \| 'subtle' \| 'outline' \| 'ghost' \| 'link'` | `'solid'` | O tratamento visual aplicado ao contexto. |
78
+ | `size` | `'xs' \| 'sm' \| 'default' \| 'lg' \| 'icon-xs' \| 'icon-sm' \| 'icon' \| 'icon-lg'` | `'default'` | A medida na escala única dos controles (tabela acima). Os `icon-*` são quadrados para botões só de ícone, com `aria-label`. |
79
+ | `asChild` | `boolean` | `false` | Renderiza como o filho (Radix Slot) em vez de `<button>` — para âncoras e afins. |
80
+ | `busy` | `boolean` | `false` | Ação em andamento (depois do clique): mostra Spinner + desabilita. Não é "carregando" de conteúdo (que é Spinner/Skeleton em um nível de página). |
81
+ | `icon` | `React.ReactNode` | | Ícone à esquerda, como nó (ex.: `icon={<Plus />}`); o glifo segue o `size`. No busy é trocado pelo Spinner — não soma. |
80
82
 
81
83
  ## ButtonGroup
82
84
 
@@ -100,9 +102,15 @@ conectar bordas. Esse modo atende ações icon-only em barras e linhas de listag
100
102
 
101
103
  ```tsx preview
102
104
  <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>
105
+ <Button variant="ghost" size="icon" aria-label="Recarregar">
106
+ <RotateCw />
107
+ </Button>
108
+ <Button variant="ghost" size="icon" aria-label="Exibição">
109
+ <SlidersHorizontal />
110
+ </Button>
111
+ <Button context="primary" size="icon" aria-label="Novo item">
112
+ <Plus />
113
+ </Button>
106
114
  </ButtonGroup>
107
115
  ```
108
116
 
@@ -132,7 +140,9 @@ semântica de outro elemento, como `label`.
132
140
  <GitBranch />
133
141
  empresa-x-api
134
142
  </ButtonGroupText>
135
- <Button variant="outline" icon={<RotateCw />}>Sincronizar</Button>
143
+ <Button variant="outline" icon={<RotateCw />}>
144
+ Sincronizar
145
+ </Button>
136
146
  </ButtonGroup>
137
147
  ```
138
148
 
@@ -142,28 +152,35 @@ semântica de outro elemento, como `label`.
142
152
 
143
153
  ```tsx preview col-start
144
154
  <ButtonGroup orientation="vertical">
145
- <Button variant="outline" size="icon" aria-label="Rodar sessão"><Play /></Button>
146
- <Button variant="outline" size="icon" aria-label="Pausar sessão"><Pause /></Button>
147
- <Button variant="outline" size="icon" aria-label="Reiniciar sessão"><RotateCw /></Button>
155
+ <Button variant="outline" size="icon" aria-label="Rodar sessão">
156
+ <Play />
157
+ </Button>
158
+ <Button variant="outline" size="icon" aria-label="Pausar sessão">
159
+ <Pause />
160
+ </Button>
161
+ <Button variant="outline" size="icon" aria-label="Reiniciar sessão">
162
+ <RotateCw />
163
+ </Button>
148
164
  </ButtonGroup>
149
165
  ```
150
166
 
151
167
  ### Propriedades de ButtonGroup
152
168
 
153
- | Propriedade | Tipo | Padrão | Descrição |
154
- |---|---|---|---|
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. |
157
- | `shape` | `'default' \| 'pill'` | `'default'` | Geometria das extremidades externas do grupo. |
169
+ | Propriedade | Tipo | Padrão | Descrição |
170
+ | -------------- | ---------------------------- | -------------- | ----------------------------------------------------------------------------------------- |
171
+ | `orientation` | `'horizontal' \| 'vertical'` | `'horizontal'` | Direção do bloco e do colapso das bordas. |
172
+ | `mode` | `'connected' \| 'spaced'` | `'connected'` | Conecta as bordas dos controles ou preserva cada controle com intervalo compacto. |
173
+ | `shape` | `'default' \| 'pill'` | `'default'` | Geometria das extremidades externas do grupo. |
174
+ | `distribution` | `'content' \| 'equal'` | `'content'` | Mantém a largura do conteúdo ou divide igualmente o espaço disponível entre os controles. |
158
175
 
159
176
  ### Propriedades de ButtonGroupSeparator
160
177
 
161
- | Propriedade | Tipo | Padrão | Descrição |
162
- |---|---|---|---|
178
+ | Propriedade | Tipo | Padrão | Descrição |
179
+ | ------------- | ---------------------------- | ------------ | ------------------------------------------------------------- |
163
180
  | `orientation` | `'horizontal' \| 'vertical'` | `'vertical'` | Direção do traço divisor; use vertical em grupos horizontais. |
164
181
 
165
182
  ### Propriedades de ButtonGroupText
166
183
 
167
- | Propriedade | Tipo | Padrão | Descrição |
168
- |---|---|---|---|
169
- | `asChild` | `boolean` | `false` | Renderiza como o filho para assumir outra semântica sem perder o estilo. |
184
+ | Propriedade | Tipo | Padrão | Descrição |
185
+ | ----------- | --------- | ------- | ------------------------------------------------------------------------ |
186
+ | `asChild` | `boolean` | `false` | Renderiza como o filho para assumir outra semântica sem perder o estilo. |
@@ -16,14 +16,14 @@ muda apenas quando o produto ou os componentes Opus mudam.
16
16
 
17
17
  ## Língua e termos no Opus
18
18
 
19
- | Camada | Convenção local |
20
- |---|---|
21
- | Identificadores de código, arquivos, diretórios e domínios | Inglês |
22
- | Nomes de action e rota | Inglês, no formato `resource.verb` |
23
- | Colunas e tabelas de banco | Inglês, em `snake_case` |
24
- | Enums, status e chaves de dicionário | Inglês, inclusive em exemplos e fixtures (`active`, não `ativo`) |
25
- | Texto de UI visível | pt-BR; o contrato fornece o label humano para valores técnicos |
26
- | Comentários e documentação deste repositório | pt-BR |
19
+ | Camada | Convenção local |
20
+ | ---------------------------------------------------------- | ---------------------------------------------------------------- |
21
+ | Identificadores de código, arquivos, diretórios e domínios | Inglês |
22
+ | Nomes de action e rota | Inglês, no formato `resource.verb` |
23
+ | Colunas e tabelas de banco | Inglês, em `snake_case` |
24
+ | Enums, status e chaves de dicionário | Inglês, inclusive em exemplos e fixtures (`active`, não `ativo`) |
25
+ | Texto de UI visível | pt-BR; o contrato fornece o label humano para valores técnicos |
26
+ | Comentários e documentação deste repositório | pt-BR |
27
27
 
28
28
  `Opus` e `Softize` são nomes próprios em prosa (`o Opus`, `a Softize`). Tokens técnicos
29
29
  preservam a grafia de código: `opus check`, `@softize/opus`, `opus.json` e
@@ -39,21 +39,21 @@ O componente ou o contrato Opus classifica cada texto antes de a Base aplicar a
39
39
  Essa classificação decide, por exemplo, se o conteúdo é um fragmento estrutural ou uma
40
40
  frase. Não copie as regras da Base para cá.
41
41
 
42
- | Superfície Opus | Papel enviado à Base |
43
- |---|---|
44
- | `label`, botão de confirmação e filhos de `Button` | `button` |
45
- | `title`, `CardTitle`, `DialogTitle` | `title` |
46
- | `description`, `hint`, `help` | `description` ou `helper-text` |
47
- | `messages.success` e `messages.error` | `success` e `error` |
48
- | `confirm.message`, `DialogDescription` | `dialog-body` |
49
- | label de campo, filtro ou opção | `label` ou `menu-item` |
50
- | placeholder de campo ou busca | `placeholder` |
51
- | `Select.emptyText` e grupos de opção | `empty-state` e `heading` |
52
- | confirmação local do `ActionTrigger` | `title`, `dialog-body` e `button` |
53
- | `dialog.alert/confirm/prompt/choose` — `title`, `description`/`body`, `action`/`cancel`, `actions[].label` | `title`, `dialog-body`, `button` (e `placeholder` no `prompt`) |
54
- | filhos de `TooltipContent` | `label` |
55
- | `LabelHelp.help` | `helper-text` |
56
- | `emptyMessage`, `errorMessage`, `retryLabel` de `DataState`, `PageState`, `ActionList`, `ActionListDialog` e `ActionView` | `empty-state`, `error`, `button` |
42
+ | Superfície Opus | Papel enviado à Base |
43
+ | ------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------- |
44
+ | `label`, botão de confirmação e filhos de `Button` | `button` |
45
+ | `title`, `CardTitle`, `DialogTitle` | `title` |
46
+ | `description`, `hint`, `help` | `description` ou `helper-text` |
47
+ | `messages.success` e `messages.error` | `success` e `error` |
48
+ | `confirm.message`, `dialog.*().body` e texto relevante no `DialogBody` | `dialog-body` |
49
+ | label de campo, filtro ou opção | `label` ou `menu-item` |
50
+ | placeholder de campo ou busca | `placeholder` |
51
+ | `Select.emptyText` e grupos de opção | `empty-state` e `heading` |
52
+ | confirmação local do `ActionTrigger` | `title`, `dialog-body` e `button` |
53
+ | `dialog.alert/confirm/prompt/choose` — `title`, `body`, `action`/`cancel`, `actions[].label` | `title`, `dialog-body`, `button` (e `placeholder` no `prompt`) |
54
+ | filhos de `TooltipContent` | `label` |
55
+ | `LabelHelp.help` | `helper-text` |
56
+ | `emptyMessage`, `errorMessage`, `retryLabel` de `DataState`, `PageState`, `ActionList`, `ActionListDialog` e `ActionView` | `empty-state`, `error`, `button` |
57
57
 
58
58
  O tooltip entra como `label` porque nomeia um controle icon-only: é um fragmento curto, sem
59
59
  ponto final, e a Base não define um papel próprio para tooltip. Texto de ajuda que precisa de
@@ -64,11 +64,11 @@ frase completa pertence ao `help` de um campo (contrato ou `LabelHelp`), não ao
64
64
  Quem vê o gate reprovar ou precisa de uma dispensa deve saber o que o extrator alcança sem
65
65
  declaração adicional:
66
66
 
67
- - **Diálogos imperativos.** `dialog.confirm({ title, description, action })` e as demais
67
+ - **Diálogos imperativos.** `dialog.confirm({ title, body, action })` e as demais
68
68
  respostas (`alert`, `prompt`, `choose`) entram no inventário como se fossem props de um
69
69
  `ActionFormDialog`; o campo do diagnóstico é `dialog.confirm().title`,
70
70
  `dialog.choose().actions[0].label` etc. Constantes locais resolvem normalmente. Uma função
71
- que devolve template (`description: describe(nome)`) gera o diagnóstico `content` habitual e
71
+ que devolve template (`body: describe(nome)`) gera o diagnóstico `content` habitual e
72
72
  se declara em `copy.dynamic` como `message-template`. Opções construídas em tempo de execução
73
73
  ou mutadas depois de declaradas reprovam como estrutura, porque nenhum texto pode ser
74
74
  atribuído a elas.
@@ -121,7 +121,7 @@ dispensados por `copy.dynamic`; ausência de conteúdo também continua bloquean
121
121
  {
122
122
  "source": "src/sessions.tsx",
123
123
  "line": 58,
124
- "field": "<DialogDescription> children",
124
+ "field": "dialog.confirm().body",
125
125
  "kind": "message-template",
126
126
  "role": "dialog-body",
127
127
  "text": "Excluir {nome}?",