@softize/opus 18.0.1 → 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 +105 -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/0017-ui-assumes-a-fixed-desktop-layout.md +54 -0
- package/docs/adr/{0012-modal-header-only-names-the-surface.md → 0018-modal-header-only-names-the-surface.md} +4 -1
- package/docs/adr/0019-productive-surfaces-use-compact-density.md +65 -0
- 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/relative-unit-scale.md +9 -2
- package/docs/releasing.md +28 -4
- package/package.json +1 -1
- package/registry/skills/build-opus-ui/references/evaluations.md +3 -1
- package/registry/skills/build-opus-ui/references/ui-patterns.md +20 -4
- package/src/auth/drivers/jwt.ts +2 -1
- package/src/core/runtime.ts +32 -5
- package/src/core/types.ts +16 -7
- package/src/mcp/index.ts +13 -1
- package/src/ui/components/patterns/action-list-dialog.tsx +2 -2
- package/src/ui/components/patterns/content-header.tsx +2 -2
- package/src/ui/components/patterns/form-dialog.tsx +7 -2
- package/src/ui/components/patterns/form.tsx +1 -1
- package/src/ui/components/patterns/list.tsx +239 -47
- package/src/ui/components/patterns/presentation.tsx +7 -5
- package/src/ui/components/patterns/sidebar.tsx +1 -1
- package/src/ui/components/patterns/state-surface.tsx +2 -2
- package/src/ui/components/patterns/surface-header.tsx +4 -4
- package/src/ui/components/primitives/alert.tsx +2 -2
- package/src/ui/components/primitives/breadcrumb.tsx +1 -1
- package/src/ui/components/primitives/button-group.tsx +1 -1
- package/src/ui/components/primitives/button.tsx +3 -3
- package/src/ui/components/primitives/calendar.tsx +1 -1
- package/src/ui/components/primitives/card.tsx +1 -1
- package/src/ui/components/primitives/close-button.tsx +40 -0
- package/src/ui/components/primitives/detail.tsx +68 -30
- package/src/ui/components/primitives/dialog.tsx +36 -21
- package/src/ui/components/primitives/drawer.tsx +26 -19
- package/src/ui/components/primitives/empty-value.tsx +3 -3
- package/src/ui/components/primitives/empty.tsx +1 -1
- package/src/ui/components/primitives/field.tsx +12 -12
- package/src/ui/components/primitives/icon-picker.tsx +1 -1
- package/src/ui/components/primitives/input-group.tsx +1 -1
- package/src/ui/components/primitives/input.tsx +2 -2
- package/src/ui/components/primitives/item.tsx +5 -5
- package/src/ui/components/primitives/pagination.tsx +4 -4
- package/src/ui/components/primitives/radio-group.tsx +1 -1
- package/src/ui/components/primitives/select.tsx +3 -3
- package/src/ui/components/primitives/table.tsx +26 -17
- package/src/ui/components/primitives/tabs.tsx +80 -23
- package/src/ui/components/primitives/textarea.tsx +1 -1
- package/src/ui/components/primitives/toggle-group.tsx +9 -2
- package/src/ui/docs/content/action-form-dialog.md +11 -4
- package/src/ui/docs/content/action-form.md +13 -3
- package/src/ui/docs/content/action-list-dialog.md +5 -7
- package/src/ui/docs/content/action-list.md +53 -5
- 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 +6 -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 +33 -8
- 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 +12 -2
- 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 +12 -10
- package/src/ui/docs/content/dialog.md +14 -7
- 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 +7 -4
- package/src/ui/docs/content/empty-value.md +4 -4
- 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 +21 -12
- 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 +6 -3
- 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 +20 -6
- 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 +48 -47
- 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 +22 -12
- package/src/ui/docs/content/testing.md +4 -2
- package/src/ui/docs/content/toast.md +5 -6
- package/src/ui/docs/content/toggle.md +37 -0
- package/src/ui/docs/content/tokens.md +45 -2
- 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
- package/src/ui/react.tsx +1 -0
- package/src/ui/theme.css +3 -0
|
@@ -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
|
|
|
@@ -15,7 +15,7 @@ validação, use `Field`.
|
|
|
15
15
|
}
|
|
16
16
|
/>
|
|
17
17
|
<DetailField
|
|
18
|
-
className="
|
|
18
|
+
className="col-span-2"
|
|
19
19
|
label="E-mail"
|
|
20
20
|
value="joao.silva@example.com"
|
|
21
21
|
icon={<Mail />}
|
|
@@ -25,8 +25,9 @@ validação, use `Field`.
|
|
|
25
25
|
|
|
26
26
|
## Valor ausente
|
|
27
27
|
|
|
28
|
-
`null`, `undefined`, string vazia ou só com espaços mostram
|
|
29
|
-
|
|
28
|
+
`null`, `undefined`, string vazia ou só com espaços mostram um travessão; a leitura assistiva
|
|
29
|
+
recebe “Não informado”. Uma string em `empty` troca esse significado no domínio, enquanto um nó
|
|
30
|
+
React substitui a apresentação. `0` e `false` seguem como valores. Ver `EmptyValue`.
|
|
30
31
|
|
|
31
32
|
```tsx preview col
|
|
32
33
|
<DetailGroup columns={2}>
|
|
@@ -37,11 +38,12 @@ significado no domínio. `0` e `false` seguem como valores. Ver `EmptyValue`.
|
|
|
37
38
|
|
|
38
39
|
## Moldura e divisórias internas
|
|
39
40
|
|
|
40
|
-
`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
|
|
41
43
|
divisórias internas; as duas opções são independentes e podem ser combinadas. `orientation`
|
|
42
44
|
define se a chave fica sobre o valor ou ao lado dele. Na orientação horizontal, todos os valores
|
|
43
|
-
começam depois da mesma coluna de rótulo, com largura padrão de `7rem
|
|
44
|
-
mais espaço para os rótulos, ajuste a variável no grupo, por exemplo com
|
|
45
|
+
começam depois da mesma coluna de rótulo, com largura padrão de `7rem` em grupos simples e
|
|
46
|
+
`8.5rem` na moldura horizontal. Quando a superfície exigir mais espaço para os rótulos, ajuste a variável no grupo, por exemplo com
|
|
45
47
|
`className="[--detail-label-width:9rem]"`.
|
|
46
48
|
|
|
47
49
|
```tsx preview col
|
|
@@ -49,7 +51,7 @@ mais espaço para os rótulos, ajuste a variável no grupo, por exemplo com
|
|
|
49
51
|
<DetailField label="Documento" value="Sem documento" />
|
|
50
52
|
<DetailField label="Fontes" value="NBS e Followize" />
|
|
51
53
|
<DetailField
|
|
52
|
-
className="
|
|
54
|
+
className="col-span-2"
|
|
53
55
|
label="E-mail"
|
|
54
56
|
value="cliente@example.com"
|
|
55
57
|
icon={<Mail />}
|
|
@@ -61,9 +63,9 @@ mais espaço para os rótulos, ajuste a variável no grupo, por exemplo com
|
|
|
61
63
|
|
|
62
64
|
| Propriedade | Tipo | Padrão | Descrição |
|
|
63
65
|
|---|---|---|---|
|
|
64
|
-
| `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. |
|
|
65
67
|
| `dividers` | `boolean` | `false` | Hairlines somente entre os campos, sem exigir moldura externa. |
|
|
66
|
-
| `columns` | `1 \| 2 \| 3 \| 4 \| 'auto'` | `1` |
|
|
68
|
+
| `columns` | `1 \| 2 \| 3 \| 4 \| 'auto'` | `1` | Número fixo de colunas ou distribuição automática por largura mínima. |
|
|
67
69
|
| `orientation` | `'vertical' \| 'horizontal'` | `'vertical'` | Chave sobre o valor ou ao lado dele em cada campo. |
|
|
68
70
|
|
|
69
71
|
## Propriedades de DetailField
|
|
@@ -73,4 +75,4 @@ mais espaço para os rótulos, ajuste a variável no grupo, por exemplo com
|
|
|
73
75
|
| `label` | `ReactNode` | | A chave do par. |
|
|
74
76
|
| `value` | `ReactNode` | | O valor; `null`, `undefined` e string vazia renderizam a ausência, `0` e `false` seguem como valores. |
|
|
75
77
|
| `icon` | `ReactNode` | | Ícone decorativo antes do par chave/valor. |
|
|
76
|
-
| `empty` | `ReactNode` | `“Não informado”` |
|
|
78
|
+
| `empty` | `ReactNode` | `“Não informado”` | Uma string dá significado acessível ao travessão; um nó próprio substitui a apresentação. |
|
|
@@ -16,7 +16,8 @@ Para conteúdo ancorado e não modal, use `Popover`. Para uma lista de ações,
|
|
|
16
16
|
|
|
17
17
|
`DialogContent` delimita a superfície. `DialogHeader`, `DialogBody` e `DialogFooter` organizam
|
|
18
18
|
título, conteúdo rolável e ações com o espaçamento da família. A superfície usa o fundo base,
|
|
19
|
-
borda
|
|
19
|
+
borda transparente no tema claro, borda sutil no escuro, raio `xl` e elevação para permanecer
|
|
20
|
+
distinta da página.
|
|
20
21
|
|
|
21
22
|
```tsx preview
|
|
22
23
|
<Dialog>
|
|
@@ -32,11 +33,11 @@ borda semântica, raio `xl` e elevação para permanecer distinta da página.
|
|
|
32
33
|
<Input id="workspace-name" placeholder="Ex.: Empresa X" />
|
|
33
34
|
</DialogBody>
|
|
34
35
|
<DialogFooter>
|
|
35
|
-
<ButtonGroup mode="spaced"
|
|
36
|
+
<ButtonGroup mode="spaced">
|
|
36
37
|
<DialogClose asChild>
|
|
37
|
-
<Button variant="
|
|
38
|
+
<Button variant="ghost">Cancelar</Button>
|
|
38
39
|
</DialogClose>
|
|
39
|
-
<Button>
|
|
40
|
+
<Button>Salvar</Button>
|
|
40
41
|
</ButtonGroup>
|
|
41
42
|
</DialogFooter>
|
|
42
43
|
</DialogContent>
|
|
@@ -44,8 +45,12 @@ borda semântica, raio `xl` e elevação para permanecer distinta da página.
|
|
|
44
45
|
```
|
|
45
46
|
|
|
46
47
|
O corpo cresce até o limite da janela e passa a rolar; cabeçalho e rodapé permanecem visíveis.
|
|
47
|
-
O
|
|
48
|
-
|
|
48
|
+
O backdrop escurece a página sem aplicar desfoque.
|
|
49
|
+
O fechamento do cabeçalho usa uma ação circular neutra e sutil. `closeSize` escolhe entre `xs` e
|
|
50
|
+
`sm`; o padrão é `sm`.
|
|
51
|
+
O `ButtonGroup` preserva a largura natural das ações por padrão. Use `distribution="equal"`
|
|
52
|
+
somente para decisões deliberadamente equivalentes. O `DialogFooter` organiza a faixa, mas não
|
|
53
|
+
decide a distribuição nem a aparência dos botões.
|
|
49
54
|
`DialogClose` encerra o modal sem exigir estado controlado. Use `open` e `onOpenChange` quando outra
|
|
50
55
|
parte da interface também precisar controlar a abertura.
|
|
51
56
|
|
|
@@ -144,7 +149,7 @@ confirmações e prompts distribuem confirmar e cancelar em duas colunas.
|
|
|
144
149
|
Em `dialog.choose`, declare pelo menos uma ação e marque exatamente uma ação habilitada com
|
|
145
150
|
`initialFocus`. Essa ação representa a saída segura. Os valores de `result` precisam ser únicos.
|
|
146
151
|
Por padrão, a última ação recebe contexto primário e variante sólida; as anteriores usam contexto
|
|
147
|
-
neutro e variante
|
|
152
|
+
neutro e variante outline. Defina `context` ou `variant` na própria ação para substituir o padrão.
|
|
148
153
|
|
|
149
154
|
### Montar o host
|
|
150
155
|
|
|
@@ -273,6 +278,8 @@ botão. O texto informa o efeito real, como `Excluir`, `Revogar acesso` ou `Ence
|
|
|
273
278
|
| Propriedade | Tipo | Padrão | Descrição |
|
|
274
279
|
| ----------------- | ----------- | ------ | --------------------------------------------------------------------------------------------------------- |
|
|
275
280
|
| `showCloseButton` | `boolean` | `true` | No modo padrão, inclui a ação de fechamento no header; o modo de alerta exige uma resposta identificável. |
|
|
281
|
+
| `closeDisabled` | `boolean` | `false` | Mantém a ação visível e impede o fechamento enquanto a tarefa está bloqueada. |
|
|
282
|
+
| `closeSize` | `"xs" \| "sm"` | `"sm"` | Define o tamanho da ação circular de fechar. |
|
|
276
283
|
| `className` | `string` | | Ajusta a superfície. |
|
|
277
284
|
| `children` | `ReactNode` | | Cabeçalho, corpo, rodapé ou conteúdo próprio. |
|
|
278
285
|
|
|
@@ -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>
|
|
@@ -26,7 +26,8 @@ entra pela direita e pode ser fechado por Esc, pelo overlay ou pelo botão de fe
|
|
|
26
26
|
`side` aceita `top`, `right`, `bottom` e `left`. `DrawerFooter` mantém as ações no rodapé;
|
|
27
27
|
`DrawerClose` fecha o painel sem exigir controle manual de estado. Como no `Dialog`, o cabeçalho
|
|
28
28
|
recebe um divisor inferior e o rodapé usa um divisor superior. O corpo preserva o mesmo alinhamento
|
|
29
|
-
horizontal entre título, conteúdo e ações.
|
|
29
|
+
horizontal entre título, conteúdo e ações. O fechamento do cabeçalho usa uma ação circular neutra
|
|
30
|
+
e sutil; `closeSize` escolhe entre `xs` e `sm`, com `sm` como padrão.
|
|
30
31
|
|
|
31
32
|
```tsx preview
|
|
32
33
|
<Drawer>
|
|
@@ -42,9 +43,9 @@ horizontal entre título, conteúdo e ações.
|
|
|
42
43
|
<Input id="ws-nome" defaultValue="Empresa X" />
|
|
43
44
|
</DrawerBody>
|
|
44
45
|
<DrawerFooter>
|
|
45
|
-
<ButtonGroup mode="spaced"
|
|
46
|
+
<ButtonGroup mode="spaced">
|
|
46
47
|
<DrawerClose asChild>
|
|
47
|
-
<Button variant="
|
|
48
|
+
<Button variant="ghost">Cancelar</Button>
|
|
48
49
|
</DrawerClose>
|
|
49
50
|
<Button>Salvar</Button>
|
|
50
51
|
</ButtonGroup>
|
|
@@ -66,6 +67,8 @@ horizontal entre título, conteúdo e ações.
|
|
|
66
67
|
| ----------------- | ---------------------------------------- | --------- | ------------------------------------------------------------------------------------------ |
|
|
67
68
|
| `side` | `'top' \| 'right' \| 'bottom' \| 'left'` | `'right'` | Borda de onde o painel aparece. |
|
|
68
69
|
| `showCloseButton` | `boolean` | `true` | Inclui a ação de fechamento no header. Desative quando o painel exigir uma ação explícita. |
|
|
70
|
+
| `closeDisabled` | `boolean` | `false` | Mantém a ação visível e impede fechar enquanto o painel está bloqueado. |
|
|
71
|
+
| `closeSize` | `"xs" \| "sm"` | `"sm"` | Define o tamanho da ação circular de fechar. |
|
|
69
72
|
|
|
70
73
|
## Propriedades de DrawerBody
|
|
71
74
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
Valor ausente tem uma representação padrão.
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
Valor ausente tem uma representação padrão. Nas células de tabela e nos pares de `DetailField`
|
|
2
|
+
aparece o travessão, enquanto a leitura assistiva recebe “Não informado”. As colunas de
|
|
3
|
+
`ActionList` e o `DetailField` já fazem isso sozinhos; um renderer customizado reutiliza a
|
|
4
|
+
primitiva em vez de repetir a condicional.
|
|
5
5
|
|
|
6
6
|
```tsx preview
|
|
7
7
|
<div className="flex items-center gap-6 text-sm">
|
|
@@ -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>
|
|
@@ -55,7 +63,8 @@ descrição; `FieldTitle` nomeia o campo quando o texto não puder ser um `<labe
|
|
|
55
63
|
|
|
56
64
|
| Propriedade | Tipo | Padrão | Descrição |
|
|
57
65
|
|---|---|---|---|
|
|
58
|
-
| `orientation` | `'vertical' \| 'horizontal' \| 'responsive'` | `'vertical'` | Direção do campo
|
|
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.
|
|
@@ -22,13 +22,13 @@ salvo em listas, cards e árvores.
|
|
|
22
22
|
|
|
23
23
|
```tsx preview col md
|
|
24
24
|
const [icon, setIcon] = useState('store')
|
|
25
|
-
const
|
|
25
|
+
const SelectedIcon = iconPickerIcons[icon] ?? FileText
|
|
26
26
|
|
|
27
27
|
render(
|
|
28
28
|
<div className="flex items-center gap-3">
|
|
29
29
|
<IconPicker value={icon} onChange={setIcon} className="w-56" />
|
|
30
30
|
<span className="flex items-center gap-2 rounded-md border px-3 py-2 text-sm">
|
|
31
|
-
<
|
|
31
|
+
<SelectedIcon className="size-4 text-muted-foreground" />
|
|
32
32
|
Painel comercial
|
|
33
33
|
</span>
|
|
34
34
|
</div>,
|
|
@@ -71,6 +71,8 @@ render(
|
|
|
71
71
|
| `maxLength` | `number` | | Quantidade de posições do código. Defina um `InputOTPSlot` para cada posição. |
|
|
72
72
|
| `value` | `string` | | Código no modo controlado. Use com `onChange`. |
|
|
73
73
|
| `onChange` | `(value: string) => void` | | Chamado a cada entrada com o código acumulado. |
|
|
74
|
+
| `onComplete` | `(value: string) => void` | | Chamado quando o código atinge `maxLength`. |
|
|
75
|
+
| `pattern` | `string` | | Expressão regular que o código precisa satisfazer; entradas que não casam são descartadas. Sem `pattern`, qualquer caractere é aceito, inclusive letras. Para somente dígitos, use `'^\\d+$'`. |
|
|
74
76
|
| `disabled` | `boolean` | `false` | Desabilita a digitação em todo o conjunto. |
|
|
75
77
|
|
|
76
78
|
## Propriedades de InputOTPSlot
|
|
@@ -21,7 +21,6 @@ como calendário em uma data; o `Label` continua responsável pelo nome acessív
|
|
|
21
21
|
|
|
22
22
|
Quando o campo precisar combinar vários adornos, prefixos ou botões, use `InputGroup`.
|
|
23
23
|
|
|
24
|
-
|
|
25
24
|
## Ação no fim do campo (trailing)
|
|
26
25
|
|
|
27
26
|
`trailing` posiciona no fim do campo uma ação relacionada ao valor, como limpar ou mostrar uma
|
|
@@ -37,7 +36,7 @@ function Demo() {
|
|
|
37
36
|
onChange={(e) => setQ(e.target.value)}
|
|
38
37
|
trailing={
|
|
39
38
|
q ? (
|
|
40
|
-
<Button variant="ghost" size="icon-xs" onClick={() => setQ('')}>
|
|
39
|
+
<Button variant="ghost" size="icon-xs" aria-label="Limpar busca" onClick={() => setQ('')}>
|
|
41
40
|
<X />
|
|
42
41
|
</Button>
|
|
43
42
|
) : undefined
|
|
@@ -167,7 +166,7 @@ Com `InputGroupTextarea`, um addon em `block-end` forma uma região de ações a
|
|
|
167
166
|
| Propriedade | Tipo | Padrão | Descrição |
|
|
168
167
|
|---|---|---|---|
|
|
169
168
|
| `size` | `'xs' \| 'sm' \| 'icon-xs' \| 'icon-sm'` | `'xs'` | O subconjunto da escala única que cabe num campo (1.5 · 2 · 1.5 · 1.75rem); os `icon-*` são quadrados. |
|
|
170
|
-
| `context` | `'neutral' \| 'primary' \| 'danger'` | `'
|
|
169
|
+
| `context` | `'neutral' \| 'primary' \| 'danger'` | `'neutral'` | Contexto semântico herdado de Button. Com `variant` `solid` ou `subtle` sem contexto declarado, o padrão passa a `'primary'`. |
|
|
171
170
|
| `variant` | `'solid' \| 'subtle' \| 'outline' \| 'ghost' \| 'link'` | `'ghost'` | Tratamento visual; use `solid` quando a ação precisar de ênfase. |
|
|
172
171
|
|
|
173
172
|
### Propriedades de InputGroupInput
|
|
@@ -3,6 +3,9 @@
|
|
|
3
3
|
A composição completa usa `ItemMedia` à esquerda, `ItemHeader` (`ItemTitle` +
|
|
4
4
|
`ItemDescription`) no meio e `ItemActions` à direita. Ícone e imagem mantêm uma moldura quadrada
|
|
5
5
|
alinhada ao topo, mesmo quando a descrição ocupa mais linhas. `variant="outline"` desenha a borda.
|
|
6
|
+
O tamanho padrão usa corpo produtivo, `0.75rem` de padding e `0.75rem` entre regiões. `size="sm"`
|
|
7
|
+
mantém o padding horizontal, reduz o padding vertical para `0.5rem` e o espaço entre regiões para
|
|
8
|
+
`0.625rem` em listas densas.
|
|
6
9
|
|
|
7
10
|
```tsx preview col
|
|
8
11
|
<Item variant="outline">
|
|
@@ -59,7 +62,7 @@ alinhada ao topo, mesmo quando a descrição ocupa mais linhas. `variant="outlin
|
|
|
59
62
|
|
|
60
63
|
## Clicável e compacto
|
|
61
64
|
|
|
62
|
-
asChild funde o Item em um
|
|
65
|
+
`asChild` funde o Item em um `<a>` — a linha inteira vira alvo (hover no fundo). `size="sm"` aperta o respiro; `ItemMedia` na variante padrão recebe um `Avatar`, que já traz a própria moldura.
|
|
63
66
|
|
|
64
67
|
```tsx preview col
|
|
65
68
|
<Item asChild size="sm" variant="outline">
|
|
@@ -97,7 +100,7 @@ Use `ItemBody` quando a linha também apresenta um valor ou controle que não pe
|
|
|
97
100
|
</Item>
|
|
98
101
|
```
|
|
99
102
|
|
|
100
|
-
`ItemContent` permanece exportado
|
|
103
|
+
`ItemContent` permanece exportado apenas por compatibilidade e está obsoleto. Código novo
|
|
101
104
|
usa `ItemHeader` ou `ItemBody` conforme o papel do conteúdo.
|
|
102
105
|
|
|
103
106
|
## Propriedades de Item
|
|
@@ -122,4 +125,4 @@ usa `ItemHeader` ou `ItemBody` conforme o papel do conteúdo.
|
|
|
122
125
|
|
|
123
126
|
`ItemHeader`, `ItemTitle`, `ItemDescription`, `ItemBody`, `ItemActions`, `ItemFooter` e
|
|
124
127
|
`ItemSeparator` aceitam as props nativas dos respectivos elementos e não adicionam propriedades
|
|
125
|
-
próprias. `ItemContent` preserva esse mesmo contrato
|
|
128
|
+
próprias. O `ItemContent` obsoleto preserva esse mesmo contrato por compatibilidade.
|
|
@@ -27,7 +27,7 @@ reconhecível que o nome da tecla.
|
|
|
27
27
|
```tsx preview col-start
|
|
28
28
|
<KbdGroup>
|
|
29
29
|
<Kbd>
|
|
30
|
-
<
|
|
30
|
+
<CommandIcon />
|
|
31
31
|
</Kbd>
|
|
32
32
|
<Kbd>
|
|
33
33
|
<CornerDownLeft />
|
|
@@ -49,6 +49,7 @@ ação antes de informar seu atalho.
|
|
|
49
49
|
Buscar workspace
|
|
50
50
|
<KbdGroup>
|
|
51
51
|
<Kbd>⌘</Kbd>
|
|
52
|
+
<span>+</span>
|
|
52
53
|
<Kbd>K</Kbd>
|
|
53
54
|
</KbdGroup>
|
|
54
55
|
</TooltipContent>
|
|
@@ -17,16 +17,22 @@ import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'
|
|
|
17
17
|
const server = createOpusMcpServer(runtime, {
|
|
18
18
|
name: 'meu-app',
|
|
19
19
|
// Valida a identidade da requisição (IdP) → contexto do runtime. Sem isso, roda anônimo
|
|
20
|
-
// (
|
|
20
|
+
// (sem usuário, só actions `public` rodam). Com isso, o agente age COMO O USUÁRIO.
|
|
21
21
|
resolveContext: async (extra) => auth.resolveFromMcp(extra),
|
|
22
22
|
})
|
|
23
23
|
|
|
24
24
|
await server.connect(new StdioServerTransport()) // local; HTTP/SSE para remoto
|
|
25
25
|
```
|
|
26
26
|
|
|
27
|
-
|
|
28
|
-
`
|
|
29
|
-
|
|
27
|
+
Só actions marcadas com `ai: { enabled: true }` ficam disponíveis, tanto para listar quanto para
|
|
28
|
+
executar. `ListTools` devolve cada uma com `name` (identificador técnico), `title` (a `label`
|
|
29
|
+
legível, quando existe), descrição, JSON Schema do input e, em `_meta`, os Produtos de Dados
|
|
30
|
+
relacionados: `com.softize.opus/data-products` (identificadores) e
|
|
31
|
+
`com.softize.opus/data-product-labels` (nome legível por identificador). `CallTool` recusa, com
|
|
32
|
+
erro, qualquer nome fora dessa lista; os demais seguem pelo `runtime.execute` — validação,
|
|
33
|
+
autorização e audit, tudo igual a uma chamada normal. Read-only? Marque só actions de leitura
|
|
34
|
+
com `ai:enabled`: a marcação decide o que o cliente MCP pode executar, e a autorização do
|
|
35
|
+
contexto continua valendo por cima.
|
|
30
36
|
|
|
31
37
|
## Escolher entre integração interna e MCP
|
|
32
38
|
|
|
@@ -104,6 +104,14 @@ MenuSub aninha um nível; inset alinha itens sem ícone com os que têm.
|
|
|
104
104
|
</Menu>
|
|
105
105
|
```
|
|
106
106
|
|
|
107
|
+
## Propriedades de Menu
|
|
108
|
+
|
|
109
|
+
| Propriedade | Tipo | Padrão | Descrição |
|
|
110
|
+
|---|---|---|---|
|
|
111
|
+
| `open` | `boolean` | | Estado do painel no modo controlado, como no menu de contexto. |
|
|
112
|
+
| `onOpenChange` | `(open: boolean) => void` | | Chamado quando o painel abre ou fecha. |
|
|
113
|
+
| `defaultOpen` | `boolean` | `false` | Estado inicial no modo não controlado. |
|
|
114
|
+
|
|
107
115
|
## Propriedades de MenuItem
|
|
108
116
|
|
|
109
117
|
| Propriedade | Tipo | Padrão | Descrição |
|
|
@@ -137,3 +145,22 @@ próprias além das de DOM.
|
|
|
137
145
|
|---|---|---|---|
|
|
138
146
|
| `value` | `string` | | Valor selecionado no grupo. |
|
|
139
147
|
| `onValueChange` | `(value: string) => void` | | Chamado quando a pessoa seleciona outro `MenuRadioItem`. |
|
|
148
|
+
|
|
149
|
+
## Propriedades de MenuRadioItem
|
|
150
|
+
|
|
151
|
+
| Propriedade | Tipo | Padrão | Descrição |
|
|
152
|
+
|---|---|---|---|
|
|
153
|
+
| `value` | `string` | | Valor que o item entrega ao `MenuRadioGroup` quando é selecionado. |
|
|
154
|
+
| `disabled` | `boolean` | `false` | Impede a seleção do item. |
|
|
155
|
+
|
|
156
|
+
## Propriedades de MenuLabel
|
|
157
|
+
|
|
158
|
+
| Propriedade | Tipo | Padrão | Descrição |
|
|
159
|
+
|---|---|---|---|
|
|
160
|
+
| `inset` | `boolean` | | Alinha o rótulo com itens que possuem ícone. |
|
|
161
|
+
|
|
162
|
+
## Propriedades de MenuSubTrigger
|
|
163
|
+
|
|
164
|
+
| Propriedade | Tipo | Padrão | Descrição |
|
|
165
|
+
|---|---|---|---|
|
|
166
|
+
| `inset` | `boolean` | | Alinha o gatilho do submenu sem ícone com os itens que possuem ícone. |
|