@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.
- package/CHANGELOG.md +58 -0
- package/PROMOTED.md +4 -5
- package/README.md +5 -4
- package/bin/cli.mjs +4 -0
- package/docs/adr/0004-page-content-state-is-composed.md +3 -0
- package/docs/adr/0005-structural-surfaces-share-an-explicit-anatomy.md +6 -2
- package/docs/adr/0011-page-shell-coordinates-persistent-page-chrome.md +6 -1
- package/docs/adr/0014-structural-headers-do-not-carry-description.md +2 -2
- package/docs/adr/0015-action-size-follows-interaction-density.md +4 -3
- package/docs/adr/{0012-modal-header-only-names-the-surface.md → 0018-modal-header-only-names-the-surface.md} +4 -1
- package/docs/adr/{0016-productive-surfaces-use-compact-density.md → 0019-productive-surfaces-use-compact-density.md} +4 -1
- package/docs/code-style.md +2 -2
- package/docs/consumer-upgrade-propagation.md +1 -1
- package/docs/data-products.md +5 -3
- package/docs/protocol.md +6 -6
- package/docs/releasing.md +28 -4
- package/package.json +1 -1
- package/registry/skills/build-opus-ui/references/ui-patterns.md +11 -1
- package/src/auth/drivers/jwt.ts +2 -1
- package/src/core/runtime.ts +25 -4
- package/src/core/types.ts +4 -4
- package/src/mcp/index.ts +9 -0
- package/src/ui/components/patterns/content-header.tsx +1 -1
- package/src/ui/components/patterns/form.tsx +1 -1
- package/src/ui/components/patterns/sidebar.tsx +1 -1
- package/src/ui/components/primitives/card.tsx +1 -1
- package/src/ui/components/primitives/detail.tsx +7 -7
- package/src/ui/components/primitives/radio-group.tsx +1 -1
- package/src/ui/components/primitives/select.tsx +1 -1
- package/src/ui/docs/content/action-form-dialog.md +11 -4
- package/src/ui/docs/content/action-form.md +7 -16
- package/src/ui/docs/content/action-list-dialog.md +4 -6
- package/src/ui/docs/content/action-list.md +46 -4
- package/src/ui/docs/content/action-trigger.md +9 -5
- package/src/ui/docs/content/action-view.md +12 -8
- package/src/ui/docs/content/actions.md +36 -13
- package/src/ui/docs/content/ai.md +26 -7
- package/src/ui/docs/content/alert.md +4 -3
- package/src/ui/docs/content/aspect-ratio.md +2 -2
- package/src/ui/docs/content/auth.md +25 -10
- package/src/ui/docs/content/avatar.md +1 -1
- package/src/ui/docs/content/badge.md +2 -2
- package/src/ui/docs/content/breadcrumb.md +3 -2
- package/src/ui/docs/content/button.md +31 -7
- package/src/ui/docs/content/calendar.md +1 -1
- package/src/ui/docs/content/card.md +1 -1
- package/src/ui/docs/content/carousel.md +14 -3
- package/src/ui/docs/content/chat.md +1 -1
- package/src/ui/docs/content/cli.md +13 -7
- package/src/ui/docs/content/command.md +34 -2
- package/src/ui/docs/content/composer.md +1 -1
- package/src/ui/docs/content/content.md +5 -4
- package/src/ui/docs/content/customization.md +1 -1
- package/src/ui/docs/content/cycle.md +7 -5
- package/src/ui/docs/content/data-state.md +6 -5
- package/src/ui/docs/content/data.md +3 -3
- package/src/ui/docs/content/detail.md +3 -2
- package/src/ui/docs/content/dialog.md +2 -2
- package/src/ui/docs/content/dictionary-value.md +1 -1
- package/src/ui/docs/content/dock.md +23 -2
- package/src/ui/docs/content/dot.md +0 -2
- package/src/ui/docs/content/drawer.md +1 -1
- package/src/ui/docs/content/empty.md +1 -4
- package/src/ui/docs/content/events.md +1 -1
- package/src/ui/docs/content/field.md +20 -11
- package/src/ui/docs/content/getting-started.md +4 -2
- package/src/ui/docs/content/icon-picker.md +2 -2
- package/src/ui/docs/content/input-otp.md +2 -0
- package/src/ui/docs/content/input.md +2 -3
- package/src/ui/docs/content/item.md +5 -4
- package/src/ui/docs/content/kbd.md +2 -1
- package/src/ui/docs/content/mcp.md +10 -4
- package/src/ui/docs/content/menu.md +27 -0
- package/src/ui/docs/content/page.md +19 -5
- package/src/ui/docs/content/pagination.md +9 -2
- package/src/ui/docs/content/popover.md +2 -2
- package/src/ui/docs/content/presentation.md +46 -45
- package/src/ui/docs/content/progress.md +2 -6
- package/src/ui/docs/content/runtime.md +8 -5
- package/src/ui/docs/content/scheduler.md +1 -1
- package/src/ui/docs/content/select.md +13 -8
- package/src/ui/docs/content/sidebar.md +3 -2
- package/src/ui/docs/content/skeleton.md +1 -1
- package/src/ui/docs/content/slider.md +4 -4
- package/src/ui/docs/content/spinner.md +3 -3
- package/src/ui/docs/content/tabs.md +6 -6
- package/src/ui/docs/content/testing.md +4 -2
- package/src/ui/docs/content/toast.md +3 -5
- package/src/ui/docs/content/toggle.md +37 -0
- package/src/ui/docs/content/tooltip.md +4 -3
- package/src/ui/docs/content/truncate.md +3 -2
- package/src/ui/docs/content/ui.md +3 -1
- package/src/ui/docs/content/upgrading.md +43 -13
- package/src/ui/docs/doc-client.tsx +1 -1
- package/src/ui/docs/registry.tsx +30 -5
- package/src/ui/meta.ts +4 -4
|
@@ -19,8 +19,9 @@ superfície apenas no hover, preservando o fundo da região onde o botão está
|
|
|
19
19
|
`size` usa a escala única dos controles: o mesmo nome tem a mesma medida em `Button`, `Select`,
|
|
20
20
|
`Tabs`, `Toggle`, `Switch`, `Avatar`, `Spinner` e nos botões embutidos. Os tamanhos de texto dão a
|
|
21
21
|
altura da linha; os `icon-*` são quadrados para botões só de ícone, que exigem `aria-label` porque não
|
|
22
|
-
há texto visível. O glifo dentro do controle acompanha o tamanho (0.875rem em `xs
|
|
23
|
-
`
|
|
22
|
+
há texto visível. O glifo dentro do controle acompanha o tamanho (0.875rem em `xs`, `sm`,
|
|
23
|
+
`icon-xs`, `icon-sm` e `icon`; 1rem em `default`; 1.25rem em `lg` e `icon-lg`), a menos que o
|
|
24
|
+
ícone traga um `size-*` próprio. O quadrado `icon` mantém a área de 2.25rem com o glifo discreto.
|
|
24
25
|
|
|
25
26
|
| Nome | Medida | Uso |
|
|
26
27
|
| --------- | ------- | -------------------------------------------------------------------------------------------------------------------------------- |
|
|
@@ -36,8 +37,12 @@ há texto visível. O glifo dentro do controle acompanha o tamanho (0.875rem em
|
|
|
36
37
|
Escolha o tamanho pela região, não pela importância visual: `variant` e `context` resolvem a
|
|
37
38
|
hierarquia da ação. Headers de Page e footers de Dialog/Drawer usam `default`; ações operacionais
|
|
38
39
|
de seção, toolbar e coleção usam `sm`; ações dentro de linha ou célula usam `xs` ou `icon-xs`.
|
|
39
|
-
|
|
40
|
-
|
|
40
|
+
Assim a mesma decisão mantém a mesma altura mesmo quando uma superfície troca uma ação secundária
|
|
41
|
+
por uma primária.
|
|
42
|
+
|
|
43
|
+
O retorno de `PageBack` usa `icon`. O fechamento de Dialog e Drawer é um `CloseButton` circular
|
|
44
|
+
(`shape="pill"`), `neutral` e `subtle`, no quadrado `icon-sm` por padrão, ou `icon-xs` com
|
|
45
|
+
`closeSize="xs"`.
|
|
41
46
|
|
|
42
47
|
```tsx preview
|
|
43
48
|
<Button size="xs">Mínimo</Button>
|
|
@@ -80,9 +85,10 @@ buttonVariants serve para o caso sem filho único.
|
|
|
80
85
|
|
|
81
86
|
| Propriedade | Tipo | Padrão | Descrição |
|
|
82
87
|
| ----------- | ------------------------------------------------------------------------------------ | ----------- | ------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
83
|
-
| `context` | `'neutral' \| 'primary' \| 'danger'` | `'primary'` | A hierarquia ou o risco comunicado pela ação.
|
|
88
|
+
| `context` | `'neutral' \| 'primary' \| 'danger'` | `'primary'` em `solid` e `subtle`; `'neutral'` nas demais variantes | A hierarquia ou o risco comunicado pela ação. |
|
|
84
89
|
| `variant` | `'solid' \| 'subtle' \| 'outline' \| 'ghost' \| 'link'` | `'solid'` | O tratamento visual aplicado ao contexto. |
|
|
85
90
|
| `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`. |
|
|
91
|
+
| `shape` | `'default' \| 'pill'` | `'default'` | Geometria do botão; `pill` arredonda as extremidades por completo. |
|
|
86
92
|
| `asChild` | `boolean` | `false` | Renderiza como o filho (Radix Slot) em vez de `<button>` — para âncoras e afins. |
|
|
87
93
|
| `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). |
|
|
88
94
|
| `icon` | `React.ReactNode` | | Ícone à esquerda, como nó (ex.: `icon={<Plus />}`); o glifo segue o `size`. No busy é trocado pelo Spinner — não soma. |
|
|
@@ -115,12 +121,30 @@ conectar bordas. Esse modo atende ações icon-only em barras e linhas de listag
|
|
|
115
121
|
<Button variant="ghost" size="icon" aria-label="Exibição">
|
|
116
122
|
<SlidersHorizontal />
|
|
117
123
|
</Button>
|
|
118
|
-
<Button
|
|
119
|
-
<
|
|
124
|
+
<Button variant="ghost" size="icon" aria-label="Exportar">
|
|
125
|
+
<Download />
|
|
120
126
|
</Button>
|
|
121
127
|
</ButtonGroup>
|
|
122
128
|
```
|
|
123
129
|
|
|
130
|
+
### No rodapé de Dialog e Drawer
|
|
131
|
+
|
|
132
|
+
`DialogFooter` e `DrawerFooter` cuidam somente da faixa; envolva as decisões em um
|
|
133
|
+
`ButtonGroup mode="spaced"`, que responde pelo agrupamento e pela distribuição. Por padrão, as
|
|
134
|
+
ações preservam a largura do conteúdo e `Cancelar` usa `ghost`. Use `distribution="equal"` somente
|
|
135
|
+
quando as duas decisões tiverem peso equivalente; nesse caso, `Cancelar` usa `outline`.
|
|
136
|
+
|
|
137
|
+
```tsx
|
|
138
|
+
<DialogFooter>
|
|
139
|
+
<ButtonGroup mode="spaced">
|
|
140
|
+
<DialogClose asChild>
|
|
141
|
+
<Button variant="ghost">Cancelar</Button>
|
|
142
|
+
</DialogClose>
|
|
143
|
+
<Button>Salvar</Button>
|
|
144
|
+
</ButtonGroup>
|
|
145
|
+
</DialogFooter>
|
|
146
|
+
```
|
|
147
|
+
|
|
124
148
|
### Ação dividida
|
|
125
149
|
|
|
126
150
|
Combine a ação principal, um separador e um botão de ícone quando o mesmo comando oferecer
|
|
@@ -67,7 +67,7 @@ captionLayout=dropdown troca o título do mês por seletores de mês e ano — b
|
|
|
67
67
|
| `locale` | `Locale` | `ptBR` | Idioma dos nomes de mês e de dia (um locale do date-fns). |
|
|
68
68
|
| `labels` | `Partial<Labels>` | rótulos em pt-BR | Rótulos acessíveis da navegação e dos seletores; mescla sobre o padrão. |
|
|
69
69
|
|
|
70
|
-
## CalendarDayButton
|
|
70
|
+
## Personalizar o dia com CalendarDayButton
|
|
71
71
|
|
|
72
72
|
Cada dia é um `CalendarDayButton` — um `Button` ghost quadrado que recebe os modificadores do
|
|
73
73
|
dia (`selected`, `range-start`, `today`…). Use `components={{ DayButton: … }}` para
|
|
@@ -72,4 +72,4 @@ Para painel com estrutura: cada slot é dono do próprio padding (como o Dialog)
|
|
|
72
72
|
| Propriedade | Tipo | Padrão | Descrição |
|
|
73
73
|
|---|---|---|---|
|
|
74
74
|
| `asChild` | `boolean` | `false` | Renderiza o filho com a superfície do Card (ex.: um `<button>` clicável inteiro). |
|
|
75
|
-
| `className` | `string` | | Compõe sobre a superfície; os slots (`CardHeader`, `CardBody`, `
|
|
75
|
+
| `className` | `string` | | Compõe sobre a superfície; os slots (`CardHeader`, `CardBody`, `CardFooter`, `CardAction`) são donos do próprio padding. `CardContent` é alias depreciado de `CardBody`. |
|
|
@@ -79,12 +79,23 @@ orientation=vertical empilha os slides; as setas migram para cima e para baixo (
|
|
|
79
79
|
| Propriedade | Tipo | Padrão | Descrição |
|
|
80
80
|
|---|---|---|---|
|
|
81
81
|
| `orientation` | `'horizontal' \| 'vertical'` | `'horizontal'` | Eixo do deslocamento. No modo vertical, os slides são empilhados e as setas apontam para cima e para baixo. |
|
|
82
|
-
| `opts` | `
|
|
83
|
-
| `setApi` | `(api:
|
|
84
|
-
| `plugins` | `
|
|
82
|
+
| `opts` | `EmblaOptionsType` | | Opções repassadas ao Embla, como `{ loop: true }` ou `{ align: 'start' }`. O Opus não reexporta esse tipo; para nomeá-lo sem depender de `embla-carousel`, use `React.ComponentProps<typeof Carousel>['opts']`. |
|
|
83
|
+
| `setApi` | `(api: EmblaCarouselType \| undefined) => void` | | Recebe a instância do Embla para controle externo, como navegar com `scrollTo` ou ler o slide ativo. |
|
|
84
|
+
| `plugins` | `EmblaPluginType[]` | | Plugins do Embla associados ao carrossel, como autoplay. |
|
|
85
85
|
|
|
86
86
|
## Propriedades de CarouselItem
|
|
87
87
|
|
|
88
88
|
| Propriedade | Tipo | Padrão | Descrição |
|
|
89
89
|
|---|---|---|---|
|
|
90
90
|
| `className` | `string` | | Classes de dimensão; a base define quantos slides cabem na área visível. |
|
|
91
|
+
|
|
92
|
+
## Propriedades de CarouselPrevious e CarouselNext
|
|
93
|
+
|
|
94
|
+
Além das props abaixo, as setas aceitam as props de `Button`. O nome acessível já vem pronto:
|
|
95
|
+
“Slide anterior” e “Próximo slide”. O clique e o estado desabilitado acompanham a posição do trilho.
|
|
96
|
+
|
|
97
|
+
| Propriedade | Tipo | Padrão | Descrição |
|
|
98
|
+
|---|---|---|---|
|
|
99
|
+
| `variant` | `ButtonProps['variant']` | `'outline'` | Tratamento visual da seta. |
|
|
100
|
+
| `size` | `ButtonProps['size']` | `'icon'` | Escala do botão. A seta aplica `size-8 rounded-full` por cima da escala, então o círculo mede 2rem; use `className` para outra medida. |
|
|
101
|
+
| `className` | `string` | | Classes adicionais, como ajustar a posição fora do trilho. |
|
|
@@ -58,7 +58,7 @@ async function chatRoute(req) {
|
|
|
58
58
|
<Chat send={async (messages) => (await api.post('/chat', { messages })).reply} />
|
|
59
59
|
```
|
|
60
60
|
|
|
61
|
-
O
|
|
61
|
+
O agente só executa actions marcadas com `ai.enabled` e, nelas, aplica o `authorize` com o contexto do usuário; uma action sem `authorize` fica aberta a qualquer usuário autenticado. Actions com `ai.destructive` ou `ai.requiresConfirmation` são recusadas nesse exemplo, porque ele não passa `confirm`; para aprovar essas chamadas, use `run(messages, { confirm })`. Para expor as actions ao agente, marque-as com `ai: { enabled: true }` no contrato — ver o recurso **IA generativa**.
|
|
62
62
|
|
|
63
63
|
## Streaming — eventos de conversa
|
|
64
64
|
|
|
@@ -20,9 +20,11 @@ opus db check # drift entidade ↔ banco (read-only)
|
|
|
20
20
|
opus seed check # bindings, dependências, ciclos e scripts paralelos de seed
|
|
21
21
|
```
|
|
22
22
|
|
|
23
|
-
`opus check` lê o source sem executar nada e aplica
|
|
24
|
-
(`action-name`, `kind`, `field-order`, `export`, `requires-sem-authorize`)
|
|
25
|
-
(`ui-structure`, `ui-semantic-api`, `removed-ui-token`, `unpaired-ui-surface`)
|
|
23
|
+
`opus check` lê o source sem executar nada e aplica regras em três grupos: actions
|
|
24
|
+
(`action-name`, `kind`, `field-order`, `export`, `requires-sem-authorize`), UI
|
|
25
|
+
(`ui-structure`, `ui-semantic-api`, `removed-ui-token`, `unpaired-ui-surface`) e Produtos de Dados
|
|
26
|
+
(`data-product-export`, `-id`, `-duplicate`, `-version`, `-interfaces`, `-interface`, `-entities`
|
|
27
|
+
e `-entity`, todas com o prefixo `data-product`). Um projeto
|
|
26
28
|
marcado com `opus.json` e ainda sem actions passa vacuamente; sem o marcador, zero actions
|
|
27
29
|
falha, porque um gate vazio não é aprovação. `opus check --help` descreve cada regra.
|
|
28
30
|
|
|
@@ -43,15 +45,19 @@ opus pre-push materialization # só a freshness dos artefatos materializados
|
|
|
43
45
|
## Seeds de desenvolvimento e teste
|
|
44
46
|
|
|
45
47
|
> Seeds registrados no `opus.config.ts` têm perfis, métricas e escopos explícitos. Listagem e gate
|
|
46
|
-
> não abrem o banco; planejamento, aplicação e verificação
|
|
48
|
+
> não abrem o banco; planejamento, aplicação e verificação só conectam com
|
|
49
|
+
> `NODE_ENV=development` ou `NODE_ENV=test`.
|
|
47
50
|
|
|
48
51
|
```bash
|
|
49
52
|
opus seed list
|
|
50
|
-
opus seed plan customers.scenarios --profile smoke --scope local
|
|
51
|
-
opus seed apply customers.scenarios --profile smoke --scope local
|
|
52
|
-
opus seed verify customers.scenarios --profile smoke --scope local
|
|
53
|
+
NODE_ENV=development opus seed plan customers.scenarios --profile smoke --scope local
|
|
54
|
+
NODE_ENV=development opus seed apply customers.scenarios --profile smoke --scope local
|
|
55
|
+
NODE_ENV=development opus seed verify customers.scenarios --profile smoke --scope local
|
|
53
56
|
```
|
|
54
57
|
|
|
58
|
+
Com qualquer outro valor de `NODE_ENV`, inclusive ausente, esses três comandos falham antes de
|
|
59
|
+
abrir a conexão. O escopo informado também precisa constar em `safety.scopes` do seed.
|
|
60
|
+
|
|
55
61
|
`--profile` escolhe o perfil (default: o `defaultProfile` do seed) e `--scope` declara o escopo
|
|
56
62
|
dos dados (a variável `OPUS_SEED_SCOPE` é a alternativa). `--json` devolve o resultado
|
|
57
63
|
estruturado, inclusive em caso de erro. `apply` converge quando repetido; não há reset ou
|
|
@@ -49,14 +49,36 @@ render(
|
|
|
49
49
|
)
|
|
50
50
|
```
|
|
51
51
|
|
|
52
|
+
## Propriedades de Command
|
|
53
|
+
|
|
54
|
+
| Propriedade | Tipo | Padrão | Descrição |
|
|
55
|
+
|---|---|---|---|
|
|
56
|
+
| `shouldFilter` | `boolean` | `true` | Com `false`, desliga a filtragem e a ordenação automáticas; o aplicativo passa a renderizar somente os itens que correspondem à busca. |
|
|
57
|
+
| `filter` | `(value: string, search: string, keywords?: string[]) => number` | | Pontua cada item para a busca atual, de `0` (oculto) a `1` (melhor resultado). |
|
|
58
|
+
| `value` | `string` | | Item destacado no modo controlado. |
|
|
59
|
+
| `onValueChange` | `(value: string) => void` | | Chamado quando o item destacado muda. |
|
|
60
|
+
| `loop` | `boolean` | `false` | Faz as setas voltarem ao início ou ao fim da lista. |
|
|
61
|
+
| `label` | `string` | | Nome acessível do menu, sem exibição visual. |
|
|
62
|
+
| `className` | `string` | | Classes adicionais aplicadas à raiz. |
|
|
63
|
+
|
|
64
|
+
## Propriedades de CommandInput
|
|
65
|
+
|
|
66
|
+
| Propriedade | Tipo | Padrão | Descrição |
|
|
67
|
+
|---|---|---|---|
|
|
68
|
+
| `placeholder` | `string` | | Texto exibido enquanto a busca está vazia. |
|
|
69
|
+
| `value` | `string` | | Texto da busca no modo controlado. |
|
|
70
|
+
| `onValueChange` | `(search: string) => void` | | Chamado quando o texto da busca muda. |
|
|
71
|
+
| `disabled` | `boolean` | `false` | Desabilita o campo de busca. |
|
|
72
|
+
| `className` | `string` | | Classes adicionais aplicadas ao campo; o ícone de busca fica no wrapper. |
|
|
73
|
+
|
|
52
74
|
## Propriedades de CommandDialog
|
|
53
75
|
|
|
54
76
|
| Propriedade | Tipo | Padrão | Descrição |
|
|
55
77
|
|---|---|---|---|
|
|
56
78
|
| `open` | `boolean` | | Estado do modal no modo controlado. |
|
|
57
79
|
| `onOpenChange` | `(open: boolean) => void` | | Atualiza o estado do modal; pode ser conectado ao atalho do aplicativo. |
|
|
58
|
-
| `title` | `string` | `'
|
|
59
|
-
| `description` | `string` | `'Busque um comando para executar
|
|
80
|
+
| `title` | `string` | `'Paleta de comandos'` | Título exibido no header compacto; também nomeia o diálogo para tecnologias assistivas. |
|
|
81
|
+
| `description` | `string` | `'Busque um comando para executar…'` | Descrição disponível somente para tecnologias assistivas. |
|
|
60
82
|
| `showCloseButton` | `boolean` | `true` | Exibe o botão de fechamento. |
|
|
61
83
|
|
|
62
84
|
## Propriedades de CommandItem
|
|
@@ -64,3 +86,13 @@ render(
|
|
|
64
86
|
| Propriedade | Tipo | Padrão | Descrição |
|
|
65
87
|
|---|---|---|---|
|
|
66
88
|
| `onSelect` | `(value: string) => void` | | Chamado ao selecionar o item por clique ou teclado. |
|
|
89
|
+
| `value` | `string` | | Valor estável usado na busca e no destaque. Sem ele, o valor é inferido do texto do item. |
|
|
90
|
+
| `keywords` | `string[]` | | Termos adicionais considerados na busca. |
|
|
91
|
+
| `disabled` | `boolean` | `false` | Impede a seleção do item. |
|
|
92
|
+
|
|
93
|
+
## Propriedades de CommandGroup
|
|
94
|
+
|
|
95
|
+
| Propriedade | Tipo | Padrão | Descrição |
|
|
96
|
+
|---|---|---|---|
|
|
97
|
+
| `heading` | `React.ReactNode` | | Título exibido acima dos itens do grupo. |
|
|
98
|
+
| `value` | `string` | | Identificador do grupo; obrigatório e único quando não há `heading`. |
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
## Envio de texto
|
|
2
2
|
|
|
3
|
-
A caixa de escrever da casa: textarea em uma pílula elevada (`rounded-xl` + `border` + `shadow-sm`), **Enter** envia / **Shift+Enter** quebra linha, enviar dentro. É o composer do [Chat](/
|
|
3
|
+
A caixa de escrever da casa: textarea em uma pílula elevada (`rounded-xl` + `border` + `shadow-sm`), **Enter** envia / **Shift+Enter** quebra linha, enviar dentro. É o composer do [Chat](/ui/chat) extraído — use sozinho quando há entrada de texto mas não um chat (ex.: criar uma sessão). Controlado: o dono do texto é você. Os callbacks opcionais `onHistoryPrevious` e `onHistoryNext` permitem que esse dono consuma **↑/↓**; sem eles, as setas mantêm o comportamento nativo da textarea.
|
|
4
4
|
|
|
5
5
|
```tsx preview col
|
|
6
6
|
const [text, setText] = React.useState('')
|
|
@@ -14,7 +14,7 @@ render(
|
|
|
14
14
|
actions={<Button variant="outline">Encerrar outras sessões</Button>}
|
|
15
15
|
>
|
|
16
16
|
<div className="rounded-lg border border-border p-4">
|
|
17
|
-
MacBook
|
|
17
|
+
MacBook Pro · ativo agora
|
|
18
18
|
</div>
|
|
19
19
|
</Content>,
|
|
20
20
|
);
|
|
@@ -40,7 +40,7 @@ render(
|
|
|
40
40
|
</ContentHeader>
|
|
41
41
|
<ContentBody>
|
|
42
42
|
<div className="rounded-lg border border-border p-4">
|
|
43
|
-
MacBook
|
|
43
|
+
MacBook Pro · ativo agora
|
|
44
44
|
</div>
|
|
45
45
|
</ContentBody>
|
|
46
46
|
</Content>,
|
|
@@ -57,7 +57,8 @@ Quando a região principal da página é uma coleção, `Content` nomeia e gover
|
|
|
57
57
|
`ContentActions`. Busca, filtros, atualização e operações dependentes do recorte atual permanecem na
|
|
58
58
|
toolbar da lista. Essa divisão aproxima cada comando do objeto que ele afeta sem criar uma família
|
|
59
59
|
paralela de componentes `List*`. Na variante `page`, as ações ficam no extremo oposto ao título. A
|
|
60
|
-
criação usa um
|
|
60
|
+
criação usa um `Button` textual na variante padrão (`solid`) e no tamanho `default`, sem ícone,
|
|
61
|
+
nomeado `Criar recurso`; o diálogo aberto pelo
|
|
61
62
|
gatilho repete esse título e a edição usa `Editar recurso`.
|
|
62
63
|
|
|
63
64
|
## Propriedades de Content
|
|
@@ -68,7 +69,7 @@ gatilho repete esse título e a edição usa `Editar recurso`.
|
|
|
68
69
|
| `count` | `number` | | Forma curta: total de itens ao lado do título da região. |
|
|
69
70
|
| `description` | `ReactNode` | | Forma curta: frase de apoio sob o título. |
|
|
70
71
|
| `actions` | `ReactNode` | | Forma curta: ações sobre a região inteira; em `page`, ficam no extremo oposto ao título. |
|
|
71
|
-
| `level` | `1 \| 2 \| 3 \| 4 \| 5 \| 6` |
|
|
72
|
+
| `level` | `1 \| 2 \| 3 \| 4 \| 5 \| 6` | `2` | Nível semântico do heading, independente do destaque visual. |
|
|
72
73
|
| `variant` | `'page' \| 'section'` | `'section'` | Hierarquia visual: `page` reproduz o cabeçalho de `Page`; `section` é a região dentro de uma superfície. |
|
|
73
74
|
|
|
74
75
|
Na composição explícita, `ContentHeader` recebe `ContentTitle`, `ContentMeta`, `ContentDescription` e
|
|
@@ -116,7 +116,7 @@ const [open, setOpen] = useState(false)
|
|
|
116
116
|
|
|
117
117
|
## O limite — de propósito
|
|
118
118
|
|
|
119
|
-
> O look curado não é customizável no app: rodapé-faixa do dialog, elevação no dark, `active:
|
|
119
|
+
> O look curado não é customizável no app: rodapé-faixa do dialog, elevação no dark, `active:brightness-90`
|
|
120
120
|
> do botão, a seta do tooltip — é identidade da casa, igual em todo projeto.
|
|
121
121
|
|
|
122
122
|
```tsx preview
|
|
@@ -4,12 +4,14 @@ O Opus cresce por **reincidência, nunca por especulação**. Quando o mesmo com
|
|
|
4
4
|
|
|
5
5
|
## Onde você aponta
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
Cada apontamento vira uma Issue no repositório do Opus. Antes de abrir, procure uma Issue existente para o mesmo comportamento e comente nela. Dois tipos:
|
|
8
8
|
|
|
9
9
|
- **`enhancement`** — código genérico que o Opus deveria ganhar (serviria a qualquer projeto). Antes de apontar, confira o que o Opus já tem (o inventário de componentes, os exports, esta doc): se já existe, use.
|
|
10
10
|
- **`bug`** — um defeito ou limitação no próprio Opus, achado usando-o.
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
Descreva cada apontamento com estes campos — um exemplo de cada tipo:
|
|
13
|
+
|
|
14
|
+
```text
|
|
13
15
|
{"type": "enhancement", "behavior": "o comportamento em uma frase.", "file": "src/onde-vive.ts", "kind": "ui|sdk|driver|infra"}
|
|
14
16
|
{"type": "bug", "behavior": "o que quebra ou falta.", "file": "onde se manifesta.", "note": "repro + o workaround aplicado."}
|
|
15
17
|
```
|
|
@@ -20,15 +22,15 @@ O ponto do ciclo é **não bloquear a entrega**. Bateu em um gap ou em um bug do
|
|
|
20
22
|
|
|
21
23
|
1. **Contorne local** — componha um wrapper no seu projeto. O Opus entrega _source_, então dá para embrulhar qualquer superfície dele. Nunca edite `node_modules` (some no próximo install).
|
|
22
24
|
2. **Entregue** a feature com o workaround.
|
|
23
|
-
3. **Aponte**
|
|
25
|
+
3. **Aponte** na Issue e siga em frente.
|
|
24
26
|
|
|
25
27
|
O "depois" — o conserto no Opus — corre em paralelo. Ele não segura o seu trabalho; o único custo de demorar é o workaround viver um pouco mais.
|
|
26
28
|
|
|
27
29
|
## Como fecha
|
|
28
30
|
|
|
29
|
-
|
|
31
|
+
A triagem acontece em uma **Issue em [github.com/softize-dev/opus](https://github.com/softize-dev/opus/issues)**; procure uma existente antes de abrir. O pacote não coleta apontamentos do seu projeto por conta própria. O desfecho depende do tipo:
|
|
30
32
|
|
|
31
|
-
- **Enhancement** aceito (com reincidência) → implementado no Opus → sai em um _bump_ → seu projeto atualiza o
|
|
33
|
+
- **Enhancement** aceito (com reincidência) → implementado no Opus → sai em um _bump_ → seu projeto [atualiza o Opus](upgrading) e troca o workaround pelo import.
|
|
32
34
|
- **Bug** → vira _fix_ + entrada no `CHANGELOG` → no _bump_, o workaround sai.
|
|
33
35
|
|
|
34
36
|
A régua e a decisão ficam com quem mantém o Opus — hoje, a **Softize**. O registro curado das promoções vive no `PROMOTED.md` do pacote.
|
|
@@ -15,7 +15,7 @@ e o tooltip dessa ação. Para uma ação em andamento depois do clique, use `bu
|
|
|
15
15
|
<DataState empty emptyMessage="Nenhum papel.">
|
|
16
16
|
<div />
|
|
17
17
|
</DataState>
|
|
18
|
-
<DataState error={{ message: 'detalhe técnico
|
|
18
|
+
<DataState error={{ message: 'detalhe técnico que não aparece na tela' }} onRetry={() => undefined}>
|
|
19
19
|
<div />
|
|
20
20
|
</DataState>
|
|
21
21
|
</div>
|
|
@@ -28,15 +28,15 @@ tabela continua responsável pela borda: o `Empty` dentro dela vem sem moldura.
|
|
|
28
28
|
disponível para criação ou vínculo, use `Empty` diretamente, com a moldura tracejada.
|
|
29
29
|
|
|
30
30
|
```tsx preview col
|
|
31
|
-
<
|
|
32
|
-
<
|
|
31
|
+
<Table variant="framed">
|
|
32
|
+
<TableBody>
|
|
33
33
|
<DataState empty emptyMessage="Nenhum usuário." colSpan={3}>
|
|
34
34
|
<tr>
|
|
35
35
|
<td />
|
|
36
36
|
</tr>
|
|
37
37
|
</DataState>
|
|
38
|
-
</
|
|
39
|
-
</
|
|
38
|
+
</TableBody>
|
|
39
|
+
</Table>
|
|
40
40
|
```
|
|
41
41
|
|
|
42
42
|
## Propriedades de DataState
|
|
@@ -51,3 +51,4 @@ disponível para criação ou vínculo, use `Empty` diretamente, com a moldura t
|
|
|
51
51
|
| `onRetry` | `() => void \| Promise<void>` | | Recuperação: mostra a ação de tentar de novo somente com ícone no estado de erro. |
|
|
52
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). |
|
|
54
|
+
| `children` | `ReactNode` | | Obrigatório. Conteúdo renderizado quando não há erro, carregamento nem vazio. |
|
|
@@ -48,15 +48,15 @@ const db = new Kysely<AdminDB>({
|
|
|
48
48
|
await db.selectFrom('agents').select(['isDefault', 'roleId']).where('workspaceId', '=', id).execute()
|
|
49
49
|
```
|
|
50
50
|
|
|
51
|
-
## Migrações
|
|
51
|
+
## Migrações e seeds
|
|
52
52
|
|
|
53
53
|
Cada etapa possui um papel diferente:
|
|
54
54
|
|
|
55
55
|
- `opus db migrate` — aplica o **schema idempotente** (`config.schema`, um script SQL
|
|
56
56
|
evolutivo: `IF NOT EXISTS` + guards cobrem nascer do zero e upgrade no mesmo artefato)
|
|
57
57
|
e roda o drift-check entidade ↔ banco na sequência (exit ≠ 0 se divergir).
|
|
58
|
-
- `
|
|
59
|
-
|
|
58
|
+
- `opus seed` — aplica datasets de desenvolvimento e teste declarados com `defineSeed` e registrados
|
|
59
|
+
no `opus.config.ts`; só conecta com `NODE_ENV=development` ou `test`. Ver [CLI opus](cli).
|
|
60
60
|
|
|
61
61
|
## Campos JSON
|
|
62
62
|
|
|
@@ -38,7 +38,8 @@ React substitui a apresentação. `0` e `false` seguem como valores. Ver `EmptyV
|
|
|
38
38
|
|
|
39
39
|
## Moldura e divisórias internas
|
|
40
40
|
|
|
41
|
-
`variant="framed"` adiciona a
|
|
41
|
+
`variant="framed"` adiciona a borda externa sem preencher o fundo; na orientação horizontal, só a
|
|
42
|
+
coluna de rótulos recebe um fundo sutil. `dividers` desenha apenas as
|
|
42
43
|
divisórias internas; as duas opções são independentes e podem ser combinadas. `orientation`
|
|
43
44
|
define se a chave fica sobre o valor ou ao lado dele. Na orientação horizontal, todos os valores
|
|
44
45
|
começam depois da mesma coluna de rótulo, com largura padrão de `7rem` em grupos simples e
|
|
@@ -62,7 +63,7 @@ começam depois da mesma coluna de rótulo, com largura padrão de `7rem` em gru
|
|
|
62
63
|
|
|
63
64
|
| Propriedade | Tipo | Padrão | Descrição |
|
|
64
65
|
|---|---|---|---|
|
|
65
|
-
| `variant` | `'plain' \| 'framed'` | `'plain'` | `framed` aplica a
|
|
66
|
+
| `variant` | `'plain' \| 'framed'` | `'plain'` | `framed` aplica a moldura canônica ao conjunto, com fundo transparente; na orientação horizontal, a coluna de rótulos recebe fundo sutil. |
|
|
66
67
|
| `dividers` | `boolean` | `false` | Hairlines somente entre os campos, sem exigir moldura externa. |
|
|
67
68
|
| `columns` | `1 \| 2 \| 3 \| 4 \| 'auto'` | `1` | Número fixo de colunas ou distribuição automática por largura mínima. |
|
|
68
69
|
| `orientation` | `'vertical' \| 'horizontal'` | `'vertical'` | Chave sobre o valor ou ao lado dele em cada campo. |
|
|
@@ -37,7 +37,7 @@ distinta da página.
|
|
|
37
37
|
<DialogClose asChild>
|
|
38
38
|
<Button variant="ghost">Cancelar</Button>
|
|
39
39
|
</DialogClose>
|
|
40
|
-
<Button>
|
|
40
|
+
<Button>Salvar</Button>
|
|
41
41
|
</ButtonGroup>
|
|
42
42
|
</DialogFooter>
|
|
43
43
|
</DialogContent>
|
|
@@ -149,7 +149,7 @@ confirmações e prompts distribuem confirmar e cancelar em duas colunas.
|
|
|
149
149
|
Em `dialog.choose`, declare pelo menos uma ação e marque exatamente uma ação habilitada com
|
|
150
150
|
`initialFocus`. Essa ação representa a saída segura. Os valores de `result` precisam ser únicos.
|
|
151
151
|
Por padrão, a última ação recebe contexto primário e variante sólida; as anteriores usam contexto
|
|
152
|
-
neutro e variante
|
|
152
|
+
neutro e variante outline. Defina `context` ou `variant` na própria ação para substituir o padrão.
|
|
153
153
|
|
|
154
154
|
### Montar o host
|
|
155
155
|
|
|
@@ -120,7 +120,7 @@ resultado é vazio e a resolução cai na meta do `t.dict` que viaja no schema.
|
|
|
120
120
|
| `dict` | `DictType \| LogicalTypeMeta \| DictionaryDescriptor` | — | O dicionário (`t.dict`), a meta lida do schema ou um descritor normalizado. |
|
|
121
121
|
| `value` | `string \| null \| undefined` | — | O código. Vazio renderiza `fallback`. |
|
|
122
122
|
| `presentation` | `'classification' \| 'status' \| 'stage' \| 'plain'` | do dicionário | Sobrepõe o papel só nesta ocorrência. |
|
|
123
|
-
| `context` | contexto de `Badge` | pelo dicionário | Sobrepõe o significado semântico
|
|
123
|
+
| `context` | contexto de `Badge` | pelo dicionário | Sobrepõe o significado semântico quando a ocorrência já é badge; sozinho, não promove texto a badge. |
|
|
124
124
|
| `variant` | variante de `Badge` | pelo papel | Sobrepõe a variante e promove texto a badge. |
|
|
125
125
|
| `icon` | `boolean \| ReactNode` | `true` | `false` esconde o ícone declarado; um nó substitui. |
|
|
126
126
|
| `icons` | `Record<string, LucideIcon>` | `iconPickerIcons` | Catálogo nome → componente. |
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
# Dock
|
|
2
|
-
|
|
3
1
|
Ferramentas ancoradas à superfície de trabalho. Um canvas ou um editor raramente comporta mais
|
|
4
2
|
uma faixa de chrome no topo: a trilha da aplicação já ocupa esse papel, e um segundo cabeçalho
|
|
5
3
|
empilha duas faixas com a mesma função. A Dock coloca as ações sobre a própria superfície,
|
|
@@ -63,10 +61,33 @@ A barra é uma `toolbar`: as setas andam entre as ações e Home/End vão às po
|
|
|
63
61
|
por tooltip, então `<TooltipProvider>` precisa existir na raiz do app — o esqueleto do `opus create`
|
|
64
62
|
já monta.
|
|
65
63
|
|
|
64
|
+
## Propriedades de Dock
|
|
65
|
+
|
|
66
66
|
| Propriedade | Tipo | Padrão | Descrição |
|
|
67
67
|
| --- | --- | --- | --- |
|
|
68
68
|
| `position` | `'bottom' \| 'bottom-left' \| 'bottom-right'` | `'bottom'` | Aresta do contêiner onde a barra se ancora. |
|
|
69
69
|
| `label` | `string` | | Nome acessível da barra. |
|
|
70
|
+
| `children` | `ReactNode` | | Os grupos de ações, em `DockGroup`. |
|
|
71
|
+
| `className` | `string` | | Classes adicionais da barra. |
|
|
72
|
+
|
|
73
|
+
## Propriedades de DockGroup
|
|
74
|
+
|
|
75
|
+
| Propriedade | Tipo | Padrão | Descrição |
|
|
76
|
+
| --- | --- | --- | --- |
|
|
77
|
+
| `children` | `ReactNode` | | As ações do grupo, em `DockAction`. A divisória antes do grupo é aplicada automaticamente, exceto no primeiro. |
|
|
78
|
+
| `className` | `string` | | Classes adicionais do grupo. |
|
|
79
|
+
|
|
80
|
+
## Propriedades de DockAction
|
|
81
|
+
|
|
82
|
+
| Propriedade | Tipo | Padrão | Descrição |
|
|
83
|
+
| --- | --- | --- | --- |
|
|
84
|
+
| `icon` | `ReactNode` | | Ícone exibido no botão. |
|
|
85
|
+
| `label` | `string` | | Nome da ação; vira o nome acessível e o tooltip quando não há `hint`. |
|
|
86
|
+
| `pressed` | `boolean` | | Presente quando a ação liga um modo: aplica o preenchimento e expõe `aria-pressed`. Ausente quando a ação apenas executa. |
|
|
87
|
+
| `disabled` | `boolean` | `false` | Desabilita a ação e a tira da navegação por setas. |
|
|
88
|
+
| `hint` | `ReactNode` | `label` | Conteúdo do tooltip quando ele precisa dizer mais que o rótulo. |
|
|
89
|
+
| `onClick` | `() => void` | | Executa a ação ou alterna o modo. |
|
|
90
|
+
| `className` | `string` | | Classes adicionais do botão. |
|
|
70
91
|
|
|
71
92
|
## Propriedades de SurfaceStatus
|
|
72
93
|
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
# Dot
|
|
2
|
-
|
|
3
1
|
Indicador visual compacto para estados que já têm contexto. O tamanho permanece fixo; `context`
|
|
4
2
|
seleciona o significado e `variant` escolhe ponto sólido ou contornado. Quando a cor reforça significado, `label` fornece o nome
|
|
5
3
|
acessível. Sem `label`, o ponto é decorativo.
|
|
@@ -11,7 +11,7 @@ entra pela direita e pode ser fechado por Esc, pelo overlay ou pelo botão de fe
|
|
|
11
11
|
</DrawerTrigger>
|
|
12
12
|
<DrawerContent side="right">
|
|
13
13
|
<DrawerHeader>
|
|
14
|
-
<DrawerTitle>
|
|
14
|
+
<DrawerTitle>Criar ticket</DrawerTitle>
|
|
15
15
|
</DrawerHeader>
|
|
16
16
|
<DrawerBody className="text-sm text-muted-foreground">
|
|
17
17
|
<p>Ação · domínio Suporte</p>
|
|
@@ -46,7 +46,7 @@ const runtime = createRuntime({
|
|
|
46
46
|
// No handler: emite pelo tipo declarado; o core preenche id/timestamp/actor/source.
|
|
47
47
|
handler: async (ctx, input) => {
|
|
48
48
|
const nota = await repo.create(input)
|
|
49
|
-
ctx.emit('nota.emitida', { id: nota.id, valor: nota.valor })
|
|
49
|
+
await ctx.emit('nota.emitida', { id: nota.id, valor: nota.valor })
|
|
50
50
|
return nota
|
|
51
51
|
}
|
|
52
52
|
```
|
|
@@ -1,29 +1,33 @@
|
|
|
1
1
|
## Campo empilhado
|
|
2
2
|
|
|
3
3
|
Use `Field` para manter rótulo, controle, ajuda e erro com espaçamento consistente. Na orientação
|
|
4
|
-
vertical, `FieldLabel
|
|
5
|
-
|
|
4
|
+
vertical, `FieldLabel` e o controle ficam empilhados. A ajuda fica junto ao rótulo, com `LabelHelp`,
|
|
5
|
+
o mesmo ícone que o `ActionForm` usa para `FieldSpec.help`. Use `FieldDescription` somente quando a
|
|
6
|
+
frase precisar ficar visível o tempo todo abaixo do controle.
|
|
6
7
|
|
|
7
8
|
```tsx preview col md
|
|
8
9
|
<Field>
|
|
9
|
-
<FieldLabel htmlFor="workspace-slug"
|
|
10
|
+
<FieldLabel htmlFor="workspace-slug" className="items-center gap-1.5">
|
|
11
|
+
<span>Slug do workspace</span>
|
|
12
|
+
<LabelHelp help="Vira o subdomínio do preview: empresa-x.preview.softize.com.br." />
|
|
13
|
+
</FieldLabel>
|
|
10
14
|
<Input id="workspace-slug" defaultValue="empresa-x" />
|
|
11
|
-
<FieldDescription>Vira o subdomínio do preview: empresa-x.preview.softize.com.br.</FieldDescription>
|
|
12
15
|
</Field>
|
|
13
16
|
```
|
|
14
17
|
|
|
15
18
|
## Horizontal com toggle
|
|
16
19
|
|
|
17
20
|
`orientation="horizontal"` posiciona o controle ao lado do texto. `FieldContent` agrupa título e
|
|
18
|
-
descrição; `FieldTitle`
|
|
21
|
+
descrição; `FieldTitle` exibe o título quando o texto não puder ser um `<label>`. Como ele não se
|
|
22
|
+
vincula ao controle, ligue-o ao controle por `aria-labelledby` para manter o nome acessível.
|
|
19
23
|
|
|
20
24
|
```tsx preview col md
|
|
21
25
|
<Field orientation="horizontal">
|
|
22
26
|
<FieldContent>
|
|
23
|
-
<FieldTitle>Acionar o revisor no handoff</FieldTitle>
|
|
27
|
+
<FieldTitle id="auto-review-title">Acionar o revisor no handoff</FieldTitle>
|
|
24
28
|
<FieldDescription>Ao abrir o handoff, o agente reviewer entra na sessão automaticamente.</FieldDescription>
|
|
25
29
|
</FieldContent>
|
|
26
|
-
<Switch id="auto-review" defaultChecked />
|
|
30
|
+
<Switch id="auto-review" aria-labelledby="auto-review-title" defaultChecked />
|
|
27
31
|
</Field>
|
|
28
32
|
```
|
|
29
33
|
|
|
@@ -31,21 +35,25 @@ descrição; `FieldTitle` nomeia o campo quando o texto não puder ser um `<labe
|
|
|
31
35
|
|
|
32
36
|
`FieldSet` agrupa campos sob uma `FieldLegend`; `FieldGroup` define o espaçamento e
|
|
33
37
|
`FieldSeparator` marca uma divisão. `FieldError` aparece somente quando existe mensagem de erro.
|
|
38
|
+
Declare `data-invalid="true"` no `Field` para que o rótulo acompanhe o contexto de erro;
|
|
39
|
+
`aria-invalid` marca apenas o controle. O `ActionForm` define os dois atributos sozinho.
|
|
34
40
|
|
|
35
41
|
```tsx preview col md
|
|
36
42
|
<FieldSet>
|
|
37
43
|
<FieldLegend>Novo agente</FieldLegend>
|
|
38
44
|
<FieldGroup>
|
|
39
|
-
<Field>
|
|
45
|
+
<Field data-invalid="true">
|
|
40
46
|
<FieldLabel htmlFor="agent-name">Nome</FieldLabel>
|
|
41
47
|
<Input id="agent-name" defaultValue="" aria-invalid placeholder="Ex.: developer" />
|
|
42
48
|
<FieldError>Informe um nome para o agente.</FieldError>
|
|
43
49
|
</Field>
|
|
44
50
|
<FieldSeparator />
|
|
45
51
|
<Field>
|
|
46
|
-
<FieldLabel htmlFor="agent-prompt">
|
|
52
|
+
<FieldLabel htmlFor="agent-prompt" className="items-center gap-1.5">
|
|
53
|
+
<span>Prompt</span>
|
|
54
|
+
<LabelHelp help="A síntese vira a primeira mensagem da sessão." />
|
|
55
|
+
</FieldLabel>
|
|
47
56
|
<Textarea id="agent-prompt" rows={3} defaultValue="Veste o papel de developer no workspace Empresa X." />
|
|
48
|
-
<FieldDescription>A síntese vira a primeira mensagem da sessão.</FieldDescription>
|
|
49
57
|
</Field>
|
|
50
58
|
</FieldGroup>
|
|
51
59
|
</FieldSet>
|
|
@@ -56,6 +64,7 @@ descrição; `FieldTitle` nomeia o campo quando o texto não puder ser um `<labe
|
|
|
56
64
|
| Propriedade | Tipo | Padrão | Descrição |
|
|
57
65
|
|---|---|---|---|
|
|
58
66
|
| `orientation` | `'vertical' \| 'horizontal' \| 'responsive'` | `'vertical'` | Direção fixa do campo. `responsive` permanece como alias compatível de `horizontal`. |
|
|
67
|
+
| `data-invalid` | `boolean \| 'true' \| 'false'` | | Com `true`, aplica o contexto de erro ao campo e ao rótulo. O `ActionForm` define o atributo sozinho. |
|
|
59
68
|
|
|
60
69
|
## Propriedades de FieldLegend
|
|
61
70
|
|
|
@@ -67,7 +76,7 @@ descrição; `FieldTitle` nomeia o campo quando o texto não puder ser um `<labe
|
|
|
67
76
|
|
|
68
77
|
| Propriedade | Tipo | Padrão | Descrição |
|
|
69
78
|
|---|---|---|---|
|
|
70
|
-
| `errors` | `Array<{ message?: string }>` | | Deduplica e apresenta uma lista de erros; sem conteúdo, o componente não renderiza. |
|
|
79
|
+
| `errors` | `Array<{ message?: string } \| undefined>` | | Deduplica e apresenta uma lista de erros; sem conteúdo, o componente não renderiza. |
|
|
71
80
|
| `children` | `ReactNode` | | Mensagem literal, com prioridade sobre `errors`. |
|
|
72
81
|
|
|
73
82
|
## Propriedades de FieldSeparator
|
|
@@ -75,8 +75,10 @@ pnpm add @softize/opus
|
|
|
75
75
|
pnpm add -D @softize/base
|
|
76
76
|
pnpm exec opus setup
|
|
77
77
|
pnpm exec base setup
|
|
78
|
+
```
|
|
78
79
|
|
|
79
|
-
|
|
80
|
+
```css
|
|
81
|
+
/* index.css do app — o tema canônico + os componentes do Opus no scan do Tailwind. */
|
|
80
82
|
@import '@softize/opus/ui/theme.css';
|
|
81
83
|
@source '../node_modules/@softize/opus/src/ui/**/*.{ts,tsx}';
|
|
82
84
|
```
|
|
@@ -111,4 +113,4 @@ await runtime.start()
|
|
|
111
113
|
|
|
112
114
|
- `CLAUDE.md` do repo e do app — o índice local: mapa, gates, gotchas.
|
|
113
115
|
- As `description` das entidades/actions — a spec de negócio, projetada no manifest pelo `opus gen`.
|
|
114
|
-
- Gate de build: `opus check` (convenções das actions) + `opus db check` (drift entidade ↔ banco). Rode antes de entregar.
|
|
116
|
+
- Gate de build: `opus check` (convenções das actions e da UI) + `opus copy --check` e `base copy check` (inventário e política de copy) + `opus db check` (drift entidade ↔ banco). Rode antes de entregar.
|