@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.
- package/CHANGELOG.md +51 -18
- package/bin/lib/check.mjs +98 -15
- package/bin/lib/copy.mjs +811 -314
- package/bin/lib/gen-manifest.mjs +24 -23
- package/bin/lib/gen-runner.mjs +188 -148
- package/docs/adr/0010-page-header-owns-page-chrome.md +3 -4
- package/docs/adr/0011-page-shell-coordinates-persistent-page-chrome.md +5 -3
- package/docs/adr/0012-modal-header-only-names-the-surface.md +45 -0
- package/docs/adr/0013-presentation-is-a-portable-action-oriented-artifact.md +92 -0
- package/docs/code-style.md +24 -19
- package/package.json +5 -1
- package/registry/skills/build-opus-ui/references/ui-patterns.md +43 -26
- package/src/core/presentation.ts +512 -0
- package/src/presentation/index.ts +1 -0
- package/src/ui/components/patterns/action-list-dialog.tsx +26 -9
- package/src/ui/components/patterns/confirm.tsx +34 -29
- package/src/ui/components/patterns/form-dialog.tsx +20 -8
- package/src/ui/components/patterns/list.tsx +26 -9
- package/src/ui/components/patterns/page.tsx +99 -139
- package/src/ui/components/patterns/presentation.tsx +316 -0
- package/src/ui/components/patterns/sidebar.tsx +3 -3
- package/src/ui/components/patterns/trigger.tsx +38 -17
- package/src/ui/components/primitives/button-group.tsx +53 -43
- package/src/ui/components/primitives/command.tsx +30 -72
- package/src/ui/components/primitives/dialog.tsx +23 -89
- package/src/ui/components/primitives/drawer.tsx +8 -34
- package/src/ui/docs/content/action-form-dialog.md +12 -10
- package/src/ui/docs/content/action-list-dialog.md +22 -17
- package/src/ui/docs/content/button.md +52 -35
- package/src/ui/docs/content/communication.md +26 -26
- package/src/ui/docs/content/dialog.md +173 -154
- package/src/ui/docs/content/drawer.md +12 -11
- package/src/ui/docs/content/page.md +72 -91
- package/src/ui/docs/content/presentation.md +158 -0
- package/src/ui/docs/registry.tsx +6 -0
- package/src/ui/meta.ts +8 -2
- 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
|
|
25
|
-
|
|
26
|
-
| `xs`
|
|
27
|
-
| `sm`
|
|
28
|
-
| `default` | 2.25rem | A linha padrão, a mesma de `Input`.
|
|
29
|
-
| `lg`
|
|
30
|
-
| `icon-xs` | 1.5rem
|
|
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`
|
|
33
|
-
| `icon-lg` | 2.5rem
|
|
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()}>
|
|
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
|
|
73
|
-
|
|
74
|
-
| `context`
|
|
75
|
-
| `variant`
|
|
76
|
-
| `size`
|
|
77
|
-
| `asChild`
|
|
78
|
-
| `busy`
|
|
79
|
-
| `icon`
|
|
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"
|
|
104
|
-
|
|
105
|
-
|
|
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 />}>
|
|
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"
|
|
146
|
-
|
|
147
|
-
|
|
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
|
|
154
|
-
|
|
155
|
-
| `orientation`
|
|
156
|
-
| `mode`
|
|
157
|
-
| `shape`
|
|
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
|
|
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
|
|
168
|
-
|
|
169
|
-
| `asChild`
|
|
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
|
|
20
|
-
|
|
21
|
-
| Identificadores de código, arquivos, diretórios e domínios | Inglês
|
|
22
|
-
| Nomes de action e rota
|
|
23
|
-
| Colunas e tabelas de banco
|
|
24
|
-
| Enums, status e chaves de dicionário
|
|
25
|
-
| Texto de UI visível
|
|
26
|
-
| Comentários e documentação deste repositório
|
|
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
|
|
43
|
-
|
|
44
|
-
| `label`, botão de confirmação e filhos de `Button`
|
|
45
|
-
| `title`, `CardTitle`, `DialogTitle`
|
|
46
|
-
| `description`, `hint`, `help`
|
|
47
|
-
| `messages.success` e `messages.error`
|
|
48
|
-
| `confirm.message`, `
|
|
49
|
-
| label de campo, filtro ou opção
|
|
50
|
-
| placeholder de campo ou busca
|
|
51
|
-
| `Select.emptyText` e grupos de opção
|
|
52
|
-
| confirmação local do `ActionTrigger`
|
|
53
|
-
| `dialog.alert/confirm/prompt/choose` — `title`, `
|
|
54
|
-
| filhos de `TooltipContent`
|
|
55
|
-
| `LabelHelp.help`
|
|
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,
|
|
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 (`
|
|
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": "
|
|
124
|
+
"field": "dialog.confirm().body",
|
|
125
125
|
"kind": "message-template",
|
|
126
126
|
"role": "dialog-body",
|
|
127
127
|
"text": "Excluir {nome}?",
|