@softize/opus 21.0.1 → 22.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 +71 -0
- package/bin/cli.mjs +9 -1
- package/bin/lib/check.mjs +37 -29
- package/docs/adr/0004-page-content-state-is-composed.md +3 -2
- package/docs/adr/0005-structural-surfaces-share-an-explicit-anatomy.md +3 -0
- package/docs/adr/0006-semantic-context-precedes-visual-variant.md +23 -14
- package/docs/adr/0011-page-shell-coordinates-persistent-page-chrome.md +5 -0
- package/docs/adr/0013-presentation-is-a-portable-action-oriented-artifact.md +7 -4
- package/docs/adr/0016-list-collection-header-belongs-to-content.md +13 -8
- package/docs/adr/0023-surfaces-share-one-anatomy-and-two-layouts.md +27 -26
- package/docs/adr/0025-content-frame-treatment-does-not-change-semantics.md +1 -0
- package/docs/adr/0029-page-header-is-the-single-page-introduction.md +71 -0
- package/docs/adr/0030-framed-content-can-use-sectioned-anatomy.md +89 -0
- package/docs/adr/0031-detail-dividers-own-the-tabular-label-treatment.md +61 -0
- package/docs/adr/0032-tab-baseline-respects-the-container-inset.md +59 -0
- package/docs/adr/0033-drawer-uses-an-inset-structural-frame.md +72 -0
- package/docs/adr/0034-tabs-can-own-a-frame-without-owning-a-surface.md +60 -0
- package/docs/adr/0035-button-group-separates-frame-relationship-and-distribution.md +63 -0
- package/docs/adr/0036-tabs-declares-trigger-distribution.md +58 -0
- package/docs/adr/0037-design-data-lives-outside-the-contract.md +117 -0
- package/docs/radius-scale.md +5 -2
- package/package.json +5 -1
- package/registry/skills/build-opus-ui/SKILL.md +9 -6
- package/registry/skills/build-opus-ui/references/evaluations.md +5 -2
- package/registry/skills/build-opus-ui/references/ui-patterns.md +14 -16
- package/registry/skills/create-opus-action/references/contract-and-binding.md +5 -3
- package/registry/skills/create-opus-action/scripts/scaffold.mjs +0 -4
- package/registry/skills/test-opus-action/SKILL.md +2 -2
- package/registry/skills/test-opus-action/references/harness.md +2 -2
- package/registry/templates/app/src/App.tsx +1 -1
- package/registry/templates/app/src/domains/tasks/actions/list.test.ts +2 -19
- package/registry/templates/app/src/domains/tasks/actions/list.ts +3 -5
- package/registry/templates/app/vite.config.ts +3 -2
- package/src/core/domain.ts +2 -2
- package/src/core/types.ts +6 -20
- package/src/design/index.ts +179 -0
- package/src/testing/fake.ts +2 -2
- package/src/testing/index.ts +7 -3
- package/src/ui/components/patterns/content-header.tsx +51 -13
- package/src/ui/components/patterns/list.tsx +51 -33
- package/src/ui/components/patterns/page.tsx +139 -251
- package/src/ui/components/patterns/presentation.tsx +2 -6
- package/src/ui/components/primitives/button-group.tsx +80 -8
- package/src/ui/components/primitives/button.tsx +85 -60
- package/src/ui/components/primitives/detail.tsx +63 -57
- package/src/ui/components/primitives/dialog.tsx +8 -11
- package/src/ui/components/primitives/drawer.tsx +16 -12
- package/src/ui/components/primitives/tabs.tsx +123 -54
- package/src/ui/docs/content/actions.md +49 -43
- package/src/ui/docs/content/button.md +55 -29
- package/src/ui/docs/content/content.md +61 -36
- package/src/ui/docs/content/detail.md +28 -19
- package/src/ui/docs/content/drawer.md +53 -47
- package/src/ui/docs/content/input.md +51 -35
- package/src/ui/docs/content/page.md +84 -95
- package/src/ui/docs/content/pane.md +83 -63
- package/src/ui/docs/content/presentation.md +20 -20
- package/src/ui/docs/content/tabs.md +107 -36
- package/src/ui/docs/content/testing.md +9 -25
- package/src/ui/meta.ts +5 -5
- package/src/ui/react.tsx +0 -1
- package/src/vite/design.ts +133 -23
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
# ADR 0029 — PageHeader é a única introdução estrutural da página
|
|
2
|
+
|
|
3
|
+
- **Status:** aceita.
|
|
4
|
+
- **Data:** 2026-09-28.
|
|
5
|
+
- **Substitui:** ADR 0011, quanto à barra persistente e à separação entre `PageHeader` e
|
|
6
|
+
`PageIntro`.
|
|
7
|
+
- **Relacionada:** ADR 0016, quanto ao cabeçalho próprio de coleções.
|
|
8
|
+
|
|
9
|
+
## Contexto
|
|
10
|
+
|
|
11
|
+
`PageShell` separou a navegação e as ações globais numa barra persistente, enquanto `PageIntro`
|
|
12
|
+
manteve o título no conteúdo. A separação estabilizou a posição das ações, mas criou duas regiões
|
|
13
|
+
para identificar a mesma página. Nas rotas simples, a barra passou a repetir o item já selecionado
|
|
14
|
+
na navegação da aplicação. Nas rotas profundas, o breadcrumb ficou visualmente distante do título
|
|
15
|
+
que ele contextualiza.
|
|
16
|
+
|
|
17
|
+
Breadcrumb é uma exceção para hierarquias que a navegação persistente não revela. Ele não precisa
|
|
18
|
+
reservar uma faixa em todas as páginas, e uma página de primeiro nível não ganha contexto ao repetir
|
|
19
|
+
seu próprio nome acima do título.
|
|
20
|
+
|
|
21
|
+
## Decisão
|
|
22
|
+
|
|
23
|
+
`PageHeader` é a única introdução estrutural de `Page`:
|
|
24
|
+
|
|
25
|
+
- o header participa da rolagem normal do conteúdo;
|
|
26
|
+
- `PageNavigation` ou `PageBack`, quando presente, ocupa uma linha acima da linha principal;
|
|
27
|
+
- `PageTitle` e `PageActions` compõem a linha principal;
|
|
28
|
+
- páginas sem hierarquia adicional não renderizam nem reservam espaço para navegação;
|
|
29
|
+
- `PageIntro` deixa de fazer parte da anatomia pública;
|
|
30
|
+
- `PageShell` pode coordenar navegação e ações conhecidas pela aplicação, mas não desenha uma barra;
|
|
31
|
+
esses valores são compostos pelo `PageHeader` da página ativa;
|
|
32
|
+
- `PageState` integral continua substituindo o header e fornece o único heading do estado;
|
|
33
|
+
- uma coleção pode continuar fornecendo o heading principal por `Content level={1}` sem criar um
|
|
34
|
+
`PageHeader` redundante.
|
|
35
|
+
|
|
36
|
+
## Consequências
|
|
37
|
+
|
|
38
|
+
- breadcrumb, título e ações voltam a pertencer à mesma região visual;
|
|
39
|
+
- páginas simples começam diretamente pelo título;
|
|
40
|
+
- a altura inicial do conteúdo pode variar quando existe breadcrumb, porque a variação agora
|
|
41
|
+
comunica hierarquia real;
|
|
42
|
+
- consumidores combinam navegação, título e ações em um único `PageHeader` ao migrar da composição
|
|
43
|
+
explícita;
|
|
44
|
+
- `PageShell` deixa de garantir navegação durante estados integrais, pois o estado substitui a
|
|
45
|
+
introdução completa da página;
|
|
46
|
+
- a remoção de `PageIntro` é uma mudança incompatível e requer migração coordenada dos consumidores.
|
|
47
|
+
|
|
48
|
+
## Alternativas descartadas
|
|
49
|
+
|
|
50
|
+
### Manter a barra persistente somente quando houver breadcrumb
|
|
51
|
+
|
|
52
|
+
Evitaria a repetição em páginas simples, mas preservaria duas anatomias para o mesmo cabeçalho e
|
|
53
|
+
manteria a navegação distante do título nas páginas profundas.
|
|
54
|
+
|
|
55
|
+
### Manter `PageIntro` como região opcional abaixo de `PageHeader`
|
|
56
|
+
|
|
57
|
+
Preservaria compatibilidade, mas continuaria exigindo que cada página decidisse qual das duas
|
|
58
|
+
regiões contém o título e as ações.
|
|
59
|
+
|
|
60
|
+
### Copiar a composição no consumidor
|
|
61
|
+
|
|
62
|
+
Validaria uma tela isolada mais rapidamente, porém criaria um segundo contrato visual fora do
|
|
63
|
+
catálogo e não provaria que páginas declarativas e `Presentation` mantêm a mesma anatomia.
|
|
64
|
+
|
|
65
|
+
## Verificação
|
|
66
|
+
|
|
67
|
+
- testes de `Page` cobrem breadcrumb acima da linha de título e ações;
|
|
68
|
+
- shorthand e composição explícita produzem a mesma anatomia;
|
|
69
|
+
- `PageShell` não renderiza barra e entrega navegação e ações ao `PageHeader` descendente;
|
|
70
|
+
- `PageState` integral mantém um único heading e remove o header;
|
|
71
|
+
- testes de `Presentation` cobrem a mesma composição dentro e fora de `PageShell`.
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
# ADR 0030 — Content com moldura pode usar anatomia seccionada
|
|
2
|
+
|
|
3
|
+
- **Status:** aceita.
|
|
4
|
+
- **Data:** 2026-09-28.
|
|
5
|
+
- **Substitui parcialmente:** ADR 0023, nas afirmações de que `Content` não expõe `layout` e é
|
|
6
|
+
sempre contínuo.
|
|
7
|
+
- **Complementa:** ADR 0025.
|
|
8
|
+
|
|
9
|
+
## Contexto
|
|
10
|
+
|
|
11
|
+
`Content` já representa uma região nomeada como `section` ou `fieldset`, com header, body e moldura
|
|
12
|
+
opcional. Quando o body é uma estrutura que possui o próprio recuo — como `DetailGroup` com
|
|
13
|
+
divisores, uma lista ou uma tabela — o acabamento contínuo acrescenta padding ao redor dessa
|
|
14
|
+
estrutura e impede que suas linhas alcancem a moldura.
|
|
15
|
+
|
|
16
|
+
O protótipo do detalhe de Veículo no Evento de Pós-vendas confirmou uma composição útil: header com
|
|
17
|
+
mídia, título, recuo de `0.75rem` e divisor; body sem recuo; conteúdo interno responsável por suas
|
|
18
|
+
células. Produzir esse desenho exigiu classes no consumidor para remover o padding da raiz, recortar
|
|
19
|
+
os cantos e reconstruir o header.
|
|
20
|
+
|
|
21
|
+
As forças em tensão são:
|
|
22
|
+
|
|
23
|
+
- reutilizar o vocabulário `continuous | sectioned` de Card, Dialog, Drawer e Pane;
|
|
24
|
+
- preservar `Content` como região semântica interna, sem transformá-lo em Card;
|
|
25
|
+
- manter `frameVariant="legend"` como acabamento da borda, sem misturá-lo à anatomia;
|
|
26
|
+
- impedir combinações em que o body encosta nas bordas sem existir uma moldura para recortá-lo.
|
|
27
|
+
|
|
28
|
+
## Decisão
|
|
29
|
+
|
|
30
|
+
`Content` passa a aceitar `layout="continuous" | "sectioned"`, com `continuous` como default.
|
|
31
|
+
|
|
32
|
+
O layout `sectioned` exige `framed` e forma um pacote indivisível:
|
|
33
|
+
|
|
34
|
+
- A raiz desenha a moldura, recorta os cantos e não aplica padding geral.
|
|
35
|
+
- `ContentHeader` aplica `p-3` e o divisor inferior.
|
|
36
|
+
- `ContentBody` não aplica padding; seu filho direto responde pelo recuo interno.
|
|
37
|
+
- Shorthand e composição explícita produzem a mesma anatomia.
|
|
38
|
+
- `ContentMedia`, título, descrição, contador e ações preservam seus contratos atuais.
|
|
39
|
+
|
|
40
|
+
`frameVariant` continua escolhendo somente o acabamento da moldura contínua. A combinação
|
|
41
|
+
`layout="sectioned"` com `frameVariant="legend"` é inválida: o primeiro coloca o header dentro da
|
|
42
|
+
moldura, enquanto o segundo o integra ao traço externo.
|
|
43
|
+
|
|
44
|
+
O layout não altera a semântica. `as="section"` continua emitindo section com heading e
|
|
45
|
+
`as="fieldset"` continua emitindo fieldset com legend nativa.
|
|
46
|
+
|
|
47
|
+
### Emenda de 2026-09-28 — a moldura usa o raio das superfícies estruturais
|
|
48
|
+
|
|
49
|
+
Quando `framed` está ativo, `Content` desenha uma moldura estrutural completa e usa `rounded-xl`,
|
|
50
|
+
o mesmo degrau de `Card`. A semântica das duas famílias continua diferente, mas essa diferença não
|
|
51
|
+
produz uma geometria externa menor. Em composições aninhadas, evitar a moldura dupla em vez de
|
|
52
|
+
reduzir globalmente o raio de `Content`.
|
|
53
|
+
|
|
54
|
+
## Consequências
|
|
55
|
+
|
|
56
|
+
- DetailGroup, listas e tabelas podem ocupar o body de ponta a ponta sem classes estruturais no
|
|
57
|
+
consumidor.
|
|
58
|
+
- Conteúdo livre que precisa de recuo continua usando o layout `continuous`, ou declara sua própria
|
|
59
|
+
região interna quando o body de ponta a ponta for deliberado.
|
|
60
|
+
- `Content` passa a compartilhar o vocabulário de anatomia das demais superfícies, mas continua sem
|
|
61
|
+
footer e sem assumir o papel de uma superfície autônoma.
|
|
62
|
+
- A API rejeita `sectioned` sem `framed` e rejeita a combinação com `legend`.
|
|
63
|
+
|
|
64
|
+
## Alternativas consideradas
|
|
65
|
+
|
|
66
|
+
### Adicionar `frameVariant="sectioned"`
|
|
67
|
+
|
|
68
|
+
Foi descartado porque misturaria anatomia de regiões com o acabamento da linha externa. Card,
|
|
69
|
+
Dialog, Drawer e Pane já usam `layout` para essa decisão.
|
|
70
|
+
|
|
71
|
+
### Criar propriedades de borda e padding
|
|
72
|
+
|
|
73
|
+
Propriedades como `headerDivider` e `bodyInset` permitiriam combinações arbitrárias e devolveriam a
|
|
74
|
+
anatomia ao consumidor. O resultado validado é um pacote, não dois controles independentes.
|
|
75
|
+
|
|
76
|
+
### Criar DetailCard
|
|
77
|
+
|
|
78
|
+
Foi descartado porque duplicaria a semântica e os slots de `Content` para um único tipo de filho.
|
|
79
|
+
A anatomia também é válida para listas e tabelas.
|
|
80
|
+
|
|
81
|
+
## Verificação
|
|
82
|
+
|
|
83
|
+
- Testes de UI cobrem shorthand, composição explícita, section e fieldset.
|
|
84
|
+
- Testes confirmam header com divisor e `p-3`, body sem padding e raiz com recorte.
|
|
85
|
+
- Testes confirmam `rounded-xl` nas molduras `default`, `legend` e `sectioned`.
|
|
86
|
+
- Testes reprovam `sectioned` sem moldura e a combinação com `frameVariant="legend"`.
|
|
87
|
+
- A documentação demonstra o caso com `DetailGroup` e diferencia anatomia de acabamento.
|
|
88
|
+
- O consumidor de Pós-vendas usa somente props públicas do Opus, sem classes que reconstruam a
|
|
89
|
+
anatomia.
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# ADR 0031 — Divisórias de DetailGroup definem o tratamento tabular dos rótulos
|
|
2
|
+
|
|
3
|
+
- **Status:** aceita.
|
|
4
|
+
- **Data:** 2026-09-28.
|
|
5
|
+
|
|
6
|
+
## Contexto
|
|
7
|
+
|
|
8
|
+
`DetailGroup` separa três decisões: orientação dos pares, divisórias internas e moldura externa.
|
|
9
|
+
Apesar disso, o fundo sutil dos rótulos horizontais era ativado por `variant="framed"`. Assim, a
|
|
10
|
+
mesma grade com divisórias mudava de aparência ao ser hospedada por um `Content` seccionado, onde a
|
|
11
|
+
moldura pertence ao `Content`, e um grupo independente, onde a moldura pertence ao próprio
|
|
12
|
+
`DetailGroup`.
|
|
13
|
+
|
|
14
|
+
O fundo do rótulo é um acabamento da grade tabular: ele ajuda a distinguir chave e valor quando os
|
|
15
|
+
campos formam células conectadas. Não comunica que o grupo possui uma borda externa.
|
|
16
|
+
|
|
17
|
+
## Decisão
|
|
18
|
+
|
|
19
|
+
Na orientação horizontal, `dividers` ativa a composição tabular completa de cada campo:
|
|
20
|
+
|
|
21
|
+
- rótulo e valor recebem padding próprio;
|
|
22
|
+
- a coluna de rótulos usa fundo sutil;
|
|
23
|
+
- a largura padrão dos rótulos passa a `8.5rem`;
|
|
24
|
+
- as divisórias continuam delimitando as células.
|
|
25
|
+
|
|
26
|
+
`variant="framed"` controla somente a moldura externa do grupo. Sem `dividers`, um grupo horizontal
|
|
27
|
+
emoldurado mantém rótulo e valor sobre o mesmo fundo. Na orientação vertical, `dividers` continua
|
|
28
|
+
adicionando somente as separações entre campos, sem pintar o rótulo.
|
|
29
|
+
|
|
30
|
+
## Consequências
|
|
31
|
+
|
|
32
|
+
- Grades horizontais com divisórias têm a mesma aparência dentro de `Content layout="sectioned"`
|
|
33
|
+
e como bloco principal independente.
|
|
34
|
+
- Moldura externa, orientação e acabamento tabular permanecem decisões combináveis.
|
|
35
|
+
- Não é necessária uma nova prop apenas para reproduzir um enfeite que já acompanha a grade.
|
|
36
|
+
- Consumidores que usavam `framed + horizontal` sem divisórias deixam de receber fundo no rótulo.
|
|
37
|
+
|
|
38
|
+
## Alternativas consideradas
|
|
39
|
+
|
|
40
|
+
### Manter o fundo associado a `framed`
|
|
41
|
+
|
|
42
|
+
Preservaria o comportamento atual, mas continuaria fazendo a moldura externa alterar o interior da
|
|
43
|
+
grade e manteria inconsistentes os grupos hospedados por outra superfície.
|
|
44
|
+
|
|
45
|
+
### Criar `labelVariant="muted"`
|
|
46
|
+
|
|
47
|
+
Tornaria o acabamento explícito, mas adicionaria uma decisão a todos os consumidores sem haver um
|
|
48
|
+
caso de produto que precise variar o fundo independentemente das divisórias.
|
|
49
|
+
|
|
50
|
+
### Aplicar o fundo a toda orientação horizontal
|
|
51
|
+
|
|
52
|
+
Uniformizaria os rótulos, mas daria aparência tabular também a grupos simples, sem células ou
|
|
53
|
+
divisórias que sustentem essa leitura.
|
|
54
|
+
|
|
55
|
+
## Verificação
|
|
56
|
+
|
|
57
|
+
- Testes de UI confirmam fundo e padding separados em `horizontal + dividers`, com e sem moldura.
|
|
58
|
+
- Testes de UI confirmam ausência de fundo em `horizontal + framed` sem divisórias.
|
|
59
|
+
- Testes de UI confirmam que divisórias verticais não pintam o rótulo.
|
|
60
|
+
- A documentação de `DetailGroup` descreve `framed`, `dividers` e `orientation` como eixos
|
|
61
|
+
independentes.
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
# ADR 0032 — A linha-base das abas respeita o recuo do contêiner
|
|
2
|
+
|
|
3
|
+
- **Status:** aceita.
|
|
4
|
+
- **Data:** 2026-09-28.
|
|
5
|
+
- **Relacionada:** ADR 0023, quanto ao alinhamento horizontal dentro de superfícies.
|
|
6
|
+
|
|
7
|
+
## Contexto
|
|
8
|
+
|
|
9
|
+
A variante horizontal `line` de `TabsList` estendia a linha-base para fora da própria lista usando
|
|
10
|
+
o recuo de `DrawerBody` e `DialogBody`. Os rótulos permaneciam alinhados ao conteúdo, mas a linha
|
|
11
|
+
alcançava as laterais da superfície e rompia o contorno visual formado pelo corpo.
|
|
12
|
+
|
|
13
|
+
A tela de detalhes do Evento tornou a divergência evidente: cards, detalhes e conteúdo respeitam o
|
|
14
|
+
mesmo recuo lateral, enquanto apenas a navegação por abas terminava nas bordas do drawer.
|
|
15
|
+
|
|
16
|
+
## Decisão
|
|
17
|
+
|
|
18
|
+
A linha-base horizontal ocupa somente a largura de `TabsList`. Ela respeita o recuo aplicado pelo
|
|
19
|
+
contêiner e acompanha o alinhamento do corpo em qualquer superfície.
|
|
20
|
+
|
|
21
|
+
`DrawerBody` e `DialogBody` deixam de publicar uma variável de gutter exclusiva para Tabs. O recuo
|
|
22
|
+
continua pertencendo à anatomia da superfície, e Tabs apenas ocupa a largura que recebe no fluxo.
|
|
23
|
+
|
|
24
|
+
### Emenda de 2026-09-28 — a aba combina uma área de botão e o indicador
|
|
25
|
+
|
|
26
|
+
Na variante horizontal `line`, o gatilho mantém duas camadas: uma área interna com os estados
|
|
27
|
+
interativos e a mesma altura de um Button do tamanho correspondente, e o indicador ancorado na
|
|
28
|
+
linha-base da lista. A área interna permanece transparente e recebe fundo apenas no hover; a aba
|
|
29
|
+
ativa se distingue pelo indicador primário. Um respiro de `0.375rem` separa as duas camadas no uso
|
|
30
|
+
comum; dentro de `Tabs framed`, ele aumenta para `0.5rem` e acompanha o padding superior da moldura.
|
|
31
|
+
|
|
32
|
+
Essa apresentação pertence ao Opus: consumidores escolhem `variant="line"` e não repetem classes
|
|
33
|
+
de fundo, raio, padding ou interação para obter o estado selecionado.
|
|
34
|
+
|
|
35
|
+
## Consequências
|
|
36
|
+
|
|
37
|
+
- A linha e os rótulos das abas compartilham os limites horizontais do corpo.
|
|
38
|
+
- A seleção permanece indicada pela linha inferior, sem manter um segundo fundo persistente.
|
|
39
|
+
- Drawer e Dialog não mantêm uma integração implícita com Tabs.
|
|
40
|
+
- Um consumidor que realmente precise de uma linha até as bordas deve compor essa apresentação de
|
|
41
|
+
forma explícita, pois ela não é mais o comportamento padrão da variante `line`.
|
|
42
|
+
|
|
43
|
+
## Alternativas descartadas
|
|
44
|
+
|
|
45
|
+
### Manter a linha até as bordas
|
|
46
|
+
|
|
47
|
+
Preservaria o comportamento anterior, mas manteria uma exceção visual exclusiva das abas e uma
|
|
48
|
+
dependência oculta entre as primitivas de corpo e Tabs.
|
|
49
|
+
|
|
50
|
+
### Adicionar uma propriedade de full bleed
|
|
51
|
+
|
|
52
|
+
Permitiria escolher os dois comportamentos, mas aumentaria a API para preservar uma apresentação
|
|
53
|
+
sem consumidor conhecido. A composição explícita é suficiente caso essa necessidade apareça.
|
|
54
|
+
|
|
55
|
+
## Verificação
|
|
56
|
+
|
|
57
|
+
O teste da variante `line` verifica que a linha usa `inset-inline: 0`, inclusive quando Tabs está
|
|
58
|
+
dentro de `DrawerBody`. O mesmo teste verifica a separação estrutural entre a superfície interna e
|
|
59
|
+
o indicador da aba ativa. A documentação viva demonstra a variante com os limites do contêiner.
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
# ADR 0033 — Drawer usa uma moldura estrutural recuada
|
|
2
|
+
|
|
3
|
+
- **Status:** aceita.
|
|
4
|
+
- **Data:** 2026-09-28.
|
|
5
|
+
- **Substitui:** a decisão da ADR 0005 que prendia a moldura externa do Drawer à borda da viewport.
|
|
6
|
+
|
|
7
|
+
## Contexto
|
|
8
|
+
|
|
9
|
+
O `Drawer` ocupava toda a altura ou largura da viewport e desenhava somente a borda voltada para o
|
|
10
|
+
conteúdo. No consumidor, o shell principal já delimita as superfícies de trabalho com recuo de
|
|
11
|
+
`0.5rem`, borda completa, fundo base e raio `xl`. Ao abrir um Drawer sobre esse shell, o painel
|
|
12
|
+
voltava à geometria antiga de uma lâmina presa à janela: perdia os cantos, encostava em três bordas
|
|
13
|
+
e não parecia pertencer ao mesmo sistema de molduras.
|
|
14
|
+
|
|
15
|
+
O painel continua precisando comunicar de qual lado entra, preservar sua animação e aproveitar a
|
|
16
|
+
altura disponível. Ao mesmo tempo, a moldura não pode ser reconstruída por cada consumidor, porque
|
|
17
|
+
posição, recorte e animação pertencem à primitive.
|
|
18
|
+
|
|
19
|
+
## Decisão
|
|
20
|
+
|
|
21
|
+
`DrawerContent` passa a ser uma superfície recuada da viewport em todos os lados:
|
|
22
|
+
|
|
23
|
+
- usa `0.25rem` de distância das bordas aplicáveis;
|
|
24
|
+
- usa borda completa, fundo base, `rounded-xl` e `overflow-hidden`;
|
|
25
|
+
- calcula a dimensão que antes ocupava `100%` descontando o recuo dos dois lados;
|
|
26
|
+
- mantém `side` responsável pela direção, dimensão principal e animação de entrada e saída;
|
|
27
|
+
- mantém largura e altura extensíveis por `className`, como antes.
|
|
28
|
+
|
|
29
|
+
O princípio durável é que uma superfície modal lateral possui moldura própria e não se confunde
|
|
30
|
+
com a viewport. O valor do recuo e o degrau de raio continuam materializações substituíveis da
|
|
31
|
+
escala visual vigente.
|
|
32
|
+
|
|
33
|
+
## Consequências
|
|
34
|
+
|
|
35
|
+
- Drawer e shell passam a compartilhar a mesma leitura de moldura estrutural.
|
|
36
|
+
- Header, body e footer full-bleed são recortados pelos cantos do painel.
|
|
37
|
+
- A área útil do Drawer perde `0.5rem` no eixo que antes preenchia a viewport.
|
|
38
|
+
- Consumidores deixam de precisar adicionar borda, raio ou margem para obter essa composição.
|
|
39
|
+
- A mudança visual alcança `top`, `right`, `bottom` e `left`, evitando quatro geometrias distintas
|
|
40
|
+
para a mesma primitive.
|
|
41
|
+
|
|
42
|
+
## Alternativas descartadas
|
|
43
|
+
|
|
44
|
+
### Manter o Drawer preso à viewport
|
|
45
|
+
|
|
46
|
+
Preservaria a geometria histórica, mas manteria a divergência mais visível justamente quando o
|
|
47
|
+
painel aparece sobre um shell emoldurado.
|
|
48
|
+
|
|
49
|
+
### Ajustar somente o Drawer do consumidor
|
|
50
|
+
|
|
51
|
+
Validaria a tela atual com menor alcance, mas espalharia posição e recorte por `className` e
|
|
52
|
+
deixaria outros Drawers fora do mesmo contrato visual.
|
|
53
|
+
|
|
54
|
+
### Arredondar apenas os cantos expostos
|
|
55
|
+
|
|
56
|
+
Manteria o painel preso à borda de entrada, mas produziria uma moldura incompleta e continuaria sem
|
|
57
|
+
o respiro que distingue a superfície da viewport.
|
|
58
|
+
|
|
59
|
+
### Alterar somente o lado direito
|
|
60
|
+
|
|
61
|
+
Resolveria o caso mais frequente, mas faria `side` trocar também o contrato visual da superfície,
|
|
62
|
+
sem uma razão de produto para essa diferença.
|
|
63
|
+
|
|
64
|
+
## Verificação
|
|
65
|
+
|
|
66
|
+
- Testes de `DrawerContent` verificam borda completa, raio, recorte e recuo para os quatro valores
|
|
67
|
+
de `side`.
|
|
68
|
+
- Os testes existentes continuam cobrindo anatomia interna, fechamento e animação.
|
|
69
|
+
- A documentação do Drawer descreve a moldura recuada e continua demonstrando a extensão de
|
|
70
|
+
largura por `className`.
|
|
71
|
+
- Um teste do consumidor confirma que o Drawer de Evento usa o default do Opus, sem reconstruir a
|
|
72
|
+
moldura localmente.
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# ADR 0034 — Tabs pode ter moldura sem criar uma superfície
|
|
2
|
+
|
|
3
|
+
- **Status:** aceita.
|
|
4
|
+
- **Data:** 2026-09-28.
|
|
5
|
+
- **Relacionadas:** ADR 0023, quanto à anatomia das superfícies; ADR 0032, quanto à linha-base das abas.
|
|
6
|
+
|
|
7
|
+
## Contexto
|
|
8
|
+
|
|
9
|
+
Uma composição em que a navegação por abas e seus painéis formam um único bloco precisa de borda,
|
|
10
|
+
raio e recorte compartilhados. Até aqui, consumidores obtinham essa forma envolvendo `Tabs` em um
|
|
11
|
+
`Card`.
|
|
12
|
+
|
|
13
|
+
O `Card`, porém, não é apenas uma moldura: ele aplica `bg-card text-card-foreground` e cria uma
|
|
14
|
+
superfície semântica própria. Em um `Drawer`, essa superfície pode se distinguir do
|
|
15
|
+
`bg-background`, especialmente no tema escuro, embora a intenção seja somente delimitar as abas
|
|
16
|
+
dentro da superfície já existente.
|
|
17
|
+
|
|
18
|
+
## Decisão
|
|
19
|
+
|
|
20
|
+
`Tabs` aceita a propriedade booleana `framed`, desativada por padrão.
|
|
21
|
+
|
|
22
|
+
Quando ativa, `framed` aplica ao root a moldura estrutural canônica para esse bloco: borda, raio
|
|
23
|
+
`rounded-xl` e recorte do conteúdo. Ela não aplica token de fundo nem de foreground. O conjunto
|
|
24
|
+
herda a superfície do contêiner em que foi composto.
|
|
25
|
+
|
|
26
|
+
Essa propriedade não altera a apresentação de `TabsList`, a seleção, o tamanho nem a orientação. O
|
|
27
|
+
consumidor continua escolhendo esses comportamentos nas APIs existentes, inclusive
|
|
28
|
+
`TabsList variant="line"`.
|
|
29
|
+
|
|
30
|
+
## Consequências
|
|
31
|
+
|
|
32
|
+
- Abas podem formar um bloco único sem serem promovidas a `Card`.
|
|
33
|
+
- Em Drawer, Dialog ou Pane, a moldura acompanha o fundo da superfície externa nos temas claro e
|
|
34
|
+
escuro.
|
|
35
|
+
- `Card` continua correto quando as abas realmente precisarem de uma superfície semântica própria.
|
|
36
|
+
- `framed` permanece independente de `TabsList variant`, que descreve apenas a apresentação da
|
|
37
|
+
lista.
|
|
38
|
+
|
|
39
|
+
## Alternativas descartadas
|
|
40
|
+
|
|
41
|
+
### Manter Card como wrapper obrigatório
|
|
42
|
+
|
|
43
|
+
Preservaria a API atual, mas continuaria acoplando uma necessidade estrutural ao token de superfície
|
|
44
|
+
do Card.
|
|
45
|
+
|
|
46
|
+
### Aplicar classes no consumidor
|
|
47
|
+
|
|
48
|
+
Resolveria uma tela, mas repetiria borda, raio e clipping sem registrar o contrato visual da
|
|
49
|
+
composição.
|
|
50
|
+
|
|
51
|
+
### Fazer toda Tabs ser emoldurada
|
|
52
|
+
|
|
53
|
+
Removeria a escolha, mas quebraria usos em que Tabs participa do fluxo de uma página ou toolbar sem
|
|
54
|
+
formar um bloco autônomo.
|
|
55
|
+
|
|
56
|
+
## Verificação
|
|
57
|
+
|
|
58
|
+
Testes da primitiva verificam que o padrão permanece sem moldura e que `framed` aplica borda, raio e
|
|
59
|
+
recorte sem qualquer classe de fundo. O teste da view de Evento verifica que a composição usa o
|
|
60
|
+
root emoldurado diretamente, sem um `Card` intermediário.
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# ADR 0035 — ButtonGroup separa moldura, relação e distribuição
|
|
2
|
+
|
|
3
|
+
- **Status:** aceita.
|
|
4
|
+
- **Data:** 2026-09-28.
|
|
5
|
+
- **Relacionadas:** ADR 0015, quanto à escala dos controles; ADR 0017, quanto à distribuição igual explícita.
|
|
6
|
+
|
|
7
|
+
## Contexto
|
|
8
|
+
|
|
9
|
+
Um conjunto de ações do Evento foi composto com `Card`, `ButtonGroup mode="spaced"`, separadores
|
|
10
|
+
manuais e `flex-1` repetido em cada botão. O resultado visual é um único grupo emoldurado, com
|
|
11
|
+
ações de mesma largura e divisores entre elas, mas o consumidor precisa reconstruir essas três
|
|
12
|
+
decisões em componentes e classes diferentes.
|
|
13
|
+
|
|
14
|
+
`ButtonGroup` já distingue a relação entre controles com `mode` e a ocupação da largura com
|
|
15
|
+
`distribution`. Tratar os divisores como uma propriedade booleana criaria combinações sem sentido,
|
|
16
|
+
como controles conectados e divididos ao mesmo tempo. Usar `Card` apenas como borda também cria uma
|
|
17
|
+
superfície semântica e um fundo que não pertencem ao grupo de ações.
|
|
18
|
+
|
|
19
|
+
## Decisão
|
|
20
|
+
|
|
21
|
+
`ButtonGroup` passa a aceitar:
|
|
22
|
+
|
|
23
|
+
- `framed`, booleano independente que aplica borda, raio estrutural e padding sem definir fundo;
|
|
24
|
+
- `mode="divided"`, além de `connected` e `spaced`, para preservar a forma individual dos
|
|
25
|
+
controles e inserir automaticamente um divisor com respiro entre filhos adjacentes;
|
|
26
|
+
- `distribution="equal"`, já existente, para dividir o espaço disponível somente entre os
|
|
27
|
+
controles, sem incluir os divisores no cálculo.
|
|
28
|
+
|
|
29
|
+
O modo `divided` deriva a orientação dos separadores da orientação do grupo. Em grupos horizontais,
|
|
30
|
+
os divisores são verticais; em grupos verticais, são horizontais. `ButtonGroupSeparator` continua
|
|
31
|
+
público para composições conectadas ou divisões seletivas.
|
|
32
|
+
|
|
33
|
+
## Consequências
|
|
34
|
+
|
|
35
|
+
- Consumidores expressam o conjunto em uma única raiz: `<ButtonGroup framed mode="divided"
|
|
36
|
+
distribution="equal">`.
|
|
37
|
+
- A moldura herda a superfície externa e não substitui `Card` quando uma superfície semântica for
|
|
38
|
+
realmente necessária.
|
|
39
|
+
- Os botões não repetem classes de largura, e separadores uniformes não são montados manualmente.
|
|
40
|
+
- `mode` continua sendo o único eixo que descreve a relação visual entre controles.
|
|
41
|
+
|
|
42
|
+
## Alternativas descartadas
|
|
43
|
+
|
|
44
|
+
### Manter Card e separadores explícitos
|
|
45
|
+
|
|
46
|
+
Preservaria a API, mas manteria no consumidor uma composição repetitiva que representa uma única
|
|
47
|
+
decisão visual.
|
|
48
|
+
|
|
49
|
+
### Adicionar `dividers` como booleano
|
|
50
|
+
|
|
51
|
+
Permitiria ativar os traços, mas faria dois mecanismos independentes disputarem a relação entre os
|
|
52
|
+
controles e aceitaria combinações contraditórias.
|
|
53
|
+
|
|
54
|
+
### Criar uma variante visual única
|
|
55
|
+
|
|
56
|
+
Uma variante como `variant="framed-divided-equal"` reduziria a chamada, mas acoplaria três eixos
|
|
57
|
+
que têm usos independentes e impediria novas combinações legítimas.
|
|
58
|
+
|
|
59
|
+
## Verificação
|
|
60
|
+
|
|
61
|
+
Testes da primitiva verificam moldura sem fundo, divisores automáticos nas duas orientações e
|
|
62
|
+
distribuição igual restrita aos controles. O teste da view de Evento verifica que o grupo usa a API
|
|
63
|
+
canônica sem `Card`, `ButtonGroupSeparator` ou classes de distribuição nos filhos.
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# ADR 0036 — Tabs declara a distribuição dos gatilhos
|
|
2
|
+
|
|
3
|
+
- **Status:** aceita.
|
|
4
|
+
- **Data:** 2026-09-28.
|
|
5
|
+
- **Relacionadas:** ADR 0032, quanto à composição da variante `line`; ADR 0034, quanto à moldura de Tabs; ADR 0035, quanto ao eixo de distribuição em grupos de controles.
|
|
6
|
+
|
|
7
|
+
## Contexto
|
|
8
|
+
|
|
9
|
+
Uma lista de abas pode abraçar a largura dos rótulos ou repartir a largura disponível igualmente
|
|
10
|
+
entre os gatilhos. A view de Evento usa quatro abas no cabeçalho de um bloco emoldurado; larguras
|
|
11
|
+
derivadas do texto deixam esse cabeçalho visualmente desequilibrado, embora todas as seções tenham o
|
|
12
|
+
mesmo nível.
|
|
13
|
+
|
|
14
|
+
Hoje, a variante horizontal `line` força cada gatilho a usar a largura do próprio conteúdo. Um
|
|
15
|
+
consumidor que precise de larguras iguais teria de sobrescrever o `flex` interno ou reconstruir a
|
|
16
|
+
lista com grid, duplicando uma decisão que já existe em `ButtonGroup` como
|
|
17
|
+
`distribution="content" | "equal"`.
|
|
18
|
+
|
|
19
|
+
## Decisão
|
|
20
|
+
|
|
21
|
+
`Tabs` aceita `distribution="content" | "equal"`, com `content` como padrão. A propriedade fica no
|
|
22
|
+
root porque descreve o conjunto de abas e, como `size` e `orientation`, flui por contexto até a
|
|
23
|
+
lista e os gatilhos.
|
|
24
|
+
|
|
25
|
+
Na orientação horizontal, `equal` faz a lista ocupar a largura disponível e atribui a cada gatilho
|
|
26
|
+
a mesma fração flexível, com largura mínima zero. A área interativa interna ocupa toda essa fração,
|
|
27
|
+
incluindo o fundo de hover. `content` preserva o comportamento atual. A distribuição não altera a
|
|
28
|
+
largura nem o layout dos painéis de conteúdo.
|
|
29
|
+
|
|
30
|
+
## Consequências
|
|
31
|
+
|
|
32
|
+
- Consumidores escolhem a mesma linguagem de distribuição usada por `ButtonGroup`.
|
|
33
|
+
- `TabsList variant="line"` continua responsável pela linha e pelos estados visuais; não recebe
|
|
34
|
+
classes de layout no consumidor.
|
|
35
|
+
- A view de Evento declara `distribution="equal"` no `Tabs` sem alterar cada `TabsTrigger`.
|
|
36
|
+
- Usos existentes preservam a distribuição pelo conteúdo.
|
|
37
|
+
|
|
38
|
+
## Alternativas descartadas
|
|
39
|
+
|
|
40
|
+
### Declarar a propriedade em TabsList
|
|
41
|
+
|
|
42
|
+
É a parte que organiza os gatilhos, mas faria a distribuição escapar do mesmo contrato de conjunto
|
|
43
|
+
em que `Tabs` já declara tamanho e orientação.
|
|
44
|
+
|
|
45
|
+
### Usar grid e número de colunas no consumidor
|
|
46
|
+
|
|
47
|
+
Exigiria conhecer a quantidade de abas e repetiria classes de layout em cada tela.
|
|
48
|
+
|
|
49
|
+
### Tornar larguras iguais o padrão
|
|
50
|
+
|
|
51
|
+
Atenderia a view de Evento, mas esticaria navegações curtas e barras que deliberadamente abraçam os
|
|
52
|
+
rótulos.
|
|
53
|
+
|
|
54
|
+
## Verificação
|
|
55
|
+
|
|
56
|
+
Testes da primitiva verificam o default `content`, a largura total da lista e a fração igual dos
|
|
57
|
+
gatilhos quando `equal` está ativo. O teste da view de Evento verifica a propriedade no root e a
|
|
58
|
+
distribuição dos quatro gatilhos sem classes locais equivalentes.
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
# ADR 0037 — Dados do modo design ficam fora do contrato
|
|
2
|
+
|
|
3
|
+
- **Status:** aceita; a primeira etapa saiu na 22.1.0, e a remoção fica para a 23.0.0.
|
|
4
|
+
- **Data:** 2026-09-28.
|
|
5
|
+
- **Relacionadas:** ADR 0002 (seeds estruturados).
|
|
6
|
+
|
|
7
|
+
## Contexto
|
|
8
|
+
|
|
9
|
+
O modo design serve para desenhar e revisar telas sem backend: `opusDesign()` monta o runtime
|
|
10
|
+
dentro do dev server, e cada action responde pelo `mockHandler` declarado no contrato. O preview de
|
|
11
|
+
sessão do Maestro depende desse modo e não tem outro propósito além de design.
|
|
12
|
+
|
|
13
|
+
Em setembro de 2026, o único consumidor, a Grand Brasil, tinha 233 `mockHandler` para 256
|
|
14
|
+
contratos, cerca de 3.200 linhas entre handlers, fixtures e estado simulado. A medição mostrou três
|
|
15
|
+
problemas:
|
|
16
|
+
|
|
17
|
+
- **O mock viaja com o contrato.** O contrato é a fatia compartilhada com a interface, então o
|
|
18
|
+
build de produção da aplicação leva os handlers simulados e suas fixtures. Um build de produção
|
|
19
|
+
da Grand Brasil continha textos das fixtures e os próprios handlers.
|
|
20
|
+
- **Metade dos mocks não acrescenta nada ao schema.** Cerca de 110 handlers devolvem um literal
|
|
21
|
+
fixo (`{ id: 'mock-x' }`) ou uma lista vazia, o que o `fake` já gera a partir do `output`.
|
|
22
|
+
- **A outra metade replica o domínio.** Cerca de 95 handlers simulam um CRUD em memória e
|
|
23
|
+
reimplementam regras do handler real, como o significado de cada filtro operacional de uma
|
|
24
|
+
listagem. Em setembro, 19 commits de funcionalidade tiveram de alterar mocks junto com o código
|
|
25
|
+
real, e nada garante que as duas versões da regra continuem iguais.
|
|
26
|
+
|
|
27
|
+
Forças em tensão:
|
|
28
|
+
|
|
29
|
+
- a aplicação real deve carregar o mínimo possível de algo que só existe para design;
|
|
30
|
+
- o preview precisa responder a qualquer action, inclusive às criadas durante a sessão;
|
|
31
|
+
- às vezes o design precisa de coerência entre respostas, como um item em cada situação ou algo
|
|
32
|
+
criado que aparece na lista em seguida;
|
|
33
|
+
- no preview, variar entre sessões é aceitável, porque dado de design não é evidência. Os seeds da
|
|
34
|
+
ADR 0002 são evidência e continuam determinísticos;
|
|
35
|
+
- o Opus é protocolo e SDK: onde os cenários ficam e se são versionados é escolha do projeto.
|
|
36
|
+
|
|
37
|
+
## Decisão
|
|
38
|
+
|
|
39
|
+
1. **O contrato deixa de declarar dados de design.** `mockHandler` sai de `ActionBase`, do
|
|
40
|
+
contrato, do `ActionDef` e do `runAction`. O runtime de produção não lê mais `OPUS_MODE` nem
|
|
41
|
+
tem ramo de design. Toda a lógica de design fica em `@softize/opus/vite`.
|
|
42
|
+
2. **Toda action responde por padrão no modo design.** O plugin registra cada contrato com um
|
|
43
|
+
executor de design que, na ausência de cenário, devolve dado gerado pelo `fake` a partir do
|
|
44
|
+
`output`:
|
|
45
|
+
- `list` devolve três páginas geradas por `fakeMany`, com `items`, `cursor` e `total`, do
|
|
46
|
+
tamanho pedido em `limit` (20 quando a entrada não pede, até 100), e respeita a paginação
|
|
47
|
+
declarada. Busca e filtros não filtram o dado gerado, porque sobre dado
|
|
48
|
+
sorteado o resultado não mostraria nada útil; quando o filtro importar para o design, o
|
|
49
|
+
caminho é um cenário;
|
|
50
|
+
- a semente é derivada do nome da action e da entrada canônica, então a mesma requisição recebe
|
|
51
|
+
a mesma resposta;
|
|
52
|
+
- quando a entrada e a saída têm `id`, a saída ecoa o `id` da entrada, desde que o schema da
|
|
53
|
+
saída aceite esse valor, para que abrir um item listado mostre o mesmo identificador;
|
|
54
|
+
- uma action ligada a um handler real (`bindAction`) mantém esse handler, como hoje.
|
|
55
|
+
3. **Cenários são registrados fora do contrato, pelo nome da action.** O plugin ganha a opção
|
|
56
|
+
`scenarios`, com um ou mais globs. Os módulos casados exportam cenários criados por
|
|
57
|
+
`defineDesignScenario(contrato, resposta)`, e a resposta pode ser um valor ou uma função tipada
|
|
58
|
+
pela entrada e pela saída do contrato. O cenário vence a resposta padrão. Um cenário para uma
|
|
59
|
+
action inexistente é erro visível no preview, não um silêncio.
|
|
60
|
+
4. **O Opus não decide onde os cenários ficam.** A opção não tem default dentro do código da
|
|
61
|
+
aplicação. O consumidor escolhe, por exemplo, uma pasta ignorada pelo git que o agente da sessão
|
|
62
|
+
preenche sob demanda. Cenários começam descartáveis: só vale discutir versionar um cenário no
|
|
63
|
+
repositório do consumidor quando o mesmo for recriado em sessões diferentes.
|
|
64
|
+
5. **Stubs de rotas externas continuam como estão.** A opção `stubs` segue atendendo superfícies
|
|
65
|
+
fora do protocolo de actions, como autenticação e motores externos.
|
|
66
|
+
|
|
67
|
+
## Consequências
|
|
68
|
+
|
|
69
|
+
- A aplicação deixa de carregar mocks. O contrato volta a descrever só a capacidade, e o build de
|
|
70
|
+
produção não inclui dados de design.
|
|
71
|
+
- Uma action nova aparece no preview sem nenhuma linha de mock.
|
|
72
|
+
- O dado padrão tem o formato certo, mas não a regra de negócio: valores de enum são sorteados, e
|
|
73
|
+
campos de uma listagem e de um detalhe só coincidem no `id`. Quando isso atrapalhar o design, o
|
|
74
|
+
caminho é um cenário.
|
|
75
|
+
- Sem cenário, não há estado entre chamadas: criar um item não o faz aparecer na lista.
|
|
76
|
+
- É uma versão major. Quem declara `mockHandler` precisa remover a declaração ou transformá-la em
|
|
77
|
+
cenário, e testes que usam `OPUS_MODE=design` com `runAction` precisam de outra forma de
|
|
78
|
+
exercitar o contrato.
|
|
79
|
+
- O template de `opus create`, a documentação "Prototipar com dados simulados", as skills
|
|
80
|
+
`create-opus-action` e `test-opus-action` e o gate de ordem de campos (`check.mjs`) mudam junto.
|
|
81
|
+
- No Maestro, que fica fora deste pacote, o preview continua igual. O agente da sessão passa a
|
|
82
|
+
escrever cenários quando precisar, orientado por uma skill própria.
|
|
83
|
+
|
|
84
|
+
## Alternativas descartadas
|
|
85
|
+
|
|
86
|
+
- **Manter o estado atual.** Preserva cenários prontos entre sessões, mas mantém o mock no bundle,
|
|
87
|
+
a regra de negócio duplicada e o custo de cada funcionalidade nova.
|
|
88
|
+
- **Remover `mockHandler` apenas no build de produção.** Resolve o bundle e nada mais. O contrato
|
|
89
|
+
continua misturando capacidade e simulação, e a duplicação de regra permanece.
|
|
90
|
+
- **Preview com backend real e dados dos seeds.** Mostra o comportamento verdadeiro e elimina os
|
|
91
|
+
mocks, mas exige banco, API e isolamento por sessão num preview que só serve a design, além de
|
|
92
|
+
rever as decisões do Maestro de manter o preview isolado e sem Postgres.
|
|
93
|
+
- **CRUD em memória genérico a partir de metadado novo no contrato.** Exigiria declarar entidade e
|
|
94
|
+
operação em cada action e, mesmo assim, não cobriria regras de negócio, que continuariam
|
|
95
|
+
escritas à mão.
|
|
96
|
+
- **Somente a resposta padrão, sem cenários.** É o mínimo absoluto, mas deixaria o design sem saída
|
|
97
|
+
quando a coerência importa. O custo do mecanismo de cenários é pequeno perto disso.
|
|
98
|
+
|
|
99
|
+
## Transição
|
|
100
|
+
|
|
101
|
+
A saída acontece em duas versões. A 22.1.0 adiciona a resposta padrão e os cenários, com
|
|
102
|
+
`mockHandler` ainda aceito e precedendo a resposta gerada, e o `check` passa a contar o campo como
|
|
103
|
+
obsoleto. O consumidor remove seus mocks domínio a domínio. A 23.0.0 remove o campo e o ramo de
|
|
104
|
+
design do runtime.
|
|
105
|
+
|
|
106
|
+
## Verificação
|
|
107
|
+
|
|
108
|
+
- testes do plugin: resposta padrão por `kind` (`view`, `list`, `form`, `simple`), páginas do
|
|
109
|
+
tamanho pedido em `limit` com a paginação declarada, mesma resposta para a mesma entrada, eco do
|
|
110
|
+
`id`, precedência do cenário e erro para cenário sem action ou duplicado;
|
|
111
|
+
- teste de tipos: `defineDesignScenario` infere entrada e saída do contrato e rejeita resposta
|
|
112
|
+
incompatível;
|
|
113
|
+
- busca estática: nenhum `OPUS_MODE` nem `mockHandler` em `src/core` e `src/testing` depois da
|
|
114
|
+
major;
|
|
115
|
+
- no consumidor: nenhum `mockHandler` nos contratos, e o build de produção sem textos das fixtures
|
|
116
|
+
antigas;
|
|
117
|
+
- typecheck, suíte do pacote, `opus check` e os gates de materialização verdes.
|