@softize/opus 19.0.0 → 20.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 +193 -0
- package/bin/cli.mjs +5 -0
- package/bin/lib/check.mjs +198 -10
- package/bin/lib/copy.mjs +29 -0
- package/bin/lib/mcp.mjs +1 -1
- package/docs/adr/0023-surfaces-share-one-anatomy-and-two-layouts.md +5 -0
- package/docs/adr/0024-fill-height-propagates-by-context.md +118 -0
- package/docs/data-products.md +15 -9
- package/docs/protocol.md +3 -4
- package/docs/releasing.md +2 -2
- package/package.json +2 -2
- package/registry/skills/create-opus-action/scripts/scaffold.mjs +2 -1
- package/registry/templates/app/package.json +1 -1
- package/src/core/runtime.ts +96 -8
- package/src/core/types.ts +5 -2
- package/src/ui/components/patterns/action-form-card.tsx +11 -1
- package/src/ui/components/patterns/content-header.tsx +15 -3
- package/src/ui/components/patterns/fill-region.ts +150 -0
- package/src/ui/components/patterns/list.tsx +89 -78
- package/src/ui/components/patterns/page.tsx +20 -4
- package/src/ui/components/patterns/presentation.tsx +52 -37
- package/src/ui/components/patterns/split.tsx +44 -4
- package/src/ui/components/patterns/surface-anatomy.ts +35 -8
- package/src/ui/components/patterns/trigger.tsx +12 -2
- package/src/ui/components/primitives/alert.tsx +9 -1
- package/src/ui/components/primitives/avatar.tsx +7 -3
- package/src/ui/components/primitives/carousel.tsx +34 -5
- package/src/ui/components/primitives/checkbox.tsx +11 -3
- package/src/ui/components/primitives/command.tsx +2 -1
- package/src/ui/components/primitives/copyable.tsx +120 -10
- package/src/ui/components/primitives/dialog.tsx +41 -10
- package/src/ui/components/primitives/drawer.tsx +9 -1
- package/src/ui/components/primitives/empty.tsx +1 -1
- package/src/ui/components/primitives/icon-picker.tsx +6 -2
- package/src/ui/components/primitives/icon-tile.tsx +7 -0
- package/src/ui/components/primitives/input-group.tsx +9 -2
- package/src/ui/components/primitives/input-otp.tsx +1 -1
- package/src/ui/components/primitives/kbd.tsx +1 -1
- package/src/ui/components/primitives/label.tsx +3 -0
- package/src/ui/components/primitives/menu.tsx +5 -0
- package/src/ui/components/primitives/popover.tsx +1 -1
- package/src/ui/components/primitives/progress.tsx +9 -1
- package/src/ui/components/primitives/slider.tsx +62 -11
- package/src/ui/components/primitives/truncate.tsx +10 -1
- package/src/ui/docs/content/accordion.md +74 -27
- package/src/ui/docs/content/action-form-card.md +24 -15
- package/src/ui/docs/content/action-form-dialog.md +17 -7
- package/src/ui/docs/content/action-form.md +92 -77
- package/src/ui/docs/content/action-list-dialog.md +75 -38
- package/src/ui/docs/content/action-list.md +134 -52
- package/src/ui/docs/content/action-trigger.md +27 -10
- package/src/ui/docs/content/action-view.md +14 -14
- package/src/ui/docs/content/actions.md +161 -66
- package/src/ui/docs/content/ai.md +43 -44
- package/src/ui/docs/content/alert.md +83 -29
- package/src/ui/docs/content/ask.md +51 -26
- package/src/ui/docs/content/aspect-ratio.md +22 -24
- package/src/ui/docs/content/audit.md +23 -19
- package/src/ui/docs/content/auth.md +38 -19
- package/src/ui/docs/content/avatar.md +54 -5
- package/src/ui/docs/content/badge.md +29 -9
- package/src/ui/docs/content/breadcrumb.md +21 -8
- package/src/ui/docs/content/button.md +73 -43
- package/src/ui/docs/content/calendar.md +134 -26
- package/src/ui/docs/content/card.md +41 -15
- package/src/ui/docs/content/carousel.md +37 -6
- package/src/ui/docs/content/chat.md +118 -37
- package/src/ui/docs/content/checkbox.md +73 -7
- package/src/ui/docs/content/cli.md +94 -55
- package/src/ui/docs/content/collapsible.md +43 -19
- package/src/ui/docs/content/command.md +30 -8
- package/src/ui/docs/content/composer.md +23 -8
- package/src/ui/docs/content/content.md +31 -7
- package/src/ui/docs/content/copyable.md +39 -8
- package/src/ui/docs/content/customization.md +55 -46
- package/src/ui/docs/content/cycle.md +33 -18
- package/src/ui/docs/content/data-products.md +115 -0
- package/src/ui/docs/content/data-state.md +20 -6
- package/src/ui/docs/content/data.md +20 -19
- package/src/ui/docs/content/detail.md +12 -5
- package/src/ui/docs/content/dialog.md +107 -24
- package/src/ui/docs/content/dictionary-value.md +4 -4
- package/src/ui/docs/content/dock.md +54 -19
- package/src/ui/docs/content/dot.md +35 -5
- package/src/ui/docs/content/drawer.md +63 -19
- package/src/ui/docs/content/empty-value.md +20 -6
- package/src/ui/docs/content/empty.md +24 -3
- package/src/ui/docs/content/events.md +76 -16
- package/src/ui/docs/content/executions.md +9 -9
- package/src/ui/docs/content/field.md +21 -6
- package/src/ui/docs/content/getting-started.md +44 -34
- package/src/ui/docs/content/icon-picker.md +19 -13
- package/src/ui/docs/content/icon-tile.md +28 -5
- package/src/ui/docs/content/input-otp.md +58 -7
- package/src/ui/docs/content/input.md +22 -3
- package/src/ui/docs/content/item.md +53 -6
- package/src/ui/docs/content/kbd.md +5 -1
- package/src/ui/docs/content/label.md +13 -4
- package/src/ui/docs/content/log.md +5 -5
- package/src/ui/docs/content/markdown.md +5 -4
- package/src/ui/docs/content/mcp.md +49 -23
- package/src/ui/docs/content/menu.md +95 -10
- package/src/ui/docs/content/metric-card.md +12 -4
- package/src/ui/docs/content/observability.md +10 -9
- package/src/ui/docs/content/page.md +118 -12
- package/src/ui/docs/content/pagination.md +13 -5
- package/src/ui/docs/content/pane.md +55 -5
- package/src/ui/docs/content/popover.md +42 -5
- package/src/ui/docs/content/presentation.md +91 -47
- package/src/ui/docs/content/progress.md +27 -14
- package/src/ui/docs/content/queue.md +39 -21
- package/src/ui/docs/content/radio-group.md +26 -4
- package/src/ui/docs/content/router.md +29 -10
- package/src/ui/docs/content/runtime.md +90 -54
- package/src/ui/docs/content/scheduler.md +53 -21
- package/src/ui/docs/content/scroll-area.md +42 -35
- package/src/ui/docs/content/select.md +78 -33
- package/src/ui/docs/content/semantic-context.md +21 -2
- package/src/ui/docs/content/separator.md +15 -9
- package/src/ui/docs/content/sidebar.md +3 -2
- package/src/ui/docs/content/skeleton.md +6 -1
- package/src/ui/docs/content/slider.md +37 -9
- package/src/ui/docs/content/spinner.md +4 -3
- package/src/ui/docs/content/split.md +19 -0
- package/src/ui/docs/content/storage.md +8 -9
- package/src/ui/docs/content/switch.md +10 -7
- package/src/ui/docs/content/table.md +46 -8
- package/src/ui/docs/content/tabs.md +14 -4
- package/src/ui/docs/content/testing.md +76 -31
- package/src/ui/docs/content/textarea.md +5 -4
- package/src/ui/docs/content/toast.md +48 -7
- package/src/ui/docs/content/toggle.md +3 -3
- package/src/ui/docs/content/tokens.md +15 -26
- package/src/ui/docs/content/tooltip.md +18 -2
- package/src/ui/docs/content/truncate.md +36 -6
- package/src/ui/docs/content/ui.md +74 -22
- package/src/ui/docs/content/upgrading.md +45 -36
- package/src/ui/docs/plugin.ts +36 -2
- package/src/ui/docs/registry.tsx +6 -0
- package/src/ui/drivers/react.tsx +16 -8
- package/src/ui/meta.ts +31 -31
- package/src/vite/design.ts +16 -4
|
@@ -1,8 +1,28 @@
|
|
|
1
|
+
## Pré-requisitos
|
|
2
|
+
|
|
3
|
+
`ActionForm` executa a action pelo cliente registrado no `OpusProvider` e usa o React Query para
|
|
4
|
+
invalidar as consultas afetadas. Monte os dois providers uma vez na raiz do aplicativo; todos os
|
|
5
|
+
exemplos desta página pressupõem essa montagem.
|
|
6
|
+
|
|
7
|
+
```tsx
|
|
8
|
+
/* main.tsx do app. */
|
|
9
|
+
<QueryClientProvider client={queryClient}>
|
|
10
|
+
<OpusProvider client={apiClient}>
|
|
11
|
+
<App />
|
|
12
|
+
</OpusProvider>
|
|
13
|
+
</QueryClientProvider>
|
|
14
|
+
```
|
|
15
|
+
|
|
1
16
|
## Formulário derivado do contrato
|
|
2
17
|
|
|
3
18
|
Use `ActionForm` para gerar campos, validação e mensagens a partir de uma `FormAction`. Sem
|
|
4
|
-
`children`, o componente
|
|
5
|
-
|
|
19
|
+
`children`, o componente monta um campo para cada chave declarada em `fields` no contrato, na ordem
|
|
20
|
+
dessa declaração, e escolhe o controle pelo tipo do campo no schema de input. Um campo presente no
|
|
21
|
+
schema, mas sem entrada em `fields`, não aparece no modo automático: declare-o em `fields` ou
|
|
22
|
+
posicione-o com `ActionFormField`, como mostra a próxima seção.
|
|
23
|
+
|
|
24
|
+
A ação principal permanece desabilitada até que algum valor mude. No exemplo, preencha o nome para
|
|
25
|
+
habilitá-la; o valor “Softize” simula um erro devolvido pelo servidor.
|
|
6
26
|
|
|
7
27
|
```tsx preview col md
|
|
8
28
|
<DocBrowserActionProvider>
|
|
@@ -13,36 +33,43 @@ no contrato. No exemplo, altere um valor para habilitar a ação principal.
|
|
|
13
33
|
## Composição dos campos
|
|
14
34
|
|
|
15
35
|
Passe `children` quando a disposição automática não atender ao formulário. Cada
|
|
16
|
-
`ActionFormField` mantém rótulo, ajuda, controle, obrigatoriedade e erro derivados do contrato;
|
|
17
|
-
|
|
18
|
-
invalidação continuam sob
|
|
36
|
+
`ActionFormField` mantém rótulo, ajuda, controle, obrigatoriedade e erro derivados do contrato; o
|
|
37
|
+
consumidor define apenas a grade e as condições. O espaçamento vertical entre os filhos vem do
|
|
38
|
+
`FieldGroup` que o formulário já aplica. Execução, validação, toast e invalidação continuam sob
|
|
39
|
+
responsabilidade de `ActionForm`.
|
|
40
|
+
|
|
41
|
+
Nesse modo, qualquer campo do schema de input pode ser posicionado, mesmo sem entrada em `fields`;
|
|
42
|
+
nesse caso, o rótulo exibido é o próprio nome técnico do campo e não há ajuda. Declare o campo em
|
|
43
|
+
`fields` para nomeá-lo.
|
|
19
44
|
|
|
20
45
|
```tsx preview col md
|
|
21
46
|
<DocBrowserActionProvider>
|
|
22
47
|
<ActionForm action={docWorkspaceCreate}>
|
|
23
|
-
<div className="
|
|
24
|
-
<
|
|
25
|
-
|
|
26
|
-
<ActionFormField name="status" />
|
|
27
|
-
</div>
|
|
28
|
-
<ActionFormField name="contact" />
|
|
29
|
-
<ActionFormField name="notes" />
|
|
48
|
+
<div className="grid grid-cols-2 gap-4">
|
|
49
|
+
<ActionFormField name="name" />
|
|
50
|
+
<ActionFormField name="status" />
|
|
30
51
|
</div>
|
|
52
|
+
<ActionFormField name="contact" />
|
|
53
|
+
<ActionFormField name="notes" />
|
|
31
54
|
</ActionForm>
|
|
32
55
|
</DocBrowserActionProvider>
|
|
33
56
|
```
|
|
34
57
|
|
|
35
58
|
## Valores iniciais e rótulos
|
|
36
59
|
|
|
37
|
-
`defaultValues` preenche o formulário
|
|
38
|
-
|
|
39
|
-
|
|
60
|
+
`defaultValues` preenche o formulário antes da primeira alteração. Em uma edição, carregue ali os
|
|
61
|
+
valores atuais do registro; em uma criação, use-o para sugerir um ponto de partida, como o status
|
|
62
|
+
inicial do exemplo. A ação principal continua desabilitada até que a pessoa altere algum campo.
|
|
63
|
+
|
|
64
|
+
Criação e edição comuns mantêm o rótulo padrão `Salvar`; use `submitLabel` somente quando a
|
|
65
|
+
operação pedir outro verbo, como `Renomear`. `onCancel` acrescenta `Cancelar` e devolve ao
|
|
66
|
+
consumidor a decisão de fechar um painel ou navegar para outra página.
|
|
40
67
|
|
|
41
68
|
```tsx preview col md
|
|
42
69
|
<DocBrowserActionProvider>
|
|
43
70
|
<ActionForm
|
|
44
71
|
action={docWorkspaceCreate}
|
|
45
|
-
defaultValues={{
|
|
72
|
+
defaultValues={{ status: "active" }}
|
|
46
73
|
onCancel={() => undefined}
|
|
47
74
|
/>
|
|
48
75
|
</DocBrowserActionProvider>
|
|
@@ -50,58 +77,17 @@ invalidação continuam sob responsabilidade de `ActionForm`.
|
|
|
50
77
|
|
|
51
78
|
## Formulário modal
|
|
52
79
|
|
|
53
|
-
[`ActionFormDialog`](/ui/action-form-dialog) acrescenta a moldura, o corpo rolável e o
|
|
54
|
-
ações ficam alinhadas no fim da faixa e preservam a largura do conteúdo;
|
|
55
|
-
Use `footerDistribution="equal"` somente quando as duas decisões precisarem
|
|
56
|
-
Nesse caso, o cancelamento muda para `outline`, salvo escolha explícita em
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
## Pré-requisitos
|
|
60
|
-
|
|
61
|
-
Monte os providers de consulta e execução uma vez na raiz do aplicativo:
|
|
80
|
+
[`ActionFormDialog`](/ui/action-form-dialog) acrescenta a moldura, o corpo rolável e o rodapé ao
|
|
81
|
+
formulário. Por padrão, as ações ficam alinhadas no fim da faixa e preservam a largura do conteúdo;
|
|
82
|
+
`Cancelar` usa `ghost`. Use `footerDistribution="equal"` somente quando as duas decisões precisarem
|
|
83
|
+
do mesmo peso visual. Nesse caso, o cancelamento muda para `outline`, salvo escolha explícita em
|
|
84
|
+
`cancelVariant`. Para apresentar o formulário como uma seção delimitada da página, use
|
|
85
|
+
[`ActionFormCard`](/ui/action-form-card). As propriedades de cada wrapper estão na página dele.
|
|
62
86
|
|
|
63
|
-
|
|
64
|
-
/* main.tsx do app. */
|
|
65
|
-
<QueryClientProvider client={queryClient}>
|
|
66
|
-
<OpusProvider client={apiClient}>
|
|
67
|
-
<App />
|
|
68
|
-
</OpusProvider>
|
|
69
|
-
</QueryClientProvider>
|
|
70
|
-
```
|
|
71
|
-
|
|
72
|
-
## useFormAction
|
|
73
|
-
|
|
74
|
-
`ActionForm` é uma composição sobre `useFormAction(action, { defaultValues, onSuccess, onError })`,
|
|
75
|
-
que devolve o `form` do react-hook-form já com o resolver Zod em pt-BR, `submit`, `isLoading`,
|
|
76
|
-
`error`, `isSuccess` e `reset`. Use o hook direto quando o formulário precisar de um layout ou de um
|
|
77
|
-
ciclo de vida que o pattern não cobre; validação e execução continuam iguais.
|
|
78
|
-
|
|
79
|
-
## Propriedades de ActionForm
|
|
80
|
-
|
|
81
|
-
| Propriedade | Tipo | Padrão | Descrição |
|
|
82
|
-
| ------------------------------------------------------ | ----------------------------------------------------- | --------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
83
|
-
| `action` | `FormContract<TInput, TData>` | | O contrato da FormAction — dele saem campos (input Zod + fields), mensagens e invalidação de cache. |
|
|
84
|
-
| `defaultValues` | `Partial<TInput>` | | Valores iniciais — o modo edição de um update/patch. |
|
|
85
|
-
| `onSuccess` | `(data: TData) => void` | | Pós-sucesso (o toast e a invalidação de cache já aconteceram). |
|
|
86
|
-
| `submitLabel / cancelLabel / cancelVariant / onCancel` | `string / string / 'ghost' \| 'outline' / () => void` | `'Salvar' / 'Cancelar' / 'ghost'` | Rodapé do form — o Cancelar só aparece com onCancel. Fora de um modal, mantenha `ghost`; o `ActionFormDialog` usa `outline` somente com `footerDistribution="equal"`. |
|
|
87
|
-
| `disabled` | `boolean` | `false` | Bloqueia campos e ações sem desmontar o formulário. |
|
|
88
|
-
| `onLoadingChange` | `(loading: boolean) => void` | | Informa início e fim da execução a quem coordena ações como um grupo. |
|
|
89
|
-
| `fieldOptions` | `Record<string, SelectOption[]>` | | Opções de runtime por campo (ex.: ids de skills) — sobrepõe as inferidas do z.enum. |
|
|
90
|
-
| `className / body / footer` | `string / (node) => node / (node) => node` | | className = classes do `<form>`. body/footer = slots: recebem os campos / os botões e escolhem o invólucro — é como o ActionFormDialog injeta DialogBody/DialogFooter (scroll + faixa). |
|
|
91
|
-
| `children` | `ReactNode` | | Modo composição: diagrame com `<ActionFormField name />`. Sem children, o automático monta todos os campos na ordem do contrato. |
|
|
87
|
+
## Ajuda no rótulo
|
|
92
88
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
| Propriedade | Tipo | Descrição |
|
|
96
|
-
| ----------- | ---------------- | ------------------------------------------------------------------------------ |
|
|
97
|
-
| `name` | `string` | O campo do contrato (chave em `fields`/schema). Fora do schema, não renderiza. |
|
|
98
|
-
| `options` | `SelectOption[]` | Opções por id de runtime — sobrepõe o fieldOptions do form e o z.enum. |
|
|
99
|
-
| `className` | `string` | Classes do invólucro (ex.: `col-span-2` em uma grid). |
|
|
100
|
-
|
|
101
|
-
## Ajuda na label
|
|
102
|
-
|
|
103
|
-
`FieldSpec.help` aparece como um ícone junto à label, com o texto num tooltip. Escreva ali o
|
|
104
|
-
critério, o efeito ou a limitação que a label não diz; ajuda que só repete a label deve ser omitida.
|
|
89
|
+
`FieldSpec.help` aparece como um ícone junto ao rótulo, com o texto em um tooltip. Escreva ali o
|
|
90
|
+
critério, o efeito ou a limitação que o rótulo não diz; ajuda que só repete o rótulo deve ser omitida.
|
|
105
91
|
Não existe texto auxiliar sob o campo: quem precisa de uma frase permanente abaixo do controle usa
|
|
106
92
|
`FieldDescription` na composição própria.
|
|
107
93
|
|
|
@@ -110,20 +96,14 @@ lugar:
|
|
|
110
96
|
|
|
111
97
|
```tsx preview col md
|
|
112
98
|
<Field>
|
|
113
|
-
<FieldLabel htmlFor="
|
|
114
|
-
<span>
|
|
115
|
-
<LabelHelp help="
|
|
99
|
+
<FieldLabel htmlFor="billing-contact" className="items-center gap-1.5">
|
|
100
|
+
<span>Contato</span>
|
|
101
|
+
<LabelHelp help="Recebe os avisos de faturamento e de integração do workspace." />
|
|
116
102
|
</FieldLabel>
|
|
117
|
-
<Input id="
|
|
103
|
+
<Input id="billing-contact" type="email" placeholder="email@cliente.com" />
|
|
118
104
|
</Field>
|
|
119
105
|
```
|
|
120
106
|
|
|
121
|
-
### Propriedades de LabelHelp
|
|
122
|
-
|
|
123
|
-
| Propriedade | Tipo | Descrição |
|
|
124
|
-
| ----------- | -------- | ------------------------------------------------------------ |
|
|
125
|
-
| `help` | `string` | O texto do tooltip. Vazio ou ausente, o ícone não renderiza. |
|
|
126
|
-
|
|
127
107
|
## Origem das opções de seleção
|
|
128
108
|
|
|
129
109
|
As opções seguem esta precedência: `options` no campo, `fieldOptions` no formulário, `options` no
|
|
@@ -137,7 +117,7 @@ referência; itens estáticos permanecem como declarados no contrato.
|
|
|
137
117
|
O literal canônico do grupo de escolhas é sempre kebab-case: `widget: 'toggle-group'`. Em enum ele
|
|
138
118
|
renderiza seleção única; em array de enum, seleção múltipla. As opções seguem a mesma precedência e
|
|
139
119
|
o mesmo `SelectOption` rico dos selects. Use esse widget quando cada opção funcionar como uma
|
|
140
|
-
escolha rica em card, com conteúdo de apoio; para uma lista textual comum, prefira `RadioGroup
|
|
120
|
+
escolha rica em card, com conteúdo de apoio; para uma lista textual comum, prefira [`RadioGroup`](/ui/radio-group).
|
|
141
121
|
Outros identificadores continuam válidos como metadado
|
|
142
122
|
para renderers próprios; o `ActionForm` aplica sua inferência normal quando não reconhece o widget.
|
|
143
123
|
|
|
@@ -170,3 +150,38 @@ function PermissionGrid() {
|
|
|
170
150
|
|
|
171
151
|
O contexto também expõe `shape` (Zod por campo), `fields` (FieldSpec) e `fieldOptions`.
|
|
172
152
|
Fora de um `<ActionForm>`, o hook lança um erro que informa o provider ausente.
|
|
153
|
+
|
|
154
|
+
## useFormAction
|
|
155
|
+
|
|
156
|
+
`ActionForm` é uma composição sobre `useFormAction(action, { defaultValues, onSuccess, onError })`,
|
|
157
|
+
que devolve o `form` do react-hook-form já com o resolver Zod em pt-BR, `submit`, `isLoading`,
|
|
158
|
+
`error`, `isSuccess` e `reset`. Use o hook direto quando o formulário precisar de um layout ou de um
|
|
159
|
+
ciclo de vida que o pattern não cobre; validação e execução continuam iguais.
|
|
160
|
+
|
|
161
|
+
## Propriedades de ActionForm
|
|
162
|
+
|
|
163
|
+
| Propriedade | Tipo | Padrão | Descrição |
|
|
164
|
+
| ------------------------------------------------------ | ----------------------------------------------------- | --------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
165
|
+
| `action` | `FormContract<TInput, TData>` | | O contrato da FormAction — dele saem campos (input Zod + fields), mensagens e invalidação de cache. |
|
|
166
|
+
| `defaultValues` | `Partial<TInput>` | | Valores iniciais: os dados atuais do registro em uma edição ou uma sugestão em uma criação. Não contam como alteração para habilitar a ação principal. |
|
|
167
|
+
| `onSuccess` | `(data: TData) => void` | | Pós-sucesso (o toast e a invalidação de cache já aconteceram). |
|
|
168
|
+
| `submitLabel / cancelLabel / cancelVariant / onCancel` | `string / string / 'ghost' \| 'outline' / () => void` | `'Salvar' / 'Cancelar' / 'ghost'` | Rodapé do form — o Cancelar só aparece com onCancel. Fora de um modal, mantenha `ghost`; o `ActionFormDialog` usa `outline` somente com `footerDistribution="equal"`. |
|
|
169
|
+
| `disabled` | `boolean` | `false` | Bloqueia campos e ações sem desmontar o formulário. |
|
|
170
|
+
| `onLoadingChange` | `(loading: boolean) => void` | | Informa início e fim da execução a quem coordena ações como um grupo. |
|
|
171
|
+
| `fieldOptions` | `Record<string, SelectOption[]>` | | Opções de runtime por campo (ex.: ids de skills) — sobrepõe as inferidas do z.enum. |
|
|
172
|
+
| `className / body / footer` | `string / (node) => node / (node) => node` | | className = classes do `<form>`. body/footer = slots: recebem os campos / os botões e escolhem o invólucro — é como o ActionFormDialog injeta DialogBody/DialogFooter (scroll + faixa). |
|
|
173
|
+
| `children` | `ReactNode` | | Modo composição: diagrame com `<ActionFormField name />`. Sem children, o modo automático monta um campo por chave de `fields`, na ordem declarada; campo sem entrada em `fields` não aparece. |
|
|
174
|
+
|
|
175
|
+
## Propriedades de ActionFormField
|
|
176
|
+
|
|
177
|
+
| Propriedade | Tipo | Descrição |
|
|
178
|
+
| ----------- | ---------------- | ------------------------------------------------------------------------------ |
|
|
179
|
+
| `name` | `string` | O campo do schema de input. Sem entrada em `fields`, usa o nome técnico como rótulo; fora do schema, não renderiza. |
|
|
180
|
+
| `options` | `SelectOption[]` | Opções por id de runtime — sobrepõe o fieldOptions do form e o z.enum. |
|
|
181
|
+
| `className` | `string` | Classes do invólucro (ex.: `col-span-2` em uma grid). |
|
|
182
|
+
|
|
183
|
+
## Propriedades de LabelHelp
|
|
184
|
+
|
|
185
|
+
| Propriedade | Tipo | Descrição |
|
|
186
|
+
| ----------- | -------- | ------------------------------------------------------------ |
|
|
187
|
+
| `help` | `string` | O texto do tooltip. Vazio ou ausente, o ícone não renderiza. |
|
|
@@ -1,76 +1,113 @@
|
|
|
1
1
|
## Listagem em um modal
|
|
2
2
|
|
|
3
|
-
Use `ActionListDialog` para consultar e apresentar uma `ListAction` sem sair do contexto atual.
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
3
|
+
Use `ActionListDialog` para consultar e apresentar uma `ListAction` sem sair do contexto atual. O
|
|
4
|
+
modal monta um [`ActionList`](/ui/action-list) no modo de composição: busca, filtros, os estados de
|
|
5
|
+
carregamento, erro e vazio, além do rodapé com total e paginação, continuam os da listagem. A consulta
|
|
6
|
+
roda ao abrir, é refeita quando `input` muda e acompanha as invalidações declaradas por outras
|
|
7
|
+
actions. O consumidor compõe somente os itens, por `children`.
|
|
7
8
|
|
|
8
9
|
```tsx preview col
|
|
10
|
+
type Workspace = {
|
|
11
|
+
id: string;
|
|
12
|
+
name: string;
|
|
13
|
+
status: "active" | "onboarding" | "paused";
|
|
14
|
+
agents: number;
|
|
15
|
+
};
|
|
16
|
+
|
|
9
17
|
const [open, setOpen] = useState(false);
|
|
10
18
|
|
|
11
19
|
render(
|
|
12
20
|
<DocBrowserActionProvider>
|
|
13
|
-
<Button onClick={() => setOpen(true)}>
|
|
21
|
+
<Button onClick={() => setOpen(true)}>Ver workspaces</Button>
|
|
14
22
|
<ActionListDialog
|
|
15
23
|
action={docWorkspaceList}
|
|
16
24
|
input={{}}
|
|
17
25
|
open={open}
|
|
18
26
|
onOpenChange={setOpen}
|
|
19
27
|
title="Workspaces"
|
|
20
|
-
actions={
|
|
21
|
-
<Button>Criar workspace</Button>
|
|
22
|
-
}
|
|
28
|
+
actions={<Button>Criar workspace</Button>}
|
|
23
29
|
emptyMessage="Nenhum workspace."
|
|
24
30
|
>
|
|
25
|
-
{(workspaces) => (
|
|
26
|
-
<
|
|
27
|
-
{workspaces.map((w) => (
|
|
28
|
-
<
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
31
|
+
{(workspaces: Workspace[]) => (
|
|
32
|
+
<ItemGroup variant="framed">
|
|
33
|
+
{workspaces.map((w, index) => (
|
|
34
|
+
<React.Fragment key={w.id}>
|
|
35
|
+
{index > 0 && <ItemSeparator />}
|
|
36
|
+
<Item size="sm">
|
|
37
|
+
<ItemHeader>
|
|
38
|
+
<ItemTitle>{w.name}</ItemTitle>
|
|
39
|
+
<ItemDescription>
|
|
40
|
+
{w.agents === 1 ? "1 agente" : `${w.agents} agentes`}
|
|
41
|
+
</ItemDescription>
|
|
42
|
+
</ItemHeader>
|
|
43
|
+
<ItemActions>
|
|
44
|
+
<DictionaryValue dict={docWorkspaceStatus} value={w.status} />
|
|
45
|
+
</ItemActions>
|
|
46
|
+
</Item>
|
|
47
|
+
</React.Fragment>
|
|
38
48
|
))}
|
|
39
|
-
</
|
|
49
|
+
</ItemGroup>
|
|
40
50
|
)}
|
|
41
51
|
</ActionListDialog>
|
|
42
52
|
</DocBrowserActionProvider>,
|
|
43
53
|
);
|
|
44
54
|
```
|
|
45
55
|
|
|
56
|
+
`actions` ocupa o extremo direito da linha acima da lista e costuma receber a criação do recurso;
|
|
57
|
+
`note` acrescenta um contexto curto do lado oposto. Quando a criação precisar de um formulário
|
|
58
|
+
próprio em modal, use [`ActionFormDialog`](/ui/action-form-dialog).
|
|
59
|
+
|
|
46
60
|
## Estado adicional do consumidor
|
|
47
61
|
|
|
48
|
-
Quando
|
|
49
|
-
Use `empty` para substituir a regra de vazio
|
|
50
|
-
|
|
62
|
+
Quando os itens dependerem de outra consulta, `loading` soma esse carregamento ao estado da lista.
|
|
63
|
+
Use `empty` para substituir a regra de vazio. No exemplo, um formulário de criação aberto no corpo
|
|
64
|
+
conta como conteúdo, e o modal deixa de exibir o estado vazio enquanto a pessoa preenche o
|
|
65
|
+
formulário.
|
|
51
66
|
|
|
52
67
|
```tsx
|
|
53
|
-
|
|
68
|
+
const [adding, setAdding] = useState(false);
|
|
69
|
+
const roles = useListAction<Role>(roleListContract, { workspaceId });
|
|
70
|
+
const roleOptions = roles.items.map((role) => ({ value: role.id, label: role.name }));
|
|
71
|
+
|
|
72
|
+
<ActionListDialog<Agent, { workspaceId: string }>
|
|
54
73
|
action={agentListContract}
|
|
55
74
|
input={{ workspaceId }}
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
75
|
+
open={open}
|
|
76
|
+
onOpenChange={setOpen}
|
|
77
|
+
title="Agentes"
|
|
78
|
+
actions={<Button onClick={() => setAdding(true)}>Criar agente</Button>}
|
|
79
|
+
loading={roles.isLoading}
|
|
80
|
+
empty={(agents) => agents.length === 0 && !adding}
|
|
81
|
+
>
|
|
82
|
+
{(agents) => (
|
|
83
|
+
<>
|
|
84
|
+
{adding && (
|
|
85
|
+
<ActionForm
|
|
86
|
+
action={agentCreateContract}
|
|
87
|
+
defaultValues={{ workspaceId }}
|
|
88
|
+
fieldOptions={{ role: roleOptions }}
|
|
89
|
+
onSuccess={() => setAdding(false)}
|
|
90
|
+
onCancel={() => setAdding(false)}
|
|
91
|
+
/>
|
|
92
|
+
)}
|
|
93
|
+
<AgentItems agents={agents} />
|
|
94
|
+
</>
|
|
95
|
+
)}
|
|
96
|
+
</ActionListDialog>;
|
|
60
97
|
```
|
|
61
98
|
|
|
62
99
|
## Propriedades de ActionListDialog
|
|
63
100
|
|
|
64
101
|
| Propriedade | Tipo | Padrão | Descrição |
|
|
65
102
|
| ------------------------------------------ | ----------------------------------- | -------------------- | ------------------------------------------------------------------------------------------------- |
|
|
66
|
-
| `action / input` | `ListAction / TInput` | `input`: `{}` | O contrato e o escopo base
|
|
67
|
-
| `open / onOpenChange` | `boolean / (open) => void` | |
|
|
103
|
+
| `action / input` | `ListAction / TInput` | `input`: `{}` | O contrato e o escopo base da consulta. Uma mudança em `input` refaz a consulta; as invalidações declaradas por forms e triggers também. |
|
|
104
|
+
| `open / onOpenChange` | `boolean / (open) => void` | | Estado controlado do modal. |
|
|
68
105
|
| `title` | `string` | | Nome da lista exibido no cabeçalho fixo. |
|
|
69
106
|
| `intro` | `ReactNode` | | Contexto relevante no início do corpo, como texto ou `Alert`. |
|
|
70
|
-
| `children` | `(items, refetch) => ReactNode` | |
|
|
71
|
-
| `note` | `ReactNode` | | Contexto curto à esquerda da
|
|
72
|
-
| `actions` | `ReactNode` | | Ação à direita da
|
|
73
|
-
| `empty` | `(items) => boolean` | `items.length === 0` |
|
|
74
|
-
| `loading` | `boolean` | |
|
|
107
|
+
| `children` | `(items, refetch) => ReactNode` | | A composição dos itens. Carregamento, erro e vazio já são tratados pelo `ActionList`. |
|
|
108
|
+
| `note` | `ReactNode` | | Contexto curto à esquerda da linha de ações. O total de itens já aparece no rodapé do `ActionList`. |
|
|
109
|
+
| `actions` | `ReactNode` | | Ação à direita da linha de ações, em geral a criação do recurso. |
|
|
110
|
+
| `empty` | `(items) => boolean` | `items.length === 0` | Substitui a regra que decide o estado vazio. |
|
|
111
|
+
| `loading` | `boolean` | | Carregamento adicional somado ao da consulta, como uma consulta de que os `children` dependem. |
|
|
75
112
|
| `emptyMessage / errorMessage / retryLabel` | `string` | `'Nenhum resultado.'` / `'Não foi possível carregar.'` / `'Tentar de novo'` | Textos dos estados, herdados do `ActionList`; `retryLabel` nomeia a ação somente com ícone e seu tooltip. |
|
|
76
|
-
| `className` | `string` | `max-w-3xl` |
|
|
113
|
+
| `className` | `string` | `max-w-3xl` | Classes do `DialogContent`, em geral para ajustar a largura. |
|