@softize/opus 30.0.0 → 31.1.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 +123 -0
- package/bin/lib/check.mjs +109 -101
- package/bin/lib/copy.mjs +2973 -1801
- package/docs/adr/0043-neutral-surfaces-and-interactions-use-opaque-role-tokens.md +52 -0
- package/docs/adr/0044-neutral-appearance-derives-from-bounded-axes-per-mode.md +27 -2
- package/docs/adr/0060-surface-composition-separates-chrome-and-intro.md +142 -0
- package/docs/adr/0064-action-list-com-itens-e-fontes-externas.md +47 -0
- package/docs/adr/0065-presentation-composes-settings-sections.md +295 -0
- package/docs/adr/0066-civil-date-input-and-calendar-list.md +28 -0
- package/docs/adr/README.md +6 -0
- package/package.json +1 -1
- package/registry/skills/build-opus-ui/SKILL.md +21 -19
- package/registry/skills/build-opus-ui/references/evaluations.md +13 -11
- package/registry/skills/build-opus-ui/references/ui-patterns.md +24 -27
- package/src/core/presentation.ts +938 -32
- package/src/core/types.ts +2 -0
- package/src/ui/components/patterns/form.tsx +22 -1
- package/src/ui/components/patterns/grouped-list.ts +2 -2
- package/src/ui/components/patterns/list-calendar.tsx +129 -0
- package/src/ui/components/patterns/list.tsx +612 -382
- package/src/ui/components/patterns/page-heading-context.tsx +12 -5
- package/src/ui/components/patterns/page.tsx +227 -197
- package/src/ui/components/patterns/presentation-fields.tsx +246 -0
- package/src/ui/components/patterns/presentation-sections.tsx +494 -0
- package/src/ui/components/patterns/presentation.tsx +1142 -229
- package/src/ui/components/patterns/structural-header.tsx +23 -32
- package/src/ui/components/patterns/surface-anatomy.ts +27 -217
- package/src/ui/components/patterns/surface.tsx +19 -29
- package/src/ui/components/patterns/trigger.tsx +10 -2
- package/src/ui/components/primitives/calendar.tsx +39 -18
- package/src/ui/components/primitives/close-button.tsx +11 -3
- package/src/ui/components/primitives/command.tsx +2 -8
- package/src/ui/components/primitives/date-input.tsx +276 -0
- package/src/ui/components/primitives/detail.tsx +1 -1
- package/src/ui/components/primitives/dialog.tsx +19 -81
- package/src/ui/components/primitives/drawer.tsx +17 -79
- package/src/ui/components/primitives/field.tsx +1 -1
- package/src/ui/components/primitives/pagination.tsx +3 -2
- package/src/ui/components/primitives/table.tsx +1 -1
- package/src/ui/components/primitives/tabs.tsx +13 -2
- package/src/ui/docs/content/action-form.md +6 -1
- package/src/ui/docs/content/action-list.md +156 -68
- package/src/ui/docs/content/action-trigger.md +5 -0
- package/src/ui/docs/content/button.md +5 -6
- package/src/ui/docs/content/calendar-month-view.md +50 -0
- package/src/ui/docs/content/calendar.md +6 -1
- package/src/ui/docs/content/command.md +62 -50
- package/src/ui/docs/content/compositions.md +129 -459
- package/src/ui/docs/content/date-input.md +67 -0
- package/src/ui/docs/content/dialog.md +44 -112
- package/src/ui/docs/content/drawer.md +44 -103
- package/src/ui/docs/content/field.md +2 -1
- package/src/ui/docs/content/input.md +3 -0
- package/src/ui/docs/content/page.md +204 -412
- package/src/ui/docs/content/presentation.md +371 -23
- package/src/ui/docs/content/separator.md +1 -1
- package/src/ui/docs/content/surface.md +65 -120
- package/src/ui/docs/content/tokens.md +18 -4
- package/src/ui/docs/registry.tsx +38 -9
- package/src/ui/drivers/context.tsx +11 -4
- package/src/ui/drivers/react.tsx +27 -7
- package/src/ui/meta.ts +17 -6
- package/src/ui/react.tsx +41 -8
- package/src/ui/theme.css +44 -33
|
@@ -22,8 +22,8 @@ A barra distribui os controles `inline` em mais de uma linha quando necessário,
|
|
|
22
22
|
ordem. Ela não move filtros automaticamente para o modal. Seletores de valor único acompanham o
|
|
23
23
|
valor escolhido até `20rem` e truncam o excedente; a busca varia entre `8rem` e `16rem`.
|
|
24
24
|
Declare como `advanced` os filtros que não precisam ficar sempre à vista, como descreve a seção
|
|
25
|
-
“Onde cada filtro aparece”.
|
|
26
|
-
`toolbarActions` acrescenta, depois deles,
|
|
25
|
+
“Onde cada filtro aparece”. As opções da lista e os filtros avançados formam um `ButtonGroup` espaçado;
|
|
26
|
+
`toolbarActions` acrescenta, depois deles, ações da coleção, como criar, importar e exportar.
|
|
27
27
|
|
|
28
28
|
```tsx preview col
|
|
29
29
|
render(
|
|
@@ -41,24 +41,30 @@ render(
|
|
|
41
41
|
|
|
42
42
|
## Coleção nomeada
|
|
43
43
|
|
|
44
|
-
Em uma página,
|
|
45
|
-
|
|
46
|
-
|
|
44
|
+
Em uma página, use [`Page`](/ui/page) para o título e ações gerais. Ações da coleção
|
|
45
|
+
ficam na barra do `ActionList`, inclusive a criação, mesmo sem depender dos filtros atuais.
|
|
46
|
+
Em abas, a barra acompanha a lista do painel ativo.
|
|
47
47
|
|
|
48
48
|
```tsx
|
|
49
|
-
<
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
>
|
|
55
|
-
|
|
56
|
-
</
|
|
49
|
+
<Page title="Workspaces" layout="fill">
|
|
50
|
+
<ActionList
|
|
51
|
+
action={workspaceList}
|
|
52
|
+
input={{}}
|
|
53
|
+
toolbarActions={
|
|
54
|
+
<Button aria-label="Criar workspace" onClick={openCreate}>
|
|
55
|
+
Criar
|
|
56
|
+
</Button>
|
|
57
|
+
}
|
|
58
|
+
/>
|
|
59
|
+
</Page>
|
|
57
60
|
```
|
|
58
61
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
+
O botão exibe “Criar”; seu nome acessível e o formulário identificam o recurso.
|
|
63
|
+
Menu com vários tipos de criação preserva os nomes específicos. Operações sobre a seleção
|
|
64
|
+
usam `batchActions`, e ações de um registro usam `rowActions`.
|
|
65
|
+
|
|
66
|
+
`toolbarActions` recebe os nós já prontos e aparece também em visualizações sem filtros
|
|
67
|
+
ou tabela. Em uma ação somente com ícone, forneça `aria-label` e tooltip.
|
|
62
68
|
|
|
63
69
|
## Barra de filtros compartilhada
|
|
64
70
|
|
|
@@ -228,7 +234,7 @@ Declare `grouping.fields` quando uma dimensão enumerável puder organizar a tab
|
|
|
228
234
|
recorte de negócio. Cada campo precisa ser um filtro `select` ou `lookup`; texto, número e data não
|
|
229
235
|
são dimensões de agrupamento. O filtro pode aceitar uma ou várias opções: cada consulta de grupo
|
|
230
236
|
envia um único valor na forma declarada. A lista continua plana por padrão, e a pessoa escolhe
|
|
231
|
-
**Agrupar por** em **
|
|
237
|
+
**Agrupar por** em **Opções da lista**.
|
|
232
238
|
|
|
233
239
|
```ts
|
|
234
240
|
filters: {
|
|
@@ -261,9 +267,17 @@ aplicados à mesma dimensão restringem os grupos exibidos.
|
|
|
261
267
|
|
|
262
268
|
## Paginação e carregamento
|
|
263
269
|
|
|
264
|
-
|
|
270
|
+
Para coleções pequenas que devem aparecer por inteiro, declare `paginate: false` no
|
|
271
|
+
contrato da list action. ActionList omite `page` e `limit` da consulta, do estado lido
|
|
272
|
+
da URL e dos links gerados; não exibe rodapé nem seletor de quantidade. O handler deve
|
|
273
|
+
devolver todos os itens que atendem à busca e aos filtros. O componente não busca páginas
|
|
274
|
+
adicionais em segundo plano nem aumenta o limite artificialmente. A opção também é
|
|
275
|
+
respeitada pelas listas renderizadas por Presentation, sem configuração visual duplicada.
|
|
276
|
+
|
|
277
|
+
Nos demais modos, `ActionList` envia `limit`, definido por `pageSize`, e `page` no input. O handler aplica o recorte e
|
|
265
278
|
devolve `total` na resposta paginada. Quando existe total, o rodapé mostra a página atual, os links
|
|
266
|
-
disponíveis e a quantidade de itens.
|
|
279
|
+
disponíveis e a quantidade de itens. Com total zero, o rodapé e seu divisor não aparecem:
|
|
280
|
+
a mensagem de vazio permanece como indicação do resultado. Alterar busca, filtro, ordenação ou período retorna à primeira
|
|
267
281
|
página. Durante a primeira consulta, `DataState` apresenta o carregamento; em atualizações
|
|
268
282
|
posteriores, a lista permanece visível com `aria-busy`.
|
|
269
283
|
|
|
@@ -279,20 +293,8 @@ rodapé podem continuar visíveis enquanto só os resultados rolam. Para isso, d
|
|
|
279
293
|
render(
|
|
280
294
|
<DocBrowserActionProvider>
|
|
281
295
|
<div className="h-80 w-full overflow-x-auto overflow-y-hidden rounded-lg border border-border">
|
|
282
|
-
<Page layout="fill">
|
|
283
|
-
<
|
|
284
|
-
<Surface as="section" level={1}>
|
|
285
|
-
<SurfaceHeader>
|
|
286
|
-
<SurfaceTitle>Workspaces</SurfaceTitle>
|
|
287
|
-
<SurfaceActions>
|
|
288
|
-
<Button>Criar workspace</Button>
|
|
289
|
-
</SurfaceActions>
|
|
290
|
-
</SurfaceHeader>
|
|
291
|
-
<SurfaceBody>
|
|
292
|
-
<ActionList action={docWorkspaceList} input={{}} />
|
|
293
|
-
</SurfaceBody>
|
|
294
|
-
</Surface>
|
|
295
|
-
</PageBody>
|
|
296
|
+
<Page title="Workspaces" layout="fill">
|
|
297
|
+
<ActionList action={docWorkspaceList} input={{}} toolbarActions={<Button aria-label="Criar workspace">Criar</Button>} />
|
|
296
298
|
</Page>
|
|
297
299
|
</div>
|
|
298
300
|
</DocBrowserActionProvider>,
|
|
@@ -319,8 +321,8 @@ componentes no caminho. Nos demais casos, a decisão é sua:
|
|
|
319
321
|
|
|
320
322
|
- Para a lista manter a altura dos resultados, como em uma seção secundária cuja rolagem pertence ao
|
|
321
323
|
`PageBody`, declare `layout="flow"`.
|
|
322
|
-
-
|
|
323
|
-
|
|
324
|
+
- `TabsPanel` repassa a altura disponível à lista. Um contêiner próprio sem essa integração
|
|
325
|
+
interrompe a herança: declare `layout="fill"` na lista e dê ao contêiner as classes
|
|
324
326
|
`flex min-h-0 flex-1 flex-col`.
|
|
325
327
|
- Dentro de [`Surface`](/ui/surface), [`Dialog`](/ui/dialog), [`Drawer`](/ui/drawer) ou
|
|
326
328
|
[`Pane`](/ui/pane), a lista não herda o `fill` da página: a altura do corpo pertence à
|
|
@@ -442,13 +444,17 @@ filters: {
|
|
|
442
444
|
|
|
443
445
|
## Exibição e estado na URL
|
|
444
446
|
|
|
445
|
-
O botão
|
|
447
|
+
O botão **Opções da lista** reúne as preferências disponíveis para a visualização. Na tabela, permite
|
|
446
448
|
escolher a ordenação, inverter sua direção, agrupar e mostrar ou ocultar colunas, inclusive as
|
|
447
|
-
declaradas com `hidden`;
|
|
448
|
-
página. Um ponto sinaliza quando alguma preferência diverge do padrão. O rodapé explicita a
|
|
449
|
+
declaradas com `hidden`; nas listas paginadas, permite alterar a quantidade de itens por
|
|
450
|
+
página. Quando não há preferências disponíveis, o botão não aparece. Um ponto sinaliza quando alguma preferência diverge do padrão. O rodapé explicita a
|
|
449
451
|
ordenação e o agrupamento ativos junto da paginação e do total. Busca, ordenação, filtros,
|
|
450
452
|
visualização, colunas e limite podem ser serializados na query string pelos helpers do componente:
|
|
451
453
|
|
|
454
|
+
Operações usam `invalidates` para atualizar os dados, e o consumidor pode manter suas
|
|
455
|
+
assinaturas de eventos. Em caso de falha, o estado de erro oferece **Tentar novamente**
|
|
456
|
+
diretamente. Não há comando de recarga manual no menu nem polling automático no ActionList.
|
|
457
|
+
|
|
452
458
|
Cada campo de `sort.fields` precisa de uma coluna com rótulo textual para aparecer no seletor e no
|
|
453
459
|
resumo do rodapé; a coluna pode estar `hidden`. Campos sem coluna continuam válidos para o handler e
|
|
454
460
|
para uma ordenação padrão, mas o Opus não expõe seu identificador técnico na interface. **Sem
|
|
@@ -468,9 +474,55 @@ restaurá-lo.
|
|
|
468
474
|
|
|
469
475
|
Convenção compacta (defaults omitidos): `?q=…&sort=key:dir&status=…&view=board&cols=a,b,c&limit=25`.
|
|
470
476
|
|
|
477
|
+
## Itens conectados
|
|
478
|
+
|
|
479
|
+
Para coleções que apresentam um nome, uma descrição e ações por registro, declare os campos
|
|
480
|
+
em `item`. O ActionList monta a moldura e os separadores com ItemGroup; mantém carregamento,
|
|
481
|
+
erro, recuperação e vazio. `title` coloca o nome da coleção junto das `toolbarActions`.
|
|
482
|
+
Nome e descrição ocupam uma linha cada, com reticências quando ultrapassam a largura disponível.
|
|
483
|
+
|
|
484
|
+
```tsx preview col
|
|
485
|
+
render(
|
|
486
|
+
<DocBrowserActionProvider>
|
|
487
|
+
<ActionList
|
|
488
|
+
action={docWorkspaceList}
|
|
489
|
+
input={{}}
|
|
490
|
+
title="Workspaces"
|
|
491
|
+
item={{ title: "name", description: "client" }}
|
|
492
|
+
/>
|
|
493
|
+
</DocBrowserActionProvider>
|
|
494
|
+
);
|
|
495
|
+
```
|
|
496
|
+
|
|
497
|
+
Os nomes em `item` são campos diretos do resultado, com valores textuais ou numéricos.
|
|
498
|
+
O objeto é serializável. `rowActions` recebe o registro e um contexto com `items`, `total`,
|
|
499
|
+
`isFetching`, `isError` e `refetch`; `toolbarActions` também pode ser uma função desse contexto.
|
|
500
|
+
O modo de itens não combina `children`, `views` ou seleção em lote. `onRowClick` continua
|
|
501
|
+
restrito à tabela; ações dos itens ficam nos controles explícitos de `rowActions`.
|
|
502
|
+
|
|
503
|
+
Com uma página, esse modo dispensa o rodapé. Com mais resultados, mantém a paginação.
|
|
504
|
+
Depois de remover o último item de uma página, volta à última página válida. A tabela conserva
|
|
505
|
+
seu rodapé e seus controles existentes.
|
|
506
|
+
|
|
507
|
+
### Fonte governada por outro serviço
|
|
508
|
+
|
|
509
|
+
Quando a coleção pertence a uma integração que já possui cliente e autorização, `source`
|
|
510
|
+
conecta esse cliente sem criar uma action artificial. Declare uma chave com o escopo de acesso
|
|
511
|
+
e um `load(input, { signal })` que retorna `{ items, total, cursor }`. A fonte deve respeitar
|
|
512
|
+
`page` e `limit`; se o serviço retorna todos os registros, o adapter pagina o conjunto completo.
|
|
513
|
+
|
|
514
|
+
A fonte substitui `action`, exige QueryClientProvider e dispensa OpusProvider quando não há
|
|
515
|
+
actions nos controles. Seu cache é separado das actions, não reaproveita dados entre escopos e
|
|
516
|
+
é descartado após a desmontagem. Falhas usam a mensagem pública `errorMessage` e oferecem
|
|
517
|
+
recuperação; detalhes técnicos do erro não são exibidos. Dados sensíveis usados pelo cliente
|
|
518
|
+
externo devem permanecer no adapter, fora dos itens retornados.
|
|
519
|
+
|
|
520
|
+
`source` é runtime: seu loader não entra no JSON. Uma definição serializável futura deverá
|
|
521
|
+
referenciar uma fonte registrada, enquanto `item` já descreve a apresentação sem JSX.
|
|
522
|
+
|
|
471
523
|
## Composição dos itens
|
|
472
524
|
|
|
473
|
-
|
|
525
|
+
Quando `item` não representar a composição necessária, passe `children` para substituir a tabela por uma composição própria, como uma lista de
|
|
474
526
|
[`Item`](/ui/item). A barra de filtros e os estados de carregamento, erro e vazio continuam sendo
|
|
475
527
|
tratados por `ActionList`. O contrato não leva o tipo do item até o componente: anote o parâmetro de
|
|
476
528
|
`children` (ou de `render`, em uma visualização) ou declare os genéricos, como em
|
|
@@ -516,6 +568,26 @@ render(
|
|
|
516
568
|
);
|
|
517
569
|
```
|
|
518
570
|
|
|
571
|
+
## Período controlado pelo consumidor
|
|
572
|
+
|
|
573
|
+
Use `periodControl` quando a coleção precisar de uma navegação temporal própria, como um mês de expediente. O controle ocupa o mesmo espaço do seletor padrão e respeita `periodPosition`, inclusive a composição com `period.basisFilter`.
|
|
574
|
+
|
|
575
|
+
Com uma action que recebe `month`, mantenha o valor no consumidor e envie-o no input:
|
|
576
|
+
|
|
577
|
+
```tsx
|
|
578
|
+
const [month, setMonth] = useState("2026-11")
|
|
579
|
+
|
|
580
|
+
<ActionList
|
|
581
|
+
action={deliveryListContract}
|
|
582
|
+
input={{ month }}
|
|
583
|
+
periodControl={<Input type="month" value={month} onChange={(event) => setMonth(event.target.value)} />}
|
|
584
|
+
/>
|
|
585
|
+
```
|
|
586
|
+
|
|
587
|
+
Quando `periodControl` está presente, ActionList ignora os presets de `action.periods` e os campos `period`, `from` e `to` do estado da lista, inclusive os recuperados da URL. O intervalo vem do `input` do consumidor; não há filtro temporal oculto. Sem o controle personalizado, o comportamento padrão permanece. Ao hidratar detalhes pelo helper `listStateToInput`, passe `applyPeriod: false` para manter o mesmo recorte.
|
|
588
|
+
|
|
589
|
+
Para distribuir os resultados pelos dias, componha a extensão `views` com [CalendarMonthView](/ui/calendar-month-view). A lista continua responsável pela consulta e pelos estados assíncronos.
|
|
590
|
+
|
|
519
591
|
## Propriedades de ActionFilterBar
|
|
520
592
|
|
|
521
593
|
| Propriedade | Tipo | Padrão | Descrição |
|
|
@@ -528,6 +600,7 @@ render(
|
|
|
528
600
|
| `filterIcons` | `Record<string, ReactNode>` | | Associa um ícone leading ao controle de cada filtro. |
|
|
529
601
|
| `advancedFilters` | `{ columns?: 1 \| 2 \| 3; sectionIcons?: Record<string, ReactNode>; sectionVariant?: 'plain' \| 'framed' }` | `{ columns: 1, sectionVariant: 'plain' }` | Define as colunas, os ícones e o tratamento das seções; o Opus deriva a largura correspondente. |
|
|
530
602
|
| `periodPosition` | `'before' \| 'after' \| { afterFilter: string }` | `'before'` | Posiciona o período antes, depois ou imediatamente após um filtro inline. |
|
|
603
|
+
| `periodControl` | `ReactNode` | — | Controle temporal do consumidor. Substitui o seletor padrão; em ActionList, também desativa a aplicação automática dos presets ao input. |
|
|
531
604
|
| `period` | `{ basisFilter: string }` | | Reúne o período e o filtro inline indicado em um único controle. |
|
|
532
605
|
| `onRefresh` | `() => Promise<void> \| void` | | Exibe a ação de recarregar e executa a consulta do consumidor. |
|
|
533
606
|
| `refreshing` | `boolean` | `false` | Desabilita e anima a ação de recarregar durante a consulta. |
|
|
@@ -564,32 +637,47 @@ para fora de `toolbarActions`.
|
|
|
564
637
|
|
|
565
638
|
## Propriedades de ActionList
|
|
566
639
|
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
|
570
|
-
|
|
|
571
|
-
| `
|
|
572
|
-
| `
|
|
573
|
-
| `
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
|
577
|
-
|
|
|
578
|
-
| `
|
|
579
|
-
| `
|
|
580
|
-
| `
|
|
581
|
-
| `
|
|
582
|
-
| `
|
|
583
|
-
| `
|
|
584
|
-
| `
|
|
585
|
-
| `
|
|
586
|
-
| `
|
|
587
|
-
| `
|
|
588
|
-
| `
|
|
589
|
-
| `
|
|
590
|
-
| `
|
|
591
|
-
| `
|
|
592
|
-
| `
|
|
593
|
-
| `
|
|
594
|
-
| `
|
|
595
|
-
| `
|
|
640
|
+
`action` e `source` são alternativas mutuamente exclusivas.
|
|
641
|
+
|
|
642
|
+
| Propriedade | Tipo | Padrão | Descrição |
|
|
643
|
+
| --- | --- | --- | --- |
|
|
644
|
+
| `source` | `ListDataSource<TItem>` | — | Fonte externa com `key` e `load`; substitui a action. |
|
|
645
|
+
| `title` | `string` | — | Título da coleção, ao lado das ações. |
|
|
646
|
+
| `item` | `ActionListItemSpec` | — | Campos `title` e `description?` da apresentação em itens. |
|
|
647
|
+
|
|
648
|
+
|
|
649
|
+
| Propriedade | Tipo | Padrão | Descrição |
|
|
650
|
+
| ----------------------- | ----------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
651
|
+
| `action` | `ListActionLike` | | A ListAction do Opus (kind list, output = item). A paginação envia `limit`/`page` e usa o `total` devolvido. |
|
|
652
|
+
| `input` | `TInput` | | O escopo base, como `{ workspaceId }`. A toolbar acrescenta busca, filtros e paginação sem sobrescrever essas chaves. |
|
|
653
|
+
| `layout` | `'flow' \| 'fill'` | `'fill'` como filha direta de `PageBody`, `SurfaceBody` 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`. |
|
|
654
|
+
| `cells` | `Record<string, (item) => ReactNode>` | | Células custom por cima das colunas do contrato (chave = column.key). |
|
|
655
|
+
| `filterOptions` | `Record<string, SelectOption[]>` | | Opções de runtime para filtros select/lookup. Em uma dimensão de agrupamento, a coleção precisa ser completa e ter de 1 a 12 itens. |
|
|
656
|
+
| `filterDefaults` | `Record<string, string>` | | Valores de repouso aplicados à consulta; o `X` só aparece quando o filtro diverge deles e retorna a eles. |
|
|
657
|
+
| `filterIcons` | `Record<string, ReactNode>` | | Ícones leading dos filtros, indexados pelo nome declarado no contrato. |
|
|
658
|
+
| `advancedFilters` | `{ columns?: 1 \| 2 \| 3; sectionIcons?: Record<string, ReactNode>; sectionVariant?: 'plain' \| 'framed' }` | `{ columns: 1, sectionVariant: 'plain' }` | Define as colunas, os ícones e o tratamento dos grupos; o Opus deriva a largura correspondente do diálogo. |
|
|
659
|
+
| `periodPosition` | `'before' \| 'after' \| { afterFilter: string }` | `'before'` | Posiciona o período antes, depois ou imediatamente após um filtro inline. |
|
|
660
|
+
| `periodControl` | `ReactNode` | — | Controle temporal do consumidor. Substitui o seletor padrão; em ActionList, também desativa a aplicação automática dos presets ao input. |
|
|
661
|
+
| `period` | `{ basisFilter: string }` | | Reúne o período e o filtro inline indicado em um único controle. |
|
|
662
|
+
| `views` | `Record<string, ActionListView<TItem>>` | | Visualizações alternativas `{ label, icon?, render }`; o seletor alterna entre a tabela e estas. |
|
|
663
|
+
| `beforeContent` | `ReactNode \| (input: TInput) => ReactNode` | | Conteúdo entre a toolbar e o corpo; a função recebe o mesmo input efetivo da consulta, para resumos que acompanham o recorte. |
|
|
664
|
+
| `columns` | `ActionListColumn<TItem>[]` | | Tabela explícita, que substitui as colunas declaradas no contrato. |
|
|
665
|
+
| `children` | `(items, refetch) => ReactNode` | | Modo composição: layout livre; a toolbar segue. Tem precedência sobre columns. |
|
|
666
|
+
| `batch` | `ActionListBatchAction[]` | | Ações em lote: `{ label, can?, run, confirm?: { title, message? }, destructive? }` — liga a multi-seleção. |
|
|
667
|
+
| `rowId` | `(item) => string` | `item.id` | Identidade da linha para seleção. |
|
|
668
|
+
| `pageSize` | `number` | `50` | Itens por página padrão (vira `limit`/`page` no input; handler devolve `total`). O usuário troca no popover de exibição. |
|
|
669
|
+
| `state / onStateChange` | `ActionListState / (next) => void` | interno | Estado da toolbar controlado — para quem embala sincronizar com a URL. |
|
|
670
|
+
| `empty` | `(items) => boolean` | `items.length === 0` | Sobrepõe o vazio derivado, por exemplo quando um formulário inline aberto conta como conteúdo. |
|
|
671
|
+
| `loading` | `boolean` | | Carga extra agregada à da consulta, como uma query irmã de que os `children` dependem. |
|
|
672
|
+
| `emptyMessage` | `string` | `'Nenhum resultado.'` | Frase do estado vazio (o `Empty` do `DataState`). |
|
|
673
|
+
| `errorMessage` | `string` | `'Não foi possível carregar.'` | Título do aviso de erro; a ação de tentar de novo refaz a consulta. |
|
|
674
|
+
| `retryLabel` | `string` | `'Tentar de novo'` | Nome acessível e tooltip da ação de recuperação. |
|
|
675
|
+
| `onRowClick` | `(item: TItem) => void` | | Clique na linha (ex.: navegar para o detalhe) — só na tabela. |
|
|
676
|
+
| `viewControls` | `ReactNode` | | Controles da visualização ativa, imediatamente após o seletor de visualização. |
|
|
677
|
+
| `toolbarActions` | `ReactNode \| ((context) => ReactNode)` | | Ações da coleção, incluindo criação, junto ao título quando declarado ou no fim da barra. Os nós são renderizados como recebidos: nome acessível e tooltip de uma ação somente com ícone ficam com o consumidor. |
|
|
678
|
+
| `rowActions` | `(item: TItem, context) => ReactNode` | | Ações por registro, na tabela ou à direita dos itens. Na tabela, a partir de duas, entram em um grupo com intervalo compacto; uma só fica solta, sem grupo. Cliques ali não disparam o `onRowClick`. |
|
|
679
|
+
|
|
680
|
+
Para carregar um detalhe a partir do mesmo recorte da coleção, use
|
|
681
|
+
`listStateToInput(state, action, { input, filterDefaults, pageSize })`. O helper materializa
|
|
682
|
+
busca, filtros, período, ordenação e paginação com a mesma regra usada pelo ActionList.
|
|
683
|
+
`input` transporta o escopo fixo; `filterDefaults` preenche filtros que não vieram no estado.
|
|
@@ -103,6 +103,11 @@ um atalho, um arrastar, um item de menu.
|
|
|
103
103
|
| `disabled` | `boolean` | `false` | Desabilita o botão independentemente da execução em andamento. |
|
|
104
104
|
| `onSuccess` | `(data: TData) => void` | | Pós-sucesso (cache já invalidado pelo action.invalidates). |
|
|
105
105
|
| `onLoadingChange` | `(loading: boolean) => void` | | Informa início e fim da execução a quem coordena bloqueio entre várias actions. |
|
|
106
|
+
| `aria-label` | `string` | | Nome acessível completo quando o texto visível é abreviado. |
|
|
106
107
|
| `icon` | `React.ReactNode` | | Torna o botão icon-only: rótulo no tooltip e no `aria-label`, clique que não vaza para o item. |
|
|
107
108
|
| `itemLabel` | `string` | | Nome do alvo na pergunta (sai entre aspas, em destaque, antes da mensagem do contrato). |
|
|
108
109
|
| `className` | `string` | | Classes do botão. O tamanho vem de `size` (escala única); com `icon`, o default é `icon-xs`. |
|
|
110
|
+
|
|
111
|
+
Quando `label` abrevia o texto visível, forneça `aria-label` com o nome completo da operação.
|
|
112
|
+
O nome acessível deve conter o texto visível; por exemplo, “Criar” e “Criar cliente”.
|
|
113
|
+
Presentation faz essa associação ao usar um rótulo contextual no comando.
|
|
@@ -32,8 +32,8 @@ há texto visível. O glifo dentro do controle acompanha o tamanho (0.875rem em
|
|
|
32
32
|
| Nome | Medida | Uso |
|
|
33
33
|
| --------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------- |
|
|
34
34
|
| `xs` | 1.5rem | Ação dentro de um campo (`InputGroupButton`). |
|
|
35
|
-
| `sm` | 2rem |
|
|
36
|
-
| `default` | 2.25rem |
|
|
35
|
+
| `sm` | 2rem | Criação de coleções e operações densas de toolbar ou seção. |
|
|
36
|
+
| `default` | 2.25rem | Headers, footers de Dialog e Drawer e controles comuns; é também a linha de `Input`. |
|
|
37
37
|
| `lg` | 2.5rem | Chamada principal com mais área de toque. |
|
|
38
38
|
| `icon-xs` | 1.5rem | Ação só de ícone dentro de um campo ou de uma linha densa; é o quadrado de `ActionTrigger` com `icon`. |
|
|
39
39
|
| `icon-sm` | 2rem | Ação só de ícone em composições compactas que precisam de mais presença; também é o quadrado das setas do pager de `ActionList`. |
|
|
@@ -41,15 +41,14 @@ há texto visível. O glifo dentro do controle acompanha o tamanho (0.875rem em
|
|
|
41
41
|
| `icon-lg` | 2.5rem | Ação só de ícone ao lado de um `lg`. |
|
|
42
42
|
|
|
43
43
|
Escolha o tamanho pela região, não pela importância visual: `variant` e `context` resolvem a
|
|
44
|
-
hierarquia da ação. Headers de Page, Dialog, Drawer e Surface usam `
|
|
44
|
+
hierarquia da ação. Headers de Page, Dialog, Drawer e Surface usam `default`/`icon`. A criação
|
|
45
45
|
no cabeçalho de uma coleção usa `sm` textual, sem ícone. Footers de
|
|
46
46
|
[`Dialog`](/ui/dialog) e [`Drawer`](/ui/drawer) conservam `default`. Operações densas de toolbar ou de seção usam `sm`;
|
|
47
47
|
ações dentro de linha ou célula usam `xs` ou `icon-xs`. Assim a mesma decisão mantém a mesma altura
|
|
48
48
|
mesmo quando uma superfície troca uma ação secundária por uma primária.
|
|
49
49
|
|
|
50
|
-
O retorno de `PageBack` usa `icon
|
|
51
|
-
(`shape="pill"`), `neutral` e `subtle`, no quadrado `icon-
|
|
52
|
-
`closeSize="xs"`.
|
|
50
|
+
O retorno de `PageBack` usa `icon`. O fechamento de Dialog e Drawer é um `CloseButton` circular
|
|
51
|
+
(`shape="pill"`), `neutral` e `subtle`, no quadrado `icon-xs` (`closeSize="xs"`) por padrão.
|
|
53
52
|
|
|
54
53
|
```tsx preview
|
|
55
54
|
<Button size="xs">Mínimo</Button>
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
## Registros distribuídos pelos dias
|
|
2
|
+
|
|
3
|
+
Use `CalendarMonthView` para consultar uma agenda ou expediente com conteúdo em cada dia. Para escolher uma data num formulário, use [DateInput](/ui/date-input); para selecionar um intervalo, use [Calendar](/ui/calendar).
|
|
4
|
+
|
|
5
|
+
O exemplo mostra um registro no mês inteiro. Clique ou use o teclado para abrir um dia:
|
|
6
|
+
|
|
7
|
+
```tsx preview
|
|
8
|
+
const [selected, setSelected] = useState("")
|
|
9
|
+
const entries = [{ date: "2026-11-02", title: "Expediente especial" }]
|
|
10
|
+
|
|
11
|
+
render(
|
|
12
|
+
<div className="space-y-3">
|
|
13
|
+
<CalendarMonthView
|
|
14
|
+
month="2026-11"
|
|
15
|
+
label="Agenda de novembro"
|
|
16
|
+
items={entries}
|
|
17
|
+
dateOf={(entry) => entry.date}
|
|
18
|
+
renderDay={(_date, items) => items.map((entry) => <span key={entry.title}>{entry.title}</span>)}
|
|
19
|
+
dayLabel={(date, items) => `${date}: ${items.map((entry) => entry.title).join(", ") || "Sem registros"}`}
|
|
20
|
+
onDayClick={(date) => setSelected(date)}
|
|
21
|
+
/>
|
|
22
|
+
{selected && <p>Data selecionada: {selected}</p>}
|
|
23
|
+
</div>,
|
|
24
|
+
)
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
A grade sempre mostra todos os dias do mês, mesmo sem itens. Ela agrupa os registros por `dateOf`, sem consultar dados ou calcular regras de expediente. Datas são strings civis; o componente não aplica o fuso do navegador.
|
|
28
|
+
|
|
29
|
+
## Dentro de ActionList
|
|
30
|
+
|
|
31
|
+
Forneça a grade no renderer de `views`. A [ActionList](/ui/action-list) mantém consulta, filtros, carregamento, erro e vazio; use `paginate: false` no contrato para que uma página de resultados não esconda dias com registros. `periodControl` permite navegar pelo mês no espaço de período da lista, com o valor temporal controlado pelo consumidor.
|
|
32
|
+
|
|
33
|
+
## Teclado e limites
|
|
34
|
+
|
|
35
|
+
Tab entra em um único dia. Setas esquerda e direita percorrem dias; cima e baixo avançam uma semana. Home e End levam ao início ou fim da semana visível. Enter e Espaço acionam o dia focado. A navegação fica dentro do mês: o consumidor fornece os controles para trocar de mês.
|
|
36
|
+
|
|
37
|
+
A semana começa no domingo, com cabeçalhos em pt-BR. Mês inválido é erro de programação; valide valores da URL antes de renderizar. O padrão não marca hoje automaticamente nem implementa seleção de datas ou PageUp/PageDown. A raiz da grade expõe `data-slot="calendar-month-view"`.
|
|
38
|
+
|
|
39
|
+
## Propriedades de CalendarMonthView
|
|
40
|
+
|
|
41
|
+
| Propriedade | Tipo | Padrão | Descrição |
|
|
42
|
+
|---|---|---|---|
|
|
43
|
+
| `month` | `string` | Obrigatória | Mês civil `AAAA-MM`, de 1000-01 a 9999-12. |
|
|
44
|
+
| `items` | `readonly TItem[]` | Obrigatória | Registros do mês, fornecidos pela coleção. |
|
|
45
|
+
| `dateOf` | `(item: TItem) => string` | Obrigatória | Data civil `AAAA-MM-DD` de cada registro. |
|
|
46
|
+
| `renderDay` | `(date: string, items: readonly TItem[]) => ReactNode` | Obrigatória | Conteúdo do dia; evite controles interativos dentro do botão. |
|
|
47
|
+
| `dayLabel` | `(date: string, items: readonly TItem[]) => string` | Obrigatória | Nome acessível do botão, incluindo data e contexto útil. |
|
|
48
|
+
| `onDayClick` | `(date: string, items: readonly TItem[]) => void` | Obrigatória | Abre ou executa a ação do dia. |
|
|
49
|
+
| `label` | `string` | Obrigatória | Nome acessível da grade. |
|
|
50
|
+
| `className` | `string` | — | Classes do contêiner externo, que permite rolagem horizontal em telas estreitas. |
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
## Dia único
|
|
2
2
|
|
|
3
3
|
Use `Calendar` quando a pessoa precisar escolher datas vendo o mês inteiro, como a data de uma
|
|
4
|
-
entrega ou a janela de um relatório. Para
|
|
4
|
+
entrega ou a janela de um relatório. Para preencher uma data com digitação e calendário em um
|
|
5
|
+
campo, use [`DateInput`](/ui/date-input). Composições próprias podem ancorá-lo em um
|
|
5
6
|
[`Popover`](/ui/popover).
|
|
6
7
|
|
|
7
8
|
Com `mode="single"`, a seleção é uma `Date`, controlada por `selected` e `onSelect`. `defaultMonth`
|
|
@@ -23,6 +24,8 @@ render(
|
|
|
23
24
|
O calendário usa pt-BR por padrão: os nomes de mês e de dia vêm do `locale` (`ptBR`, de
|
|
24
25
|
`date-fns/locale`) e os controles de navegação têm nomes acessíveis em português. Passe outro
|
|
25
26
|
`locale` para trocar o idioma; `labels` substitui nomes acessíveis individualmente.
|
|
27
|
+
O título usa mês com inicial maiúscula e barra antes do ano, como `Setembro/2026`.
|
|
28
|
+
Esse formato também aparece nos campos `DateInput`; `formatters.formatCaption` permite substituí-lo.
|
|
26
29
|
|
|
27
30
|
## Intervalo
|
|
28
31
|
|
|
@@ -181,3 +184,5 @@ no nome acessível do dia por `labels.labelDayButton`.
|
|
|
181
184
|
| `className` | `string` | | Classes somadas ao botão do dia. |
|
|
182
185
|
|
|
183
186
|
`CalendarDayButton` aceita também as props nativas de `<button>`, repassadas pelo `Calendar`.
|
|
187
|
+
|
|
188
|
+
Para consultar registros por dia, use [CalendarMonthView](/ui/calendar-month-view). A grade recebe um mês civil válido no formato `AAAA-MM`. Os cabeçalhos estão em pt-BR, e a semana começa no domingo. A consulta e os estados de carregamento e erro pertencem à ActionList.
|