@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
|
@@ -6,14 +6,17 @@ recursos e envia o estado correspondente no input. Filtros avançados aparecem n
|
|
|
6
6
|
os filtros aplicados permanecem visíveis como chips removíveis.
|
|
7
7
|
|
|
8
8
|
A tabela derivada não cria uma moldura própria. A superfície que recebe o `ActionList` define os
|
|
9
|
-
limites visuais da coleção; use `Table` diretamente quando a composição precisar da
|
|
10
|
-
`framed`.
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
9
|
+
limites visuais da coleção; use [`Table`](/ui/table) diretamente quando a composição precisar da
|
|
10
|
+
variante `framed`. Carregamento, erro e vazio usam o mesmo [`DataState`](/ui/data-state) das
|
|
11
|
+
demais coleções.
|
|
12
|
+
|
|
13
|
+
A barra mantém em uma única linha os controles declarados como `inline`: ela não quebra e não move
|
|
14
|
+
filtros para o modal por falta de espaço. Seletores de valor único acompanham o valor escolhido até
|
|
15
|
+
`20rem` e truncam o excedente; a busca varia entre `8rem` e `16rem` conforme a largura
|
|
16
|
+
disponível. Quando a barra ficar longa demais, declare como `advanced` os filtros que não precisam
|
|
17
|
+
ficar sempre à vista, como descreve a seção “Onde cada filtro aparece”. Recarregar e
|
|
18
|
+
exibição formam um `ButtonGroup` espaçado; `toolbarActions` acrescenta, depois deles, operações
|
|
19
|
+
ligadas ao recorte atual.
|
|
17
20
|
|
|
18
21
|
```tsx preview col
|
|
19
22
|
render(
|
|
@@ -31,8 +34,9 @@ render(
|
|
|
31
34
|
|
|
32
35
|
## Coleção nomeada
|
|
33
36
|
|
|
34
|
-
Em uma página, envolva a listagem com `Content
|
|
35
|
-
cabeçalho da coleção; busca, filtros e atualização permanecem na toolbar do
|
|
37
|
+
Em uma página, envolva a listagem com [`Content`](/ui/content). O título e a criação ocupam
|
|
38
|
+
extremos opostos do cabeçalho da coleção; busca, filtros e atualização permanecem na toolbar do
|
|
39
|
+
`ActionList`.
|
|
36
40
|
|
|
37
41
|
```tsx
|
|
38
42
|
<Content
|
|
@@ -46,7 +50,8 @@ cabeçalho da coleção; busca, filtros e atualização permanecem na toolbar do
|
|
|
46
50
|
```
|
|
47
51
|
|
|
48
52
|
Use `toolbarActions` somente quando a operação depender do recorte visível, como exportar os
|
|
49
|
-
resultados filtrados.
|
|
53
|
+
resultados filtrados. A propriedade recebe os nós já prontos: em uma ação somente com ícone, forneça
|
|
54
|
+
você mesmo o `aria-label` e o `Tooltip` com o nome da operação.
|
|
50
55
|
|
|
51
56
|
## Barra de filtros compartilhada
|
|
52
57
|
|
|
@@ -64,9 +69,9 @@ superfícies que não são listagens, como relatórios. O estado é controlado p
|
|
|
64
69
|
/>
|
|
65
70
|
```
|
|
66
71
|
|
|
67
|
-
Seletores inline de valor único
|
|
72
|
+
Seletores inline de valor único acompanham o valor selecionado até `20rem`. Valores maiores são
|
|
68
73
|
truncados no controle, enquanto o dropdown pode crescer além dele para preservar a opção.
|
|
69
|
-
Multiseletores mantêm `
|
|
74
|
+
Multiseletores mantêm `13rem`; no modal de filtros avançados, o seletor ocupa toda a largura.
|
|
70
75
|
`filterIcons` associa um ícone leading ao nome do filtro quando a superfície precisa reforçar
|
|
71
76
|
dimensões recorrentes, sem substituir o rótulo. Busca, filtros e período aparecem somente quando
|
|
72
77
|
declarados.
|
|
@@ -79,7 +84,7 @@ simples usam o valor vazio como padrão; por isso, opções como “Todos” tam
|
|
|
79
84
|
Use `periodPosition` para manter o período antes ou depois dos filtros inline. Quando ele precisa
|
|
80
85
|
apenas aparecer depois de um filtro específico, use `{ afterFilter: 'dateBasis' }`. Se tipo de data
|
|
81
86
|
e período formam uma única decisão, declare `period={{ basisFilter: 'dateBasis' }}`: o Opus os reúne
|
|
82
|
-
|
|
87
|
+
em um só controle, com ícone no início e uma única ação de limpar no fim. Quando a pessoa muda o tipo
|
|
83
88
|
ou o período padrão, essa ação aparece e restaura os dois valores. Se a âncora de `periodPosition`
|
|
84
89
|
não existir, o período permanece visível no fim dos filtros inline.
|
|
85
90
|
|
|
@@ -177,7 +182,7 @@ render(
|
|
|
177
182
|
action={docWorkspaceList}
|
|
178
183
|
input={{}}
|
|
179
184
|
cells={{
|
|
180
|
-
name: (w) => (
|
|
185
|
+
name: (w: { name: string }) => (
|
|
181
186
|
<a
|
|
182
187
|
href="#"
|
|
183
188
|
onClick={(e) => e.preventDefault()}
|
|
@@ -218,6 +223,65 @@ disponíveis e a quantidade de itens. Alterar busca, filtro, ordenação ou per
|
|
|
218
223
|
página. Durante a primeira consulta, `DataState` apresenta o carregamento; em atualizações
|
|
219
224
|
posteriores, a lista permanece visível com `aria-busy`.
|
|
220
225
|
|
|
226
|
+
## Ocupar a altura disponível
|
|
227
|
+
|
|
228
|
+
Por padrão, a lista cresce com os resultados e a rolagem acontece na janela ou no contêiner que a
|
|
229
|
+
hospeda. Quando a coleção é a região principal de uma tela de altura fixa, a barra de filtros e o
|
|
230
|
+
rodapé podem continuar visíveis enquanto só os resultados rolam. Para isso, declare
|
|
231
|
+
`layout="fill"` na [`Page`](/ui/page) e componha a lista com `PageBody` e
|
|
232
|
+
[`Content`](/ui/content), como no exemplo abaixo. Role a tabela para ver o cabeçalho fixo.
|
|
233
|
+
|
|
234
|
+
```tsx preview col
|
|
235
|
+
render(
|
|
236
|
+
<DocBrowserActionProvider>
|
|
237
|
+
<div className="h-80 w-full overflow-x-auto overflow-y-hidden rounded-lg border border-border">
|
|
238
|
+
<Page layout="fill">
|
|
239
|
+
<PageBody>
|
|
240
|
+
<Content level={1} variant="page">
|
|
241
|
+
<ContentHeader>
|
|
242
|
+
<ContentTitle>Workspaces</ContentTitle>
|
|
243
|
+
<ContentActions>
|
|
244
|
+
<Button>Criar workspace</Button>
|
|
245
|
+
</ContentActions>
|
|
246
|
+
</ContentHeader>
|
|
247
|
+
<ContentBody>
|
|
248
|
+
<ActionList action={docWorkspaceList} input={{}} />
|
|
249
|
+
</ContentBody>
|
|
250
|
+
</Content>
|
|
251
|
+
</PageBody>
|
|
252
|
+
</Page>
|
|
253
|
+
</div>
|
|
254
|
+
</DocBrowserActionProvider>,
|
|
255
|
+
);
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
A página limita a própria altura à do contêiner que a hospeda, normalmente o shell, e `PageBody`,
|
|
259
|
+
`Content` e `ContentBody` repassam essa altura até a lista, que passa a usar `layout="fill"` sem que
|
|
260
|
+
você o declare. Em uma [`Presentation`](/ui/presentation) de lista, basta `layout="fill"` no
|
|
261
|
+
próprio `Presentation`. Só as regiões que contêm a lista mudam: uma seção irmã, como um resumo acima
|
|
262
|
+
da coleção, mantém a altura do próprio conteúdo. Os demais filhos de cada região que repassa a
|
|
263
|
+
altura se esticam à largura dela; dê `self-start` a um botão que deva manter a largura do conteúdo.
|
|
264
|
+
|
|
265
|
+
Com a altura limitada, a barra de filtros, o `beforeContent` e o rodapé mantêm a própria altura. A
|
|
266
|
+
região de resultados ocupa o espaço restante e rola nos dois eixos; o rodapé se mede pelo conteúdo
|
|
267
|
+
e mantém a mesma altura com e sem paginador. Na tabela, o cabeçalho fica fixo no topo da região que
|
|
268
|
+
rola, sobre a cor da superfície e com uma linha inferior, e a moldura dos estados de carregamento,
|
|
269
|
+
erro e vazio ocupa a altura disponível. Em outras visualizações e em `children`, a rolagem interna
|
|
270
|
+
continua, mas não existe cabeçalho fixo.
|
|
271
|
+
|
|
272
|
+
A lista só assume `fill` sozinha quando é filha direta de `PageBody`, `ContentBody` ou do corpo de
|
|
273
|
+
uma `Presentation`, e a altura só chega até ela se não houver um contêiner próprio entre esses
|
|
274
|
+
componentes no caminho. Nos demais casos, a decisão é sua:
|
|
275
|
+
|
|
276
|
+
- Para a lista manter a altura dos resultados, como em uma seção secundária cuja rolagem pertence ao
|
|
277
|
+
`PageBody`, declare `layout="flow"`.
|
|
278
|
+
- Um contêiner próprio entre `ContentBody` e a lista, como um `TabsContent`, não repassa a altura, e
|
|
279
|
+
a lista volta a `flow`. Declare `layout="fill"` na lista e dê ao contêiner as classes
|
|
280
|
+
`flex min-h-0 flex-1 flex-col`.
|
|
281
|
+
- Dentro de [`Card`](/ui/card), [`Dialog`](/ui/dialog), [`Drawer`](/ui/drawer) ou
|
|
282
|
+
[`Pane`](/ui/pane), a lista não herda o `fill` da página: a altura do corpo pertence à
|
|
283
|
+
superfície.
|
|
284
|
+
|
|
221
285
|
## Ações em lote
|
|
222
286
|
|
|
223
287
|
`batch` acrescenta seleção à tabela. `can(item)` determina quais linhas podem participar: itens
|
|
@@ -250,6 +314,14 @@ fornece um `render`; `ActionList` preserva a mesma fonte de dados, filtros e est
|
|
|
250
314
|
“Tabela” aparece quando existem colunas.
|
|
251
315
|
|
|
252
316
|
```tsx preview col
|
|
317
|
+
type Workspace = {
|
|
318
|
+
id: string;
|
|
319
|
+
name: string;
|
|
320
|
+
client: string;
|
|
321
|
+
status: "active" | "onboarding" | "paused";
|
|
322
|
+
agents: number;
|
|
323
|
+
};
|
|
324
|
+
|
|
253
325
|
render(
|
|
254
326
|
<DocBrowserActionProvider>
|
|
255
327
|
<div className="w-full">
|
|
@@ -260,24 +332,20 @@ render(
|
|
|
260
332
|
gallery: {
|
|
261
333
|
label: "Galeria",
|
|
262
334
|
icon: <LayoutGrid />,
|
|
263
|
-
render: (workspaces) => (
|
|
335
|
+
render: (workspaces: Workspace[]) => (
|
|
264
336
|
<div className="grid grid-cols-2 gap-3">
|
|
265
337
|
{workspaces.map((w) => (
|
|
266
|
-
<
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
<
|
|
273
|
-
dict={docWorkspaceStatus}
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
<p className="mt-1 text-xs text-muted-foreground">
|
|
278
|
-
{w.agents} agentes.
|
|
279
|
-
</p>
|
|
280
|
-
</div>
|
|
338
|
+
<Card key={w.id}>
|
|
339
|
+
<CardHeader>
|
|
340
|
+
<CardTitle>{w.name}</CardTitle>
|
|
341
|
+
<CardDescription>
|
|
342
|
+
{w.agents === 1 ? "1 agente" : `${w.agents} agentes`}
|
|
343
|
+
</CardDescription>
|
|
344
|
+
<CardAction>
|
|
345
|
+
<DictionaryValue dict={docWorkspaceStatus} value={w.status} />
|
|
346
|
+
</CardAction>
|
|
347
|
+
</CardHeader>
|
|
348
|
+
</Card>
|
|
281
349
|
))}
|
|
282
350
|
</div>
|
|
283
351
|
),
|
|
@@ -334,28 +402,42 @@ Convenção compacta (defaults omitidos): `?q=…&sort=chave:dir&status=…&view
|
|
|
334
402
|
|
|
335
403
|
## Composição dos itens
|
|
336
404
|
|
|
337
|
-
Passe `children` para substituir a tabela por uma composição própria
|
|
338
|
-
estados de carregamento, erro e vazio continuam sendo
|
|
405
|
+
Passe `children` para substituir a tabela por uma composição própria, como uma lista de
|
|
406
|
+
[`Item`](/ui/item). A barra de filtros e os estados de carregamento, erro e vazio continuam sendo
|
|
407
|
+
tratados por `ActionList`. O contrato não leva o tipo do item até o componente: anote o parâmetro de
|
|
408
|
+
`children` (ou de `render`, em uma visualização) ou declare os genéricos, como em
|
|
409
|
+
`<ActionList<Input, Workspace>>`. Sem uma das duas formas, os itens chegam como `unknown`.
|
|
339
410
|
|
|
340
411
|
```tsx preview col
|
|
412
|
+
type Workspace = {
|
|
413
|
+
id: string;
|
|
414
|
+
name: string;
|
|
415
|
+
client: string;
|
|
416
|
+
status: "active" | "onboarding" | "paused";
|
|
417
|
+
agents: number;
|
|
418
|
+
};
|
|
419
|
+
|
|
341
420
|
render(
|
|
342
421
|
<DocBrowserActionProvider>
|
|
343
422
|
<div className="w-full">
|
|
344
423
|
<ActionList action={docWorkspaceList} input={{}}>
|
|
345
|
-
{(workspaces) => (
|
|
346
|
-
<
|
|
347
|
-
{workspaces.map((w) => (
|
|
348
|
-
<
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
<
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
424
|
+
{(workspaces: Workspace[]) => (
|
|
425
|
+
<ItemGroup variant="framed">
|
|
426
|
+
{workspaces.map((w, index) => (
|
|
427
|
+
<React.Fragment key={w.id}>
|
|
428
|
+
{index > 0 && <ItemSeparator />}
|
|
429
|
+
<Item>
|
|
430
|
+
<ItemHeader>
|
|
431
|
+
<ItemTitle>{w.name}</ItemTitle>
|
|
432
|
+
<ItemDescription>Cliente {w.client}.</ItemDescription>
|
|
433
|
+
</ItemHeader>
|
|
434
|
+
<ItemActions>
|
|
435
|
+
<DictionaryValue dict={docWorkspaceStatus} value={w.status} />
|
|
436
|
+
</ItemActions>
|
|
437
|
+
</Item>
|
|
438
|
+
</React.Fragment>
|
|
357
439
|
))}
|
|
358
|
-
</
|
|
440
|
+
</ItemGroup>
|
|
359
441
|
)}
|
|
360
442
|
</ActionList>
|
|
361
443
|
</div>
|
|
@@ -403,9 +485,9 @@ chamar a action.
|
|
|
403
485
|
|
|
404
486
|
| Propriedade | Tipo | Padrão | Descrição |
|
|
405
487
|
| ----------------------- | ----------------------------------------------------------------------------------------------------------- | ----------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
406
|
-
| `action` | `
|
|
407
|
-
| `input` | `TInput` | | O
|
|
408
|
-
| `layout` | `'flow' \| 'fill'` | `'flow'`
|
|
488
|
+
| `action` | `ListActionLike` | | A ListAction do Opus (kind list, output = item). A paginação envia `limit`/`page` e usa o `total` devolvido. |
|
|
489
|
+
| `input` | `TInput` | | O escopo base, como `{ workspaceId }`. A toolbar acrescenta busca, filtros e paginação sem sobrescrever essas chaves. |
|
|
490
|
+
| `layout` | `'flow' \| 'fill'` | `'fill'` como filha direta de `PageBody`, `ContentBody` ou do corpo da `Presentation` em uma página `fill`; `'flow'` nos demais casos | Em `fill`, ocupa a altura de um ancestral limitado e rola somente a região de resultados; na tabela, o cabeçalho fica fixo. Sem ancestral limitado, equivale a `flow`. |
|
|
409
491
|
| `cells` | `Record<string, (item) => ReactNode>` | | Células custom por cima das colunas do contrato (chave = column.key). |
|
|
410
492
|
| `filterOptions` | `Record<string, SelectOption[]>` | | Opções de runtime para os filtros select/lookup (chave = nome do filtro). |
|
|
411
493
|
| `filterDefaults` | `Record<string, string>` | | Valores de repouso aplicados à consulta; o `X` só aparece quando o filtro diverge deles e retorna a eles. |
|
|
@@ -415,7 +497,7 @@ chamar a action.
|
|
|
415
497
|
| `period` | `{ basisFilter: string }` | | Reúne o período e o filtro inline indicado em um único controle. |
|
|
416
498
|
| `views` | `Record<string, ActionListView<TItem>>` | | Visualizações alternativas `{ label, icon?, render }`; o seletor alterna entre a tabela e estas. |
|
|
417
499
|
| `beforeContent` | `ReactNode` | | Conteúdo entre a toolbar e o corpo, como um resumo que reage ao recorte atual. |
|
|
418
|
-
| `columns` | `ActionListColumn<TItem>[]` | | Tabela
|
|
500
|
+
| `columns` | `ActionListColumn<TItem>[]` | | Tabela explícita, que substitui as colunas declaradas no contrato. |
|
|
419
501
|
| `children` | `(items, refetch) => ReactNode` | | Modo composição: layout livre; a toolbar segue. Tem precedência sobre columns. |
|
|
420
502
|
| `batch` | `ActionListBatchAction[]` | | Ações em lote: `{ label, can?, run, confirm?: { title, message? }, destructive? }` — liga a multi-seleção. |
|
|
421
503
|
| `rowId` | `(item) => string` | `item.id` | Identidade da linha para seleção. |
|
|
@@ -427,5 +509,5 @@ chamar a action.
|
|
|
427
509
|
| `errorMessage` | `string` | `'Não foi possível carregar.'` | Título do aviso de erro; a ação de tentar de novo refaz a consulta. |
|
|
428
510
|
| `retryLabel` | `string` | `'Tentar de novo'` | Nome acessível e tooltip da ação de recuperação. |
|
|
429
511
|
| `onRowClick` | `(item: TItem) => void` | | Clique na linha (ex.: navegar para o detalhe) — só na tabela. |
|
|
430
|
-
| `toolbarActions` | `ReactNode` | | Operações ligadas ao recorte atual, no fim da barra e separadas do grupo de controles.
|
|
431
|
-
| `rowActions` | `(item: TItem) => ReactNode` | | Ações por linha (coluna final, à direita). A partir de duas, entram
|
|
512
|
+
| `toolbarActions` | `ReactNode` | | Operações ligadas ao recorte atual, no fim da barra e separadas do grupo de controles. Os nós são renderizados como recebidos: nome acessível e tooltip de uma ação somente com ícone ficam com o consumidor. |
|
|
513
|
+
| `rowActions` | `(item: TItem) => ReactNode` | | Ações por linha (coluna final, à direita). A partir de duas, entram em um grupo com intervalo compacto; uma só fica solta, sem grupo. Cliques ali não disparam o `onRowClick`. |
|
|
@@ -13,9 +13,11 @@ de tradução ou estiver ausente, o botão usa `action.name`.
|
|
|
13
13
|
|
|
14
14
|
## Confirmação declarada no contrato
|
|
15
15
|
|
|
16
|
-
Quando a action declara `confirm`, o componente monta o diálogo
|
|
17
|
-
|
|
18
|
-
|
|
16
|
+
Quando a action declara `confirm`, o componente monta o diálogo antes de executar. Com
|
|
17
|
+
`confirm.destructive: true` no contrato, o gatilho e o botão de confirmação usam o contexto
|
|
18
|
+
`danger`. Use a propriedade `confirm` somente quando esta ocorrência precisar de uma mensagem
|
|
19
|
+
diferente da declarada no contrato; ela substitui os textos, mas o caráter destrutivo continua
|
|
20
|
+
vindo do contrato.
|
|
19
21
|
|
|
20
22
|
```tsx preview
|
|
21
23
|
<DocBrowserActionProvider>
|
|
@@ -41,20 +43,35 @@ confirm: {
|
|
|
41
43
|
Com `icon`, o botão exibe somente o ícone no quadrado `icon-xs` da escala (1.5rem, a ação que mora
|
|
42
44
|
dentro de uma linha ou card) e usa `label`, ou `action.label`, no tooltip e no nome acessível. Uma
|
|
43
45
|
composição que peça mais presença, como a barra do `PageHeader`, declara `size="icon"`. O clique
|
|
44
|
-
não aciona o item clicável ao redor.
|
|
46
|
+
não aciona o item clicável ao redor.
|
|
47
|
+
|
|
48
|
+
Em uma lista, várias linhas repetem a mesma ação. Inclua o alvo em `label`, como `Excluir Unidade
|
|
49
|
+
Centro`, para que cada botão tenha um nome acessível distinto. `itemLabel` identifica o registro na
|
|
50
|
+
pergunta de confirmação.
|
|
45
51
|
|
|
46
52
|
```tsx
|
|
53
|
+
// No contrato:
|
|
54
|
+
confirm: {
|
|
55
|
+
title: 'Excluir a unidade?',
|
|
56
|
+
message: 'Os agendamentos desta unidade também serão removidos.',
|
|
57
|
+
confirmLabel: 'Excluir',
|
|
58
|
+
destructive: true,
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// Na linha da lista:
|
|
47
62
|
<ActionTrigger
|
|
48
63
|
action={unitDeleteContract}
|
|
49
64
|
input={{ id: unit.id }}
|
|
50
65
|
icon={<Trash2 />}
|
|
51
|
-
label=
|
|
66
|
+
label={`Excluir ${unit.name}`}
|
|
52
67
|
itemLabel={unit.name}
|
|
53
68
|
/>
|
|
54
69
|
```
|
|
55
70
|
|
|
56
|
-
|
|
57
|
-
|
|
71
|
+
Sem `confirmLabel` no contrato ou `actionLabel` na propriedade `confirm`, o botão de confirmação
|
|
72
|
+
usa o `label` da action, como `Excluir`. O nome longo passado em `label` serve à linha; na pergunta,
|
|
73
|
+
o alvo já aparece por `itemLabel`. O `label` do gatilho só nomeia o botão de confirmação quando a
|
|
74
|
+
action não declara `label`.
|
|
58
75
|
|
|
59
76
|
## Erro que a pessoa entende
|
|
60
77
|
|
|
@@ -80,9 +97,9 @@ um atalho, um arrastar, um item de menu.
|
|
|
80
97
|
|---|---|---|---|
|
|
81
98
|
| `action` | `SimpleContract<TInput, TData>` | | A SimpleAction do Opus — label, messages e confirm vêm do contrato. |
|
|
82
99
|
| `input` | `TInput` | | O que a action recebe — geralmente { id }. |
|
|
83
|
-
| `label` | `string` | `action.label` quando é texto; senão `action.name` |
|
|
84
|
-
| `context / variant / size` | `do Button` | gatilho: `primary`/`solid`; `danger` quando
|
|
85
|
-
| `confirm` | `{ title, body?, actionLabel?, cancelLabel? }` | | Confirmação
|
|
100
|
+
| `label` | `string` | `action.label` quando é texto; senão `action.name` | Texto do botão ou, com `icon`, seu nome acessível e tooltip. Só vira o botão de confirmação quando a action não declara `label` e nem o contrato nem `confirm` declaram outro rótulo. |
|
|
101
|
+
| `context / variant / size` | `do Button` | gatilho: `primary`/`solid`; `danger` quando `action.confirm.destructive` é `true`; no modo ícone, `ghost` e `neutral` (ou `danger` se destrutiva) / `default`, ou `icon-xs` com `icon` | Visual do gatilho; `context` explícito vence. O botão de confirmar é sempre `solid`: `danger` quando `action.confirm.destructive` é `true`, senão a prop `context` do gatilho (ou `primary`). |
|
|
102
|
+
| `confirm` | `{ title, body?, actionLabel?, cancelLabel? }` | | Confirmação para esta ocorrência; substitui os textos do `confirm` do contrato. Sem `actionLabel`, o botão de confirmar usa `action.label`. O contexto `danger` continua dependendo de `action.confirm.destructive`. |
|
|
86
103
|
| `disabled` | `boolean` | `false` | Desabilita o botão independentemente da execução em andamento. |
|
|
87
104
|
| `onSuccess` | `(data: TData) => void` | | Pós-sucesso (cache já invalidado pelo action.invalidates). |
|
|
88
105
|
| `onLoadingChange` | `(loading: boolean) => void` | | Informa início e fim da execução a quem coordena bloqueio entre várias actions. |
|
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
Use `ActionView` para carregar um recurso por uma `ViewAction` e manter carregamento e erro no
|
|
4
4
|
mesmo fluxo. No exemplo, alterne entre os workspaces para observar o carregamento e a recuperação de
|
|
5
|
-
erro. O consumidor compõe somente o conteúdo disponível.
|
|
5
|
+
erro. O consumidor compõe somente o conteúdo disponível, aqui com [`Detail`](/ui/detail). Para uma
|
|
6
|
+
coleção, use [`ActionList`](/ui/action-list).
|
|
6
7
|
|
|
7
8
|
```tsx preview col
|
|
8
9
|
const [id, setId] = useState('empresa-x')
|
|
@@ -10,26 +11,25 @@ const [id, setId] = useState('empresa-x')
|
|
|
10
11
|
render(
|
|
11
12
|
<DocBrowserActionProvider>
|
|
12
13
|
<div className="w-full space-y-3">
|
|
13
|
-
<
|
|
14
|
+
<ButtonGroup mode="spaced">
|
|
14
15
|
<Button variant="outline" size="sm" onClick={() => setId('empresa-x')}>Empresa X</Button>
|
|
15
16
|
<Button variant="outline" size="sm" onClick={() => setId('empresa-y')}>Empresa Y</Button>
|
|
16
17
|
<Button variant="outline" size="sm" onClick={() => setId('sessao-fantasma')}>Inexistente (erro)</Button>
|
|
17
|
-
</
|
|
18
|
-
<
|
|
18
|
+
</ButtonGroup>
|
|
19
|
+
<Card className="p-4">
|
|
19
20
|
<ActionView action={docWorkspaceView} input={{ id }}>
|
|
20
21
|
{(ws) => (
|
|
21
|
-
<
|
|
22
|
-
<
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
</div>
|
|
22
|
+
<DetailGroup columns={3}>
|
|
23
|
+
<DetailField label="Workspace" value={ws.name} />
|
|
24
|
+
<DetailField label="Cliente" value={ws.client} />
|
|
25
|
+
<DetailField
|
|
26
|
+
label="Status"
|
|
27
|
+
value={<DictionaryValue dict={docWorkspaceStatus} value={ws.status} />}
|
|
28
|
+
/>
|
|
29
|
+
</DetailGroup>
|
|
30
30
|
)}
|
|
31
31
|
</ActionView>
|
|
32
|
-
</
|
|
32
|
+
</Card>
|
|
33
33
|
</div>
|
|
34
34
|
</DocBrowserActionProvider>,
|
|
35
35
|
)
|