@softize/opus 15.2.2 → 16.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 +51 -18
- package/bin/lib/check.mjs +98 -15
- package/bin/lib/copy.mjs +811 -314
- package/bin/lib/gen-manifest.mjs +24 -23
- package/bin/lib/gen-runner.mjs +188 -148
- package/docs/adr/0010-page-header-owns-page-chrome.md +3 -4
- package/docs/adr/0011-page-shell-coordinates-persistent-page-chrome.md +5 -3
- package/docs/adr/0012-modal-header-only-names-the-surface.md +45 -0
- package/docs/adr/0013-presentation-is-a-portable-action-oriented-artifact.md +92 -0
- package/docs/code-style.md +24 -19
- package/package.json +5 -1
- package/registry/skills/build-opus-ui/references/ui-patterns.md +43 -26
- package/src/core/presentation.ts +512 -0
- package/src/presentation/index.ts +1 -0
- package/src/ui/components/patterns/action-list-dialog.tsx +26 -9
- package/src/ui/components/patterns/confirm.tsx +34 -29
- package/src/ui/components/patterns/form-dialog.tsx +20 -8
- package/src/ui/components/patterns/list.tsx +26 -9
- package/src/ui/components/patterns/page.tsx +99 -139
- package/src/ui/components/patterns/presentation.tsx +316 -0
- package/src/ui/components/patterns/sidebar.tsx +3 -3
- package/src/ui/components/patterns/trigger.tsx +38 -17
- package/src/ui/components/primitives/button-group.tsx +53 -43
- package/src/ui/components/primitives/command.tsx +30 -72
- package/src/ui/components/primitives/dialog.tsx +23 -89
- package/src/ui/components/primitives/drawer.tsx +8 -34
- package/src/ui/docs/content/action-form-dialog.md +12 -10
- package/src/ui/docs/content/action-list-dialog.md +22 -17
- package/src/ui/docs/content/button.md +52 -35
- package/src/ui/docs/content/communication.md +26 -26
- package/src/ui/docs/content/dialog.md +173 -154
- package/src/ui/docs/content/drawer.md +12 -11
- package/src/ui/docs/content/page.md +72 -91
- package/src/ui/docs/content/presentation.md +158 -0
- package/src/ui/docs/registry.tsx +6 -0
- package/src/ui/meta.ts +8 -2
- package/src/ui/react.tsx +10 -3
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
# ADR 0010 — PageHeader também representa o chrome compacto da página
|
|
2
2
|
|
|
3
|
-
- **Status:**
|
|
3
|
+
- **Status:** substituída pela ADR 0011.
|
|
4
4
|
- **Data:** 2026-09-09.
|
|
5
5
|
- **Complementa:** ADR 0005.
|
|
6
6
|
|
|
7
|
-
> **Atualização (2026-09-
|
|
8
|
-
>
|
|
9
|
-
> cabeçalho, mas o título do conteúdo passa a `PageIntro` e as ações são coordenadas pelo Opus.
|
|
7
|
+
> **Atualização (2026-09-11).** A ADR 0011 torna `PageShell` o único componente responsável pela
|
|
8
|
+
> barra persistente. `PageHeader` volta a ter uma única apresentação dentro da página.
|
|
10
9
|
|
|
11
10
|
## Contexto
|
|
12
11
|
|
|
@@ -17,8 +17,9 @@ anatomias concorrentes e faz um estado integral remover também a navegação pe
|
|
|
17
17
|
## Decisão
|
|
18
18
|
|
|
19
19
|
`PageShell` representa a moldura persistente de uma página dentro de um shell de aplicação. Ele
|
|
20
|
-
renderiza a
|
|
21
|
-
|
|
20
|
+
renderiza a barra, recebe a navegação conhecida pelo shell e oferece o alvo canônico para ações
|
|
21
|
+
declaradas pela `Page` descendente. Essa barra existe somente por `PageShell`; `PageHeader` não
|
|
22
|
+
possui variante visual para reproduzi-la dentro da página.
|
|
22
23
|
|
|
23
24
|
Quando uma `Page` está dentro de `PageShell`, sua forma curta transforma título e descrição em
|
|
24
25
|
`PageIntro`, dentro do conteúdo. `PageActions` continua declarado pela página, mas aparece na barra.
|
|
@@ -41,7 +42,8 @@ Ele apenas coordena a barra e a área em que uma única `Page` é renderizada.
|
|
|
41
42
|
- título e descrição deixam de ser mascarados por seletores globais;
|
|
42
43
|
- ações de página têm um único destino oficial na barra;
|
|
43
44
|
- estados integrais preservam a barra e escondem somente a introdução do conteúdo;
|
|
44
|
-
- a composição
|
|
45
|
+
- a composição de `Page` com `PageHeader` permanece disponível fora de `PageShell`, sem uma segunda
|
|
46
|
+
forma de produzir a barra;
|
|
45
47
|
- `PageActionsTarget` continua disponível apenas para workspaces imersivos que não usam
|
|
46
48
|
`PageShell`.
|
|
47
49
|
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# ADR 0012 — O cabeçalho modal apenas nomeia a superfície
|
|
2
|
+
|
|
3
|
+
- **Status:** aceita.
|
|
4
|
+
- **Data:** 2026-09-11.
|
|
5
|
+
|
|
6
|
+
## Contexto
|
|
7
|
+
|
|
8
|
+
`DialogDescription` e `DrawerDescription` tornavam natural preencher o cabeçalho com uma segunda
|
|
9
|
+
linha mesmo quando ela apenas repetia o título ou explicava a ação óbvia. O resultado era uma
|
|
10
|
+
hierarquia mais pesada, mais espaço fixo antes da tarefa e textos que raramente ajudavam a pessoa a
|
|
11
|
+
decidir.
|
|
12
|
+
|
|
13
|
+
Há, porém, contexto que não pode desaparecer: consequências, restrições e instruções que mudam a
|
|
14
|
+
decisão. Esse conteúdo pertence à tarefa, não ao nome da superfície. Também pode precisar participar
|
|
15
|
+
da descrição acessível do modal.
|
|
16
|
+
|
|
17
|
+
## Decisão
|
|
18
|
+
|
|
19
|
+
- `DialogHeader` e `DrawerHeader` contêm o título e, quando necessário, mídia. Não existe API pública
|
|
20
|
+
`DialogDescription` ou `DrawerDescription`.
|
|
21
|
+
- Contexto relevante aparece no início de `DialogBody` ou `DrawerBody`, como texto, `Alert` ou uma
|
|
22
|
+
composição própria. Texto que apenas repete o título ou a ação é omitido.
|
|
23
|
+
- A API imperativa usa somente `body` para esse conteúdo. `ActionFormDialog` e `ActionListDialog`
|
|
24
|
+
oferecem `intro` no início do corpo; não oferecem `description`.
|
|
25
|
+
- `DialogContent` e `DrawerContent` não inferem uma descrição. Quando um trecho conciso do corpo deve
|
|
26
|
+
descrever a superfície para tecnologias assistivas, o consumidor relaciona seu `id` por
|
|
27
|
+
`aria-describedby`.
|
|
28
|
+
- `CommandDialog` mantém internamente uma instrução apenas para tecnologias assistivas, porque ela
|
|
29
|
+
explica o funcionamento do controle e não é copy visual do cabeçalho.
|
|
30
|
+
|
|
31
|
+
## Consequências
|
|
32
|
+
|
|
33
|
+
- Modais comuns começam mais perto da tarefa e não pedem texto de preenchimento.
|
|
34
|
+
- Informações importantes continuam visíveis, mas ocupam a região rolável e podem usar o componente
|
|
35
|
+
semântico adequado.
|
|
36
|
+
- A migração troca `description` por `body` na API imperativa, por `intro` nos wrappers e move conteúdo
|
|
37
|
+
declarativo relevante para o começo do corpo.
|
|
38
|
+
- O checker reprova as APIs removidas com orientação de migração.
|
|
39
|
+
|
|
40
|
+
## Verificação
|
|
41
|
+
|
|
42
|
+
- o barrel público não exporta `DialogDescription` nem `DrawerDescription`;
|
|
43
|
+
- os tipos das APIs imperativas não aceitam `description`;
|
|
44
|
+
- testes cobrem `body`, `intro`, a relação acessível e os diagnósticos de migração;
|
|
45
|
+
- a auditoria de docs, o inventário de copy, o typecheck e a suíte do pacote permanecem verdes.
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
# ADR 0013 — Presentation é um artefato portátil orientado a actions
|
|
2
|
+
|
|
3
|
+
- **Status:** aceita.
|
|
4
|
+
- **Data:** 2026-09-11.
|
|
5
|
+
|
|
6
|
+
## Contexto
|
|
7
|
+
|
|
8
|
+
Page, Dialog e Drawer compartilham uma anatomia estrutural, mas consumidores ainda repetem a
|
|
9
|
+
coordenação entre título, navegação, corpo, ações, estados e ciclo de abertura. Essa repetição
|
|
10
|
+
dificulta apresentar o mesmo recurso em superfícies diferentes e impede que ferramentas analisem
|
|
11
|
+
a interface antes de executar React.
|
|
12
|
+
|
|
13
|
+
O Opus já declara actions `simple`, `form`, `list` e `view`. Um artefato de interface não deve
|
|
14
|
+
reimplementar seus contratos, validação, autorização ou transporte; deve apenas compor essas
|
|
15
|
+
capacidade em uma apresentação verificável.
|
|
16
|
+
|
|
17
|
+
## Decisão
|
|
18
|
+
|
|
19
|
+
`Presentation` é o artefato declarativo que descreve um recurso independentemente da superfície em
|
|
20
|
+
que aparece. `Surface` escolhe `page`, `dialog` ou `drawer` no momento da renderização.
|
|
21
|
+
|
|
22
|
+
A anatomia portátil é `Header + Body + Footer?`. O header organiza horizontalmente
|
|
23
|
+
`Navigation? + Title + Actions?`; o body contém o recurso; o footer contém ações de conclusão.
|
|
24
|
+
Dialog e Drawer acrescentam o fechamento ao final das ações do header. Page pode ainda usar
|
|
25
|
+
navegação persistente fornecida pelo shell e uma introdução opcional dentro do body, sem mover nem
|
|
26
|
+
duplicar o título estrutural.
|
|
27
|
+
|
|
28
|
+
Uma action assume um de dois papéis:
|
|
29
|
+
|
|
30
|
+
- conteúdo no body: actions `form`, `list` e `view` usam seus patterns canônicos;
|
|
31
|
+
- comando no header ou footer: `simple` executa por `ActionTrigger`; os demais kinds abrem ou
|
|
32
|
+
navegam para outra Presentation que os apresenta como conteúdo.
|
|
33
|
+
|
|
34
|
+
O kind declarado pela action determina o pattern. A Presentation não repete `presentation: form`
|
|
35
|
+
ou `presentation: trigger`. Bindings declarativos fornecem input a partir de rota, registro, item,
|
|
36
|
+
seleção, sessão, resultado, valor fixo ou relógio. Autorização permanece no servidor.
|
|
37
|
+
|
|
38
|
+
Efeitos posteriores e coordenação de bloqueio são dados declarativos, não callbacks persistidos. O
|
|
39
|
+
renderer pode coordenar os escopos `action`, `group` e `surface`, mas cada pattern continua dono de
|
|
40
|
+
loading, erro, vazio, validação e repetição próprios.
|
|
41
|
+
|
|
42
|
+
Presentations possuem identificador e versão de schema, são registradas no `opus.config.ts` e
|
|
43
|
+
projetadas no manifest. A lens lê essa projeção; não infere a interface pelo JSX. Combinações
|
|
44
|
+
inválidas, referências ausentes e bindings incompatíveis produzem diagnósticos antes do runtime.
|
|
45
|
+
|
|
46
|
+
`PresentationDefinition` e `PresentationInvocation` têm ciclos de vida distintos. A definição é
|
|
47
|
+
estática, publicável no manifest e inspecionável pela Lens. A invocação é o estado serializável de
|
|
48
|
+
uma execução: identifica a Presentation, escolhe a surface, carrega somente input JSON e mantém a
|
|
49
|
+
pilha de frames necessária para voltar. Ela não é publicada no manifest.
|
|
50
|
+
|
|
51
|
+
`back` restaura o último frame da pilha. `close` encerra apenas dialog ou drawer e é inválido para
|
|
52
|
+
page. `navigate` abre outra invocação por push ou substitui a atual; sincronizar esse estado com URL
|
|
53
|
+
é responsabilidade do adaptador da aplicação quando refresh, deep link ou histórico forem
|
|
54
|
+
necessários. O inspetor de desenvolvimento reúne definição, invocação, bindings resolvidos e
|
|
55
|
+
diagnósticos, mascarando chaves sensíveis antes de expor o JSON.
|
|
56
|
+
|
|
57
|
+
## Consequências
|
|
58
|
+
|
|
59
|
+
- O mesmo recurso pode ser apresentado como page, dialog ou drawer sem três implementações.
|
|
60
|
+
- Novas interfaces convencionais concentram código na declaração e na composição específica.
|
|
61
|
+
- `ActionFormDialog`, `ActionListDialog` e wrappers equivalentes permanecem atalhos manuais, mas não
|
|
62
|
+
formam novos kinds do artefato.
|
|
63
|
+
- Interfaces específicas continuam possíveis por nós de extensão explícitos; uma extensão não é
|
|
64
|
+
considerada portátil até possuir renderer registrado para as superfícies declaradas.
|
|
65
|
+
- O schema evolui por versão e migração; consumidores não dependem de detalhes internos do renderer.
|
|
66
|
+
|
|
67
|
+
## Alternativas consideradas
|
|
68
|
+
|
|
69
|
+
### Persistir JSX ou callbacks
|
|
70
|
+
|
|
71
|
+
Preservaria liberdade irrestrita, mas não seria serializável, verificável nem seguro para autoria
|
|
72
|
+
por ferramentas. Foi descartada em favor de bindings e efeitos fechados.
|
|
73
|
+
|
|
74
|
+
### Criar schemas separados para Page, Dialog e Drawer
|
|
75
|
+
|
|
76
|
+
Representaria diretamente a aparência atual, mas triplicaria a composição e faria a superfície
|
|
77
|
+
definir o recurso. Foi descartada porque as diferenças pertencem ao renderer.
|
|
78
|
+
|
|
79
|
+
### Tratar toda action como ActionTrigger
|
|
80
|
+
|
|
81
|
+
Uniformizaria comandos visualmente, mas perderia os ciclos próprios de formulário, lista e view.
|
|
82
|
+
Foi descartada porque compatibilidade exige delegar cada kind ao pattern canônico.
|
|
83
|
+
|
|
84
|
+
## Verificação
|
|
85
|
+
|
|
86
|
+
- testes de schema cobrem versão, referências, kinds, placements e bindings;
|
|
87
|
+
- testes do renderer exercitam `simple`, `form`, `list` e `view` nas superfícies válidas;
|
|
88
|
+
- o manifest projeta Presentations sem callbacks nem dados server-only;
|
|
89
|
+
- a lens lista e expõe o JSON integral de cada Presentation;
|
|
90
|
+
- testes de invocação cobrem push, replace, back, close e rejeição de input não JSON;
|
|
91
|
+
- o inspetor mascara segredo, token, cookie, autorização, senha e chave de API;
|
|
92
|
+
- uma aplicação consumidora usa o pacote local por symlink durante a migração página por página.
|
package/docs/code-style.md
CHANGED
|
@@ -61,7 +61,12 @@ Base instalada é dona do catálogo, dos kinds aceitos e do fundamento de cada r
|
|
|
61
61
|
"allowedUppercase": ["CPF"],
|
|
62
62
|
"exclude": ["scripts/fixtures/**"],
|
|
63
63
|
"transforms": [
|
|
64
|
-
{
|
|
64
|
+
{
|
|
65
|
+
"source": "src/account.ts",
|
|
66
|
+
"line": 12,
|
|
67
|
+
"role": "button",
|
|
68
|
+
"transform": "uppercase"
|
|
69
|
+
}
|
|
65
70
|
],
|
|
66
71
|
"exemptions": [
|
|
67
72
|
{
|
|
@@ -78,24 +83,24 @@ Base instalada é dona do catálogo, dos kinds aceitos e do fundamento de cada r
|
|
|
78
83
|
}
|
|
79
84
|
```
|
|
80
85
|
|
|
81
|
-
| Propriedade Opus
|
|
82
|
-
|
|
83
|
-
| `label`, `confirm.*Label`, `ActionTrigger.label`
|
|
84
|
-
| `title`, `examples[].name`
|
|
85
|
-
| `summary`, `description`, `examples[].description`, `expand.*.description`
|
|
86
|
-
| `messages.success`, `messages.error`, `messages.confirmation`
|
|
87
|
-
| `confirm.message`
|
|
88
|
-
| `fields.*.label`, `filters.*.label`
|
|
89
|
-
| `placeholder`, `help`
|
|
90
|
-
| opções estáticas
|
|
91
|
-
| `columns[].label`, `periods[].label`
|
|
92
|
-
| `Select.emptyText`, `Select.searchPlaceholder`
|
|
93
|
-
| `Select.options[].hint/triggerLabel/group`
|
|
94
|
-
| `ActionTrigger.confirm.*`
|
|
95
|
-
| `t.dict` — `label`, `description`, `doc` das entradas e `doc` do dicionário
|
|
86
|
+
| Propriedade Opus | Papel no protocolo Base |
|
|
87
|
+
| ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -------------------------------------------------------- |
|
|
88
|
+
| `label`, `confirm.*Label`, `ActionTrigger.label` | `button` |
|
|
89
|
+
| `title`, `examples[].name` | `title` |
|
|
90
|
+
| `summary`, `description`, `examples[].description`, `expand.*.description` | `description` |
|
|
91
|
+
| `messages.success`, `messages.error`, `messages.confirmation` | `success`, `error`, `message` |
|
|
92
|
+
| `confirm.message` | `dialog-body` |
|
|
93
|
+
| `fields.*.label`, `filters.*.label` | `label` |
|
|
94
|
+
| `placeholder`, `help` | `placeholder`, `helper-text` |
|
|
95
|
+
| opções estáticas | `menu-item` |
|
|
96
|
+
| `columns[].label`, `periods[].label` | `heading`, `tab` |
|
|
97
|
+
| `Select.emptyText`, `Select.searchPlaceholder` | `empty-state`, `placeholder` |
|
|
98
|
+
| `Select.options[].hint/triggerLabel/group` | `label`, `label`, `heading` |
|
|
99
|
+
| `ActionTrigger.confirm.*` | papel correspondente do diálogo |
|
|
100
|
+
| `t.dict` — `label`, `description`, `doc` das entradas e `doc` do dicionário | `label`, `description` |
|
|
96
101
|
| `DataState`/`PageState`/`ActionList`/`ActionListDialog` — `emptyMessage`, `errorMessage`, `retryLabel`; `PageState`/`ActionListDialog` — `title`, `description`; `ActionView.emptyMessage` | `empty-state`, `error`, `button`, `title`, `description` |
|
|
97
|
-
| `dialog.alert/confirm/prompt/choose()` — `title`, `description`, `body`, `action`, `cancel`, `placeholder`, `actions[].label`
|
|
98
|
-
| `TooltipContent` (children), `LabelHelp.help`
|
|
102
|
+
| `dialog.alert/confirm/prompt/choose()` — `title`, `description`, `body`, `action`, `cancel`, `placeholder`, `actions[].label` | papel correspondente do diálogo |
|
|
103
|
+
| `TooltipContent` (children), `LabelHelp.help` | `label`, `helper-text` |
|
|
99
104
|
|
|
100
105
|
## Cobertura e significado do gate verde
|
|
101
106
|
|
|
@@ -109,7 +114,7 @@ O extrator cobre três superfícies, sem heurística de nome:
|
|
|
109
114
|
`@softize/opus/schema/zod`; metadata livre não é classificada por nome, declarações dinâmicas
|
|
110
115
|
reprovam em vez de serem executadas e o dicionário mantém um snapshot imutável das entradas;
|
|
111
116
|
3. texto estático em filhos e props de uma allowlist de componentes importados diretamente
|
|
112
|
-
de `@softize/opus/ui*` — por exemplo, `Button`, `DialogTitle`, `
|
|
117
|
+
de `@softize/opus/ui*` — por exemplo, `Button`, `DialogTitle`, `DialogBody`,
|
|
113
118
|
`FieldLabel`, `TabsTrigger`, `Page`, `Input` e `DataState`. Alias e namespace de import
|
|
114
119
|
continuam rastreáveis. `uppercase`, variantes como `sm:hover:uppercase`, modificadores
|
|
115
120
|
`!uppercase`/`uppercase!` e classes em descendentes são projetados na superfície que
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@softize/opus",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "16.0.0",
|
|
4
4
|
"description": "End-to-end action protocol for TypeScript. Single package with subpath exports (core + adapters).",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -153,6 +153,10 @@
|
|
|
153
153
|
"types": "./src/seed/index.ts",
|
|
154
154
|
"default": "./src/seed/index.ts"
|
|
155
155
|
},
|
|
156
|
+
"./presentation": {
|
|
157
|
+
"types": "./src/presentation/index.ts",
|
|
158
|
+
"default": "./src/presentation/index.ts"
|
|
159
|
+
},
|
|
156
160
|
"./server": {
|
|
157
161
|
"types": "./src/server/index.ts",
|
|
158
162
|
"default": "./src/server/index.ts"
|
|
@@ -6,26 +6,29 @@
|
|
|
6
6
|
- URL representa estado que precisa sobreviver a refresh, deep link ou histórico.
|
|
7
7
|
- `Page` fornece o `<main>` e o container centralizado com teto padrão de `80rem`. Sua forma
|
|
8
8
|
explícita é `Page > PageHeader (PageBack? | PageNavigation?, PageTitle, PageDescription?,
|
|
9
|
-
|
|
9
|
+
PageActions?) + PageBody`; `title`, `description` e `actions` no próprio `Page` são a abreviação
|
|
10
10
|
para o caso direto.
|
|
11
11
|
Não misturar as duas formas. Alterar `className` apenas quando a superfície tiver uma necessidade
|
|
12
12
|
real de largura; não reconstruir esse container em cada rota.
|
|
13
13
|
- Fora de `PageShell`, a composição explícita também pode trocar `PageHeader` por `PageIntro` quando
|
|
14
14
|
o conteúdo precisar somente de título, descrição e ações, sem retorno ou breadcrumb. `PageIntro`
|
|
15
15
|
dá mais presença ao título e não é uma abreviação visual de `PageHeader`.
|
|
16
|
-
- `PageHeader` é a
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
`PageActionsTarget` fica reservado a workspaces imersivos que já possuam chrome próprio.
|
|
16
|
+
- `PageHeader` é a região de cabeçalho dentro de uma `Page` isolada e organiza navegação, título e
|
|
17
|
+
ações na mesma linha. Em uma subpágina simples, `PageBack` recebe o destino pai explícito e aparece
|
|
18
|
+
antes do título como controle somente com ícone. Para mais de um ancestral relevante, use
|
|
19
|
+
`Breadcrumb` dentro de `PageNavigation`. Não combine retorno e breadcrumb nem crie um chrome
|
|
20
|
+
paralelo para uma `Page`. `PageActionsTarget` fica reservado a workspaces imersivos que já
|
|
21
|
+
possuam chrome próprio.
|
|
23
22
|
- Quando shell e rota conhecem partes diferentes da mesma página, use `PageShell` ao redor da rota.
|
|
24
|
-
O shell fornece `navigation`; a `Page` descendente continua
|
|
25
|
-
`actions`. O Opus mantém a barra de `3rem`, projeta as
|
|
26
|
-
como `PageIntro` no conteúdo.
|
|
27
|
-
`
|
|
28
|
-
|
|
23
|
+
O shell é o único responsável pela barra: fornece `navigation`; a `Page` descendente continua
|
|
24
|
+
declarando `title`, `description` e `actions`. O Opus mantém a barra de `3rem`, projeta as
|
|
25
|
+
ações nela e apresenta título e descrição como `PageIntro` no conteúdo. Ações com texto na barra
|
|
26
|
+
usam `Button size="sm"`; ações somente com ícone usam `icon-sm`. Na forma explícita dentro do
|
|
27
|
+
shell, use `Page > PageIntro (PageTitle, PageDescription?, PageActions?) + PageBody`. Não monte
|
|
28
|
+
`PaneHeader`, portal ou seletor global para reconstruir essa composição.
|
|
29
|
+
- Quando a rota precisa de navegação própria além da navegação persistente do shell, declare
|
|
30
|
+
`PageNavigation` no `PageIntro`. Esse slot permanece com o recurso ao alternar entre Page, Dialog
|
|
31
|
+
e Drawer; não replique nele a navegação global já fornecida pelo shell.
|
|
29
32
|
- `PageState` substitui todo o conteúdo principal quando a página carrega, falha ou está vazia. Na
|
|
30
33
|
forma curta ele pode ser escrito como filho direto de `Page`, que cria o `PageBody`; na forma
|
|
31
34
|
explícita, fica sozinho dentro de `PageBody`. Nos três estados ativos, o cabeçalho da Page isolada
|
|
@@ -37,7 +40,7 @@
|
|
|
37
40
|
recuperação como botão `outline` textual. Estados de seção ou coleção continuam em `DataState`,
|
|
38
41
|
`ActionView`, `ActionList` ou `Alert`; não elevar uma falha parcial a estado da página.
|
|
39
42
|
- `Content` delimita uma seção e segue a mesma anatomia: `Content > ContentHeader (ContentTitle,
|
|
40
|
-
|
|
43
|
+
ContentDescription, ContentMeta, ContentActions) + ContentBody`. `ContentHeader` nunca fica
|
|
41
44
|
solto. `title`, `description`, `count` e `actions` no `Content` são a abreviação para o caso
|
|
42
45
|
direto e não podem ser misturados ao header explícito. `level` preserva a hierarquia semântica
|
|
43
46
|
do heading.
|
|
@@ -64,6 +67,11 @@
|
|
|
64
67
|
controles customizados pelo contexto. `ActionFormCard` e `ActionFormDialog` acrescentam a
|
|
65
68
|
casca; não duplicar o form para obter card ou modal. Cancelamento em forms, confirmações e
|
|
66
69
|
modais usa `ghost`, deixando o destaque visual para a ação principal.
|
|
70
|
+
- Cabeçalhos de `Dialog` e `Drawer` apenas nomeiam a superfície com o título. Não preencher uma
|
|
71
|
+
segunda linha por hábito. Consequência, restrição ou instrução que realmente mude a tarefa entra
|
|
72
|
+
no início de `DialogBody`/`DrawerBody`, como texto ou `Alert`; wrappers usam `intro` e a API
|
|
73
|
+
imperativa usa `body`. Relacione texto conciso por `aria-describedby` somente quando ele também
|
|
74
|
+
precisar descrever a superfície para tecnologias assistivas.
|
|
67
75
|
- `ActionList` mantém fetch, toolbar, loading, erro, retry, vazio, seleção e paginação enquanto
|
|
68
76
|
permite três composições de resultado: tabela por `columns`, renderer completo por `children`
|
|
69
77
|
ou views nomeadas. Usar `ActionFilterBar` isoladamente só quando outra superfície assumir a
|
|
@@ -100,12 +108,12 @@
|
|
|
100
108
|
O dicionário declara o papel; a tela só escolhe onde o valor fica. Tabela de decisão aplicada
|
|
101
109
|
por `DictionaryValue` e pelas colunas de `ActionList`:
|
|
102
110
|
|
|
103
|
-
| Papel declarado
|
|
104
|
-
|
|
105
|
-
| `classification`
|
|
106
|
-
| `status`
|
|
107
|
-
| `stage`
|
|
108
|
-
| `plain` ou ausente | Fonte, formato, período
|
|
111
|
+
| Papel declarado | Exemplos | Forma | Contexto | Variante | Ícone | Tooltip |
|
|
112
|
+
| ------------------ | ------------------------------------ | ----- | ---------------------------------- | -------------------------------------- | --------------------------------------- | ------------------------------------- |
|
|
113
|
+
| `classification` | Tipo de cliente, categoria, natureza | Badge | `neutral` | `outline`; ignora `context` da entrada | se a entrada declara `icon` do catálogo | se `description` acrescenta ao rótulo |
|
|
114
|
+
| `status` | Aberto, resolvido, degradado | Badge | pela entrada; `neutral` por padrão | `subtle`; nunca `outline` | idem | idem |
|
|
115
|
+
| `stage` | Prospect, cliente; etapa do funil | Badge | igual a `status` | `subtle` | idem | idem |
|
|
116
|
+
| `plain` ou ausente | Fonte, formato, período | Texto | — | — | idem | idem |
|
|
109
117
|
|
|
110
118
|
Regras que não dependem da tabela:
|
|
111
119
|
|
|
@@ -123,13 +131,22 @@ Exemplo correto — tipo e estágio em colunas próprias, apresentação do dici
|
|
|
123
131
|
|
|
124
132
|
```ts
|
|
125
133
|
export const customerKindDict = t.dict(
|
|
126
|
-
{
|
|
127
|
-
|
|
128
|
-
|
|
134
|
+
{
|
|
135
|
+
pf: { label: "Pessoa física", icon: "user" },
|
|
136
|
+
pj: { label: "Empresa", icon: "building" },
|
|
137
|
+
},
|
|
138
|
+
{
|
|
139
|
+
doc: "Natureza da parte no cadastro global.",
|
|
140
|
+
presentation: "classification",
|
|
141
|
+
},
|
|
142
|
+
);
|
|
129
143
|
export const customerStageDict = t.dict(
|
|
130
|
-
{
|
|
131
|
-
|
|
132
|
-
|
|
144
|
+
{
|
|
145
|
+
prospect: { label: "Prospect" },
|
|
146
|
+
customer: { label: "Cliente", context: "success" },
|
|
147
|
+
},
|
|
148
|
+
{ doc: "Estágio comercial atual da parte.", presentation: "stage" },
|
|
149
|
+
);
|
|
133
150
|
// contrato:
|
|
134
151
|
// columns: [{ key: 'name' }, { key: 'kind', label: 'Tipo' }, { key: 'stage', label: 'Estágio' }]
|
|
135
152
|
// output: z.object({ kind: customerKindDict.zod(), stage: customerStageDict.zod() })
|