@softize/opus 23.0.0 → 24.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 +81 -0
- package/bin/cli.mjs +2 -0
- package/bin/lib/check.mjs +241 -42
- package/bin/lib/copy.mjs +16 -34
- package/docs/adr/0023-surfaces-share-one-anatomy-and-two-layouts.md +6 -0
- package/docs/adr/0039-filter-presentation-is-independent-from-filter-type.md +3 -3
- package/docs/adr/0040-tabs-use-a-single-navigation-presentation.md +5 -6
- package/docs/adr/0042-toggle-group-shares-the-grouped-control-grammar.md +79 -0
- package/docs/adr/0043-neutral-surfaces-and-interactions-use-opaque-role-tokens.md +73 -0
- package/docs/adr/0044-neutral-appearance-derives-from-bounded-axes-per-mode.md +133 -0
- package/docs/adr/0045-surface-replaces-content-and-card.md +230 -0
- package/docs/adr/0046-structural-body-owns-content-rhythm.md +103 -0
- package/docs/adr/0047-pane-is-only-a-split-layout-unit.md +71 -0
- package/docs/adr/0048-modal-intro-separates-content-from-chrome.md +34 -0
- package/package.json +5 -1
- package/registry/skills/build-opus-ui/SKILL.md +11 -11
- package/registry/skills/build-opus-ui/references/evaluations.md +10 -9
- package/registry/skills/build-opus-ui/references/ui-patterns.md +17 -16
- package/registry/templates/app/src/App.tsx +24 -12
- package/src/ui/appearance.ts +149 -0
- package/src/ui/components/patterns/action-form-card.tsx +46 -33
- package/src/ui/components/patterns/action-list-dialog.tsx +2 -4
- package/src/ui/components/patterns/confirm.tsx +3 -1
- package/src/ui/components/patterns/fill-region.ts +8 -7
- package/src/ui/components/patterns/form-dialog.tsx +1 -3
- package/src/ui/components/patterns/form.tsx +8 -7
- package/src/ui/components/patterns/list.tsx +15 -19
- package/src/ui/components/patterns/page.tsx +15 -11
- package/src/ui/components/patterns/pane.tsx +9 -240
- package/src/ui/components/patterns/presentation.tsx +14 -14
- package/src/ui/components/patterns/sidebar.tsx +7 -17
- package/src/ui/components/patterns/split.tsx +111 -59
- package/src/ui/components/patterns/{surface-header.tsx → structural-header.tsx} +50 -19
- package/src/ui/components/patterns/structural-media.tsx +26 -0
- package/src/ui/components/patterns/surface-anatomy.ts +71 -61
- package/src/ui/components/patterns/surface-assistant.tsx +2 -4
- package/src/ui/components/patterns/surface.tsx +620 -0
- package/src/ui/components/patterns/trigger.tsx +11 -9
- package/src/ui/components/primitives/ask.tsx +155 -83
- package/src/ui/components/primitives/button.tsx +11 -9
- package/src/ui/components/primitives/checkbox.tsx +8 -8
- package/src/ui/components/primitives/command.tsx +1 -1
- package/src/ui/components/primitives/composer.tsx +47 -45
- package/src/ui/components/primitives/detail.tsx +9 -2
- package/src/ui/components/primitives/dialog.tsx +60 -26
- package/src/ui/components/primitives/drawer.tsx +58 -12
- package/src/ui/components/primitives/icon-picker.tsx +90 -73
- package/src/ui/components/primitives/input-group.tsx +35 -28
- package/src/ui/components/primitives/input-otp.tsx +16 -16
- package/src/ui/components/primitives/input.tsx +20 -10
- package/src/ui/components/primitives/item.tsx +9 -12
- package/src/ui/components/primitives/menu.tsx +44 -65
- package/src/ui/components/primitives/metric-card.tsx +75 -59
- package/src/ui/components/primitives/radio-group.tsx +9 -9
- package/src/ui/components/primitives/select.tsx +344 -209
- package/src/ui/components/primitives/switch.tsx +10 -10
- package/src/ui/components/primitives/table.tsx +29 -24
- package/src/ui/components/primitives/tabs.tsx +4 -2
- package/src/ui/components/primitives/textarea.tsx +6 -6
- package/src/ui/components/primitives/toggle-group-context.ts +24 -0
- package/src/ui/components/primitives/toggle-group.tsx +116 -74
- package/src/ui/components/primitives/toggle.tsx +82 -16
- package/src/ui/docs/DocBrowser.tsx +77 -69
- package/src/ui/docs/content/action-form-card.md +9 -9
- package/src/ui/docs/content/action-list.md +76 -70
- package/src/ui/docs/content/action-view.md +33 -18
- package/src/ui/docs/content/button.md +1 -1
- package/src/ui/docs/content/communication.md +1 -1
- package/src/ui/docs/content/customization.md +64 -11
- package/src/ui/docs/content/detail.md +8 -6
- package/src/ui/docs/content/dialog.md +100 -58
- package/src/ui/docs/content/drawer.md +63 -19
- package/src/ui/docs/content/field.md +14 -15
- package/src/ui/docs/content/icon-tile.md +14 -13
- package/src/ui/docs/content/page.md +34 -26
- package/src/ui/docs/content/pane.md +41 -290
- package/src/ui/docs/content/presentation.md +3 -3
- package/src/ui/docs/content/separator.md +6 -6
- package/src/ui/docs/content/sidebar.md +68 -266
- package/src/ui/docs/content/skeleton.md +20 -18
- package/src/ui/docs/content/split.md +14 -14
- package/src/ui/docs/content/surface.md +513 -0
- package/src/ui/docs/content/tabs.md +20 -20
- package/src/ui/docs/content/toggle.md +117 -65
- package/src/ui/docs/content/tokens.md +124 -40
- package/src/ui/docs/registry.tsx +4 -6
- package/src/ui/index.ts +30 -27
- package/src/ui/meta.ts +15 -27
- package/src/ui/react.tsx +40 -43
- package/src/ui/theme.css +311 -64
- package/src/ui/components/patterns/content-header.tsx +0 -528
- package/src/ui/components/patterns/surface-media.tsx +0 -69
- package/src/ui/components/primitives/card.tsx +0 -191
- package/src/ui/docs/content/card.md +0 -292
- package/src/ui/docs/content/content.md +0 -275
|
@@ -6,17 +6,27 @@ erro. O consumidor compõe somente o conteúdo disponível, aqui com [`Detail`](
|
|
|
6
6
|
coleção, use [`ActionList`](/ui/action-list).
|
|
7
7
|
|
|
8
8
|
```tsx preview col
|
|
9
|
-
const [id, setId] = useState(
|
|
9
|
+
const [id, setId] = useState("empresa-x");
|
|
10
10
|
|
|
11
11
|
render(
|
|
12
12
|
<DocBrowserActionProvider>
|
|
13
13
|
<div className="w-full space-y-3">
|
|
14
14
|
<ButtonGroup mode="spaced">
|
|
15
|
-
<Button variant="outline" size="sm" onClick={() => setId(
|
|
16
|
-
|
|
17
|
-
|
|
15
|
+
<Button variant="outline" size="sm" onClick={() => setId("empresa-x")}>
|
|
16
|
+
Empresa X
|
|
17
|
+
</Button>
|
|
18
|
+
<Button variant="outline" size="sm" onClick={() => setId("empresa-y")}>
|
|
19
|
+
Empresa Y
|
|
20
|
+
</Button>
|
|
21
|
+
<Button
|
|
22
|
+
variant="outline"
|
|
23
|
+
size="sm"
|
|
24
|
+
onClick={() => setId("sessao-fantasma")}
|
|
25
|
+
>
|
|
26
|
+
Inexistente (erro)
|
|
27
|
+
</Button>
|
|
18
28
|
</ButtonGroup>
|
|
19
|
-
<
|
|
29
|
+
<Surface framed elevation="raised" className="p-4">
|
|
20
30
|
<ActionView action={docWorkspaceView} input={{ id }}>
|
|
21
31
|
{(ws) => (
|
|
22
32
|
<DetailGroup columns={3}>
|
|
@@ -24,15 +34,20 @@ render(
|
|
|
24
34
|
<DetailField label="Cliente" value={ws.client} />
|
|
25
35
|
<DetailField
|
|
26
36
|
label="Status"
|
|
27
|
-
value={
|
|
37
|
+
value={
|
|
38
|
+
<DictionaryValue
|
|
39
|
+
dict={docWorkspaceStatus}
|
|
40
|
+
value={ws.status}
|
|
41
|
+
/>
|
|
42
|
+
}
|
|
28
43
|
/>
|
|
29
44
|
</DetailGroup>
|
|
30
45
|
)}
|
|
31
46
|
</ActionView>
|
|
32
|
-
</
|
|
47
|
+
</Surface>
|
|
33
48
|
</div>
|
|
34
49
|
</DocBrowserActionProvider>,
|
|
35
|
-
)
|
|
50
|
+
);
|
|
36
51
|
```
|
|
37
52
|
|
|
38
53
|
O handler da view deve devolver um valor. Uma consulta que resolve `undefined` é tratada como erro
|
|
@@ -47,13 +62,13 @@ mais de uma região da tela ou quando o carregamento precisa ser orquestrado por
|
|
|
47
62
|
|
|
48
63
|
## Propriedades de ActionView
|
|
49
64
|
|
|
50
|
-
| Propriedade
|
|
51
|
-
|
|
52
|
-
| `action`
|
|
53
|
-
| `input`
|
|
54
|
-
| `children`
|
|
55
|
-
| `render`
|
|
56
|
-
| `loading`
|
|
57
|
-
| `empty`
|
|
58
|
-
| `emptyMessage` | `string`
|
|
59
|
-
| `error`
|
|
65
|
+
| Propriedade | Tipo | Padrão | Descrição |
|
|
66
|
+
| -------------- | ------------------------------------- | ---------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
67
|
+
| `action` | `ViewContract<TInput, TData>` | | A ViewAction do Opus (kind view, 1 recurso). |
|
|
68
|
+
| `input` | `TInput` | | Geralmente { id } — mudou, recarrega. |
|
|
69
|
+
| `children` | `(data: TData, refetch) => ReactNode` | | Obrigatório, salvo quando `render` é informado. Conteúdo apresentado quando os dados estão disponíveis. `refetch` permite recarregar por código. |
|
|
70
|
+
| `render` | `(data: TData, refetch) => ReactNode` | | Alias de compatibilidade de `children`; `children` tem precedência. Sem nenhum dos dois, o componente lança erro. |
|
|
71
|
+
| `loading` | `ReactNode \| boolean` | `3 skeletons` | Sobrescreve o carregamento: um nó próprio, `true` para o padrão ou `false` para não renderizar nada enquanto carrega. |
|
|
72
|
+
| `empty` | `ReactNode` | `emptyMessage` ou nada | Estado reservado a `data` indefinido. Como o react-query converte esse resultado em erro, ele não aparece na prática; devolva um valor ou o erro `not_found`. |
|
|
73
|
+
| `emptyMessage` | `string` | | Atalho do vazio, sujeito à mesma limitação de `empty`: a frase na mesma superfície de `DataState` (`Empty` com moldura sólida). |
|
|
74
|
+
| `error` | `(err, retry) => ReactNode` | `"Não foi possível carregar" + Tentar de novo` | Sobrescreve o estado de erro padrão. Sem ele, a frase do servidor só aparece quando é legível pela pessoa (`conflict`, `validation`, `not_found`, `authorization`, `authentication`); código técnico nunca vira título, e o botão de tentar de novo some quando o problema é de permissão ou sessão. |
|
|
@@ -43,7 +43,7 @@ há texto visível. O glifo dentro do controle acompanha o tamanho (0.875rem em
|
|
|
43
43
|
Escolha o tamanho pela região, não pela importância visual: `variant` e `context` resolvem a
|
|
44
44
|
hierarquia da ação. Headers de Page, a criação no cabeçalho de uma coleção e footers de
|
|
45
45
|
[`Dialog`](/ui/dialog) e [`Drawer`](/ui/drawer) usam `default`; a criação de uma coleção é um botão textual, sem
|
|
46
|
-
ícone, como mostra [`
|
|
46
|
+
ícone, como mostra [`Surface`](/ui/surface). 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
|
|
|
@@ -42,7 +42,7 @@ frase. Não copie as regras da Base para cá.
|
|
|
42
42
|
| Superfície Opus | Papel enviado à Base |
|
|
43
43
|
| ------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------- |
|
|
44
44
|
| `label`, botão de confirmação e filhos de `Button` | `button` |
|
|
45
|
-
| `title`, `
|
|
45
|
+
| `title`, `SurfaceTitle`, `DialogTitle` | `title` |
|
|
46
46
|
| `description`, `hint`, `help` | `description` ou `helper-text` |
|
|
47
47
|
| `messages.success` e `messages.error` | `success` e `error` |
|
|
48
48
|
| `confirm.message`, `dialog.*().body` e texto relevante no `DialogBody` | `dialog-body` |
|
|
@@ -17,12 +17,12 @@ variáveis.
|
|
|
17
17
|
|
|
18
18
|
```css
|
|
19
19
|
/* index.css do app — depois do import do tema. */
|
|
20
|
-
@import
|
|
20
|
+
@import "@softize/opus/ui/theme.css";
|
|
21
21
|
|
|
22
22
|
:root {
|
|
23
23
|
--primary: hsl(262 83% 58%); /* A cor da marca do projeto. */
|
|
24
24
|
--ring: hsl(262 83% 58%);
|
|
25
|
-
--radius: 0.5rem;
|
|
25
|
+
--radius: 0.5rem; /* Uma base menor deixa toda a escala mais contida. */
|
|
26
26
|
}
|
|
27
27
|
```
|
|
28
28
|
|
|
@@ -36,6 +36,55 @@ Quando o produto precisa de outra densidade, declare essa escolha no CSS do app.
|
|
|
36
36
|
Opus mede em `rem` acompanha a proporção. O valor continua sendo uma escolha do app, não uma regra
|
|
37
37
|
da biblioteca.
|
|
38
38
|
|
|
39
|
+
### Ajuste de aparência dos neutros
|
|
40
|
+
|
|
41
|
+
Quando a aplicação quer neutros levemente tingidos pela marca, camadas mais separadas ou um escuro
|
|
42
|
+
mais profundo — como padrão do produto ou como preferência de cada pessoa —, ela não precisa
|
|
43
|
+
redeclarar `--background`, `--card` e os demais tokens neutros. O tema calcula essa escala a partir
|
|
44
|
+
de quatro eixos por modo, e basta alterar os eixos. Cada um aceita um inteiro de 0 a 100; a tabela
|
|
45
|
+
com o efeito e o preset de cada eixo está em [Tokens](/ui/tokens).
|
|
46
|
+
|
|
47
|
+
Para definir o padrão do produto, declare os eixos no CSS do app. Os eixos do modo claro e os do
|
|
48
|
+
modo escuro ficam juntos em `:root`; o tema usa o conjunto do modo ativo.
|
|
49
|
+
|
|
50
|
+
```css
|
|
51
|
+
:root {
|
|
52
|
+
--neutral-hue: 262; /* O matiz da marca nos neutros. */
|
|
53
|
+
--appearance-light-color-intensity: 40;
|
|
54
|
+
--appearance-dark-color-intensity: 60;
|
|
55
|
+
--appearance-dark-surface-brightness: 30; /* Um escuro mais profundo que o preset. */
|
|
56
|
+
}
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
Para aplicar a preferência de uma pessoa, use o helper de `@softize/opus/ui/appearance`. Ele
|
|
60
|
+
arredonda e limita os valores, grava os eixos informados e remove os demais. Guardar a preferência
|
|
61
|
+
e desenhar a tela de ajuste são responsabilidades da aplicação.
|
|
62
|
+
|
|
63
|
+
```ts
|
|
64
|
+
import { applyAppearanceCustomProperties } from "@softize/opus/ui/appearance";
|
|
65
|
+
|
|
66
|
+
const style = document.documentElement.style;
|
|
67
|
+
|
|
68
|
+
// Aplica somente os eixos informados; os demais continuam no padrão.
|
|
69
|
+
applyAppearanceCustomProperties(style, "light", { layerContrast: 60 });
|
|
70
|
+
applyAppearanceCustomProperties(style, "dark", {
|
|
71
|
+
contrast: 40,
|
|
72
|
+
surfaceBrightness: 20,
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
// Voltar ao padrão é aplicar sem overrides: as propriedades são removidas.
|
|
76
|
+
applyAppearanceCustomProperties(style, "dark");
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
O Opus não oferece um componente de reset. Sem o override, vale o que o CSS do app declarou ou,
|
|
80
|
+
na falta disso, o preset do tema. Em renderização no servidor, `appearanceCustomProperties` devolve
|
|
81
|
+
o mesmo mapa sem tocar no DOM, para a aplicação escrever os eixos no HTML inicial.
|
|
82
|
+
|
|
83
|
+
Nenhum valor de 0 a 100 deixa a interface menos legível que o tema padrão: a separação entre os
|
|
84
|
+
papéis e o contraste do texto sobre as superfícies em repouso nunca ficam abaixo do preset. Um
|
|
85
|
+
token neutro redeclarado diretamente pelo app, como `--background`, deixa de acompanhar os eixos e
|
|
86
|
+
fica fora dessa proteção.
|
|
87
|
+
|
|
39
88
|
## 2 · className em tudo
|
|
40
89
|
|
|
41
90
|
Todo componente aceita `className` e o combina com as próprias classes por tailwind-merge: quando
|
|
@@ -44,28 +93,30 @@ local, como largura, margem e grid, e não para repintar o visual dos componente
|
|
|
44
93
|
|
|
45
94
|
```tsx
|
|
46
95
|
<Button className="w-full">Continuar</Button>
|
|
47
|
-
<
|
|
96
|
+
<Surface framed elevation="raised" className="max-w-sm" />
|
|
48
97
|
<DialogContent className="max-w-2xl" />
|
|
49
98
|
```
|
|
50
99
|
|
|
51
100
|
## 3 · Recomposição estrutural
|
|
52
101
|
|
|
53
|
-
Os componentes são divididos em partes nomeadas, como `
|
|
102
|
+
Os componentes são divididos em partes nomeadas, como `SurfaceHeader` e `SurfaceBody`, e a tela usa só as
|
|
54
103
|
que precisa. `asChild` faz o filho assumir o estilo e o comportamento do componente, e as funções
|
|
55
104
|
`*Variants` aplicam o visual de um componente a um elemento qualquer.
|
|
56
105
|
|
|
57
106
|
```tsx preview
|
|
58
107
|
<Button asChild variant="outline">
|
|
59
|
-
<a href="#" onClick={(e) => e.preventDefault()}>
|
|
108
|
+
<a href="#" onClick={(e) => e.preventDefault()}>
|
|
109
|
+
Link com aparência de botão
|
|
110
|
+
</a>
|
|
60
111
|
</Button>
|
|
61
112
|
```
|
|
62
113
|
|
|
63
114
|
```tsx
|
|
64
115
|
// Partes: só o que a tela pede.
|
|
65
|
-
<
|
|
66
|
-
<
|
|
67
|
-
<
|
|
68
|
-
</
|
|
116
|
+
<Surface framed elevation="raised">
|
|
117
|
+
<SurfaceHeader><SurfaceTitle>Workspace</SurfaceTitle></SurfaceHeader>
|
|
118
|
+
<SurfaceBody>…</SurfaceBody>
|
|
119
|
+
</Surface>
|
|
69
120
|
|
|
70
121
|
// asChild: o link assume o estilo e o comportamento do botão.
|
|
71
122
|
<Button asChild><a href="/docs">Abrir documentação</a></Button>
|
|
@@ -128,8 +179,10 @@ componentes.
|
|
|
128
179
|
## O que fica fora das alavancas
|
|
129
180
|
|
|
130
181
|
Alguns detalhes fazem parte da identidade visual do Opus e são iguais em todo projeto: a faixa do
|
|
131
|
-
rodapé do dialog, a
|
|
132
|
-
|
|
182
|
+
rodapé do dialog, a ordem entre canvas, controle, superfície elevada e estados neutros, o
|
|
183
|
+
escurecimento de botões sólidos ao serem pressionados e a seta do tooltip. Eles não são
|
|
184
|
+
configuráveis pela aplicação. O ajuste de aparência muda a distância entre os papéis neutros, mas
|
|
185
|
+
não a ordem entre eles.
|
|
133
186
|
|
|
134
187
|
Se uma necessidade real não cabe nas alavancas (tokens, `className`, partes e `asChild`, props e
|
|
135
188
|
contrato), não crie uma variação local. Proponha a evolução do componente no Opus, com a
|
|
@@ -44,12 +44,13 @@ React substitui a apresentação. `0` e `false` seguem como valores. A regra é
|
|
|
44
44
|
</DetailGroup>
|
|
45
45
|
```
|
|
46
46
|
|
|
47
|
-
##
|
|
47
|
+
## Elevação, moldura e divisórias internas
|
|
48
48
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
49
|
+
Por padrão, o grupo usa o mesmo fundo de uma superfície elevada. Use `elevation="none"` quando ele
|
|
50
|
+
precisar se integrar ao fundo do hospedeiro. `variant="framed"` adiciona somente a borda externa.
|
|
51
|
+
`dividers` desenha as divisórias internas; na orientação horizontal, também forma a grade tabular
|
|
52
|
+
com fundo sutil e padding próprio na coluna de rótulos. As opções são independentes e podem ser
|
|
53
|
+
combinadas. `orientation` define se a chave fica sobre o valor ou ao lado dele.
|
|
53
54
|
|
|
54
55
|
Na orientação horizontal, todos os valores começam depois da mesma coluna de rótulo, com largura
|
|
55
56
|
padrão de `7rem` em grupos simples e `8.5rem` quando `dividers` está ativo. Quando a superfície
|
|
@@ -73,7 +74,8 @@ exigir mais espaço para os rótulos, ajuste a variável no grupo, por exemplo c
|
|
|
73
74
|
|
|
74
75
|
| Propriedade | Tipo | Padrão | Descrição |
|
|
75
76
|
| ------------- | ---------------------------- | ------------ | --------------------------------------------------------------------------------------------------------- |
|
|
76
|
-
| `variant` | `'plain' \| 'framed'` | `'plain'` | `framed` aplica somente a moldura canônica ao conjunto
|
|
77
|
+
| `variant` | `'plain' \| 'framed'` | `'plain'` | `framed` aplica somente a moldura canônica ao conjunto. |
|
|
78
|
+
| `elevation` | `'none' \| 'raised'` | `'raised'` | `raised` usa o fundo de superfície elevada; `none` herda o fundo do hospedeiro. |
|
|
77
79
|
| `dividers` | `boolean` | `false` | Linhas finas entre os campos; na orientação horizontal, aplica fundo sutil e padding próprio aos rótulos. |
|
|
78
80
|
| `columns` | `1 \| 2 \| 3 \| 4 \| 'auto'` | `1` | Número fixo de colunas ou distribuição automática por largura mínima. |
|
|
79
81
|
| `orientation` | `'vertical' \| 'horizontal'` | `'vertical'` | Chave sobre o valor ou ao lado dele em cada campo. |
|
|
@@ -29,9 +29,11 @@ distinta da página.
|
|
|
29
29
|
<DialogHeader>
|
|
30
30
|
<DialogTitle>Criar workspace</DialogTitle>
|
|
31
31
|
</DialogHeader>
|
|
32
|
-
<DialogBody
|
|
33
|
-
<
|
|
34
|
-
|
|
32
|
+
<DialogBody>
|
|
33
|
+
<div className="space-y-2">
|
|
34
|
+
<Label htmlFor="workspace-name">Nome</Label>
|
|
35
|
+
<Input id="workspace-name" placeholder="Ex.: Empresa X" />
|
|
36
|
+
</div>
|
|
35
37
|
</DialogBody>
|
|
36
38
|
<DialogFooter>
|
|
37
39
|
<ButtonGroup mode="spaced">
|
|
@@ -46,6 +48,9 @@ distinta da página.
|
|
|
46
48
|
```
|
|
47
49
|
|
|
48
50
|
O corpo cresce até o limite da janela e passa a rolar; cabeçalho e rodapé permanecem visíveis.
|
|
51
|
+
Seus filhos diretos recebem o ritmo estrutural de `1.5rem`. Um grupo compacto, uma grade ou uma
|
|
52
|
+
linha declara a própria relação em um wrapper filho; `flush` fica reservado ao conteúdo que
|
|
53
|
+
controla todo o inset.
|
|
49
54
|
O backdrop escurece a página sem aplicar desfoque.
|
|
50
55
|
O fechamento do cabeçalho usa uma ação circular neutra e sutil. `closeSize` escolhe entre `xs` e
|
|
51
56
|
`sm`; o padrão é `sm`.
|
|
@@ -131,7 +136,9 @@ fluxo modal encadeado, em que a superfície permanece aberta e troca de etapa.
|
|
|
131
136
|
</DialogActions>
|
|
132
137
|
</DialogHeader>
|
|
133
138
|
<DialogBody>
|
|
134
|
-
<p className="text-sm text-muted-foreground">
|
|
139
|
+
<p className="text-sm text-muted-foreground">
|
|
140
|
+
Detalhe do evento selecionado.
|
|
141
|
+
</p>
|
|
135
142
|
</DialogBody>
|
|
136
143
|
</DialogContent>
|
|
137
144
|
</Dialog>
|
|
@@ -147,9 +154,9 @@ decidir aparece no começo do corpo, como texto ou `Alert`.
|
|
|
147
154
|
## Identificar a tarefa com um ícone
|
|
148
155
|
|
|
149
156
|
Use `DialogMedia` quando um ícone ajuda a reconhecer a tarefa antes da leitura do título. No modo
|
|
150
|
-
padrão, ele
|
|
151
|
-
|
|
152
|
-
|
|
157
|
+
padrão, ele apenas reserva e alinha o espaço antes do título. Componha [`IconTile`](/ui/icon-tile)
|
|
158
|
+
explicitamente quando o ícone precisar de moldura; passe o glifo diretamente quando não precisar.
|
|
159
|
+
O mesmo contrato vale no `mode="alert"`: a mídia não ganha tamanho, fundo ou borda automaticamente.
|
|
153
160
|
|
|
154
161
|
```tsx preview
|
|
155
162
|
render(
|
|
@@ -161,13 +168,17 @@ render(
|
|
|
161
168
|
<DialogContent>
|
|
162
169
|
<DialogHeader>
|
|
163
170
|
<DialogMedia>
|
|
164
|
-
<
|
|
171
|
+
<IconTile size="sm">
|
|
172
|
+
<Share2 />
|
|
173
|
+
</IconTile>
|
|
165
174
|
</DialogMedia>
|
|
166
175
|
<DialogTitle>Compartilhar contrato</DialogTitle>
|
|
167
176
|
</DialogHeader>
|
|
168
|
-
<DialogBody
|
|
169
|
-
<
|
|
170
|
-
|
|
177
|
+
<DialogBody>
|
|
178
|
+
<div className="space-y-2">
|
|
179
|
+
<Label htmlFor="share-email">E-mail</Label>
|
|
180
|
+
<Input id="share-email" placeholder="nome@empresa.com.br" />
|
|
181
|
+
</div>
|
|
171
182
|
</DialogBody>
|
|
172
183
|
<DialogFooter>
|
|
173
184
|
<ButtonGroup mode="spaced">
|
|
@@ -185,8 +196,10 @@ render(
|
|
|
185
196
|
</DialogTrigger>
|
|
186
197
|
<DialogContent>
|
|
187
198
|
<DialogHeader>
|
|
188
|
-
<DialogMedia
|
|
189
|
-
<
|
|
199
|
+
<DialogMedia>
|
|
200
|
+
<IconTile size="lg" context="danger">
|
|
201
|
+
<ShieldOff />
|
|
202
|
+
</IconTile>
|
|
190
203
|
</DialogMedia>
|
|
191
204
|
<DialogTitle>Revogar acesso de Marina?</DialogTitle>
|
|
192
205
|
</DialogHeader>
|
|
@@ -211,7 +224,8 @@ render(
|
|
|
211
224
|
);
|
|
212
225
|
```
|
|
213
226
|
|
|
214
|
-
Na API imperativa, a opção `media`
|
|
227
|
+
Na API imperativa, a opção `media` preserva o nó recebido. Passe um `IconTile` quando quiser
|
|
228
|
+
moldura.
|
|
215
229
|
|
|
216
230
|
## Pedir uma resposta pela API imperativa
|
|
217
231
|
|
|
@@ -245,7 +259,11 @@ function Demo() {
|
|
|
245
259
|
const accepted = await dialog.confirm({
|
|
246
260
|
title: "Excluir rascunho?",
|
|
247
261
|
body: "O rascunho e os comentários dele serão removidos.",
|
|
248
|
-
media:
|
|
262
|
+
media: (
|
|
263
|
+
<IconTile context="danger">
|
|
264
|
+
<Trash2 />
|
|
265
|
+
</IconTile>
|
|
266
|
+
),
|
|
249
267
|
action: "Excluir",
|
|
250
268
|
context: "danger",
|
|
251
269
|
});
|
|
@@ -443,42 +461,43 @@ botão. O texto informa o efeito real, como `Excluir`, `Revogar acesso` ou `Arqu
|
|
|
443
461
|
|
|
444
462
|
## Propriedades de DialogContent
|
|
445
463
|
|
|
446
|
-
| Propriedade | Tipo
|
|
447
|
-
| ----------------- |
|
|
448
|
-
| `showCloseButton` | `boolean`
|
|
449
|
-
| `closeDisabled` | `boolean`
|
|
450
|
-
| `closeSize` | `"xs" \| "sm"`
|
|
451
|
-
| `layout` | `'continuous' \| 'sectioned'` | `'sectioned'` | Anatomia da superfície inteira; os slots leem esse valor e não o recebem. Ignorado em `mode="alert"`.
|
|
452
|
-
| `className` | `string`
|
|
453
|
-
| `children` | `ReactNode`
|
|
464
|
+
| Propriedade | Tipo | Padrão | Descrição |
|
|
465
|
+
| ----------------- | ----------------------------- | ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
466
|
+
| `showCloseButton` | `boolean` | `true` | No modo padrão, inclui a ação de fechamento no header; o modo de alerta exige uma resposta identificável. |
|
|
467
|
+
| `closeDisabled` | `boolean` | `false` | Mantém o botão de fechar visível e desabilitado e impede que Esc e o clique externo fechem a superfície. Handlers como `onEscapeKeyDown` e `onPointerDownOutside` continuam sendo chamados antes do bloqueio. |
|
|
468
|
+
| `closeSize` | `"xs" \| "sm"` | `"sm"` | Define o tamanho da ação circular de fechar. |
|
|
469
|
+
| `layout` | `'continuous' \| 'sectioned'` | `'sectioned'` | Anatomia da superfície inteira; os slots leem esse valor e não o recebem. Ignorado em `mode="alert"`. |
|
|
470
|
+
| `className` | `string` | | Ajusta a superfície. A largura máxima é `32rem` no modo padrão e `20rem` no alerta; amplie o alerta com `max-w-lg` quando o rodapé tiver três ações. |
|
|
471
|
+
| `children` | `ReactNode` | | Cabeçalho, corpo, rodapé ou conteúdo próprio. |
|
|
454
472
|
|
|
455
473
|
## Propriedades de DialogHeader
|
|
456
474
|
|
|
457
|
-
| Propriedade | Tipo | Padrão | Descrição
|
|
458
|
-
| ----------- | ----------- | ------ |
|
|
459
|
-
| `className` | `string` | | Ajusta a faixa superior sobre o recuo do layout.
|
|
475
|
+
| Propriedade | Tipo | Padrão | Descrição |
|
|
476
|
+
| ----------- | ----------- | ------ | ----------------------------------------------------------------------------------------------------------------------------------------- |
|
|
477
|
+
| `className` | `string` | | Ajusta a faixa superior sobre o recuo do layout. |
|
|
460
478
|
| `children` | `ReactNode` | | Somente `DialogNavigation`, `DialogMedia`, `DialogTitle` e `DialogActions`, no máximo um de cada; o fechamento padrão entra depois deles. |
|
|
461
479
|
|
|
462
480
|
## Propriedades de DialogNavigation
|
|
463
481
|
|
|
464
|
-
| Propriedade | Tipo | Padrão | Descrição
|
|
465
|
-
| ----------- | ----------- | ------ |
|
|
466
|
-
| `className` | `string` | | Ajusta a região introdutória da linha.
|
|
467
|
-
| `children` | `ReactNode` | | Retorno de um fluxo modal encadeado, antes do título.
|
|
482
|
+
| Propriedade | Tipo | Padrão | Descrição |
|
|
483
|
+
| ----------- | ----------- | ------ | ----------------------------------------------------- |
|
|
484
|
+
| `className` | `string` | | Ajusta a região introdutória da linha. |
|
|
485
|
+
| `children` | `ReactNode` | | Retorno de um fluxo modal encadeado, antes do título. |
|
|
468
486
|
|
|
469
487
|
## Propriedades de DialogActions
|
|
470
488
|
|
|
471
|
-
| Propriedade | Tipo | Padrão | Descrição
|
|
472
|
-
| ----------- | ----------- | ------ |
|
|
473
|
-
| `className` | `string` | | Ajusta o agrupamento das ações.
|
|
474
|
-
| `children` | `ReactNode` | | Ações da tela no cabeçalho, antes do botão de fechar.
|
|
489
|
+
| Propriedade | Tipo | Padrão | Descrição |
|
|
490
|
+
| ----------- | ----------- | ------ | ----------------------------------------------------- |
|
|
491
|
+
| `className` | `string` | | Ajusta o agrupamento das ações. |
|
|
492
|
+
| `children` | `ReactNode` | | Ações da tela no cabeçalho, antes do botão de fechar. |
|
|
475
493
|
|
|
476
494
|
## Propriedades de DialogBody
|
|
477
495
|
|
|
478
|
-
| Propriedade | Tipo | Padrão
|
|
479
|
-
| ----------- | ----------- |
|
|
480
|
-
| `
|
|
481
|
-
| `
|
|
496
|
+
| Propriedade | Tipo | Padrão | Descrição |
|
|
497
|
+
| ----------- | ----------- | ------- | ---------------------------------------------------------------------- |
|
|
498
|
+
| `flush` | `boolean` | `false` | Remove o inset para conteúdo que controla o próprio recuo. |
|
|
499
|
+
| `className` | `string` | | Ajusta o corpo rolável do modo padrão ou o conteúdo próprio do alerta. |
|
|
500
|
+
| `children` | `ReactNode` | | Conteúdo principal da tarefa. |
|
|
482
501
|
|
|
483
502
|
## Propriedades de DialogFooter
|
|
484
503
|
|
|
@@ -489,25 +508,18 @@ botão. O texto informa o efeito real, como `Excluir`, `Revogar acesso` ou `Arqu
|
|
|
489
508
|
|
|
490
509
|
## Propriedades de DialogTitle
|
|
491
510
|
|
|
492
|
-
| Propriedade | Tipo
|
|
493
|
-
| ----------- |
|
|
494
|
-
| `level` | `1 \| 2 \| 3 \| 4 \| 5 \| 6` | `h2` da primitiva | Hierarquia do documento. O tamanho vem do `layout`, nunca do nível.
|
|
495
|
-
| `className` | `string`
|
|
496
|
-
| `children` | `ReactNode`
|
|
511
|
+
| Propriedade | Tipo | Padrão | Descrição |
|
|
512
|
+
| ----------- | ---------------------------- | ----------------- | ----------------------------------------------------------------------------------------------------------------------------------- |
|
|
513
|
+
| `level` | `1 \| 2 \| 3 \| 4 \| 5 \| 6` | `h2` da primitiva | Hierarquia do documento. O tamanho vem do `layout`, nunca do nível. |
|
|
514
|
+
| `className` | `string` | | Ajusta o título. No modo padrão, ele trunca quando não cabe na linha; no alerta, fica centralizado e pode ocupar mais de uma linha. |
|
|
515
|
+
| `children` | `ReactNode` | | Nome da tarefa ou do conteúdo modal. |
|
|
497
516
|
|
|
498
517
|
## Propriedades de DialogMedia
|
|
499
518
|
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
|
504
|
-
| ----------- | ----------------------------------------------------------- | --------- | -------------------------------------------------- |
|
|
505
|
-
| `size` | `'xs' \| 'sm' \| 'default' \| 'lg'` | `sm` | Escala da moldura; no alerta vale a moldura maior. |
|
|
506
|
-
| `context` | `UiContext` | `neutral` | Cor semântica da moldura. |
|
|
507
|
-
| `variant` | `'subtle' \| 'outline'` | `subtle` | Tratamento visual da moldura. |
|
|
508
|
-
| `className` | `string` | | Ajustes pontuais da moldura. |
|
|
509
|
-
| `children` | `ReactNode` | | Ícone que reforça o contexto da resposta. |
|
|
510
|
-
| `asChild` | `boolean` | `false` | Cede o elemento para uma marca com visual próprio — um orbe, um logotipo — que ocupa o slot sem ganhar a moldura por cima. |
|
|
519
|
+
| Propriedade | Tipo | Padrão | Descrição |
|
|
520
|
+
| ----------- | ----------- | ------ | ----------------------------------------------------------------------- |
|
|
521
|
+
| `className` | `string` | | Ajusta o alinhamento do slot. |
|
|
522
|
+
| `children` | `ReactNode` | | `IconTile`, marca, imagem ou glifo. O slot não acrescenta apresentação. |
|
|
511
523
|
|
|
512
524
|
## Propriedades de DialogClose
|
|
513
525
|
|
|
@@ -540,7 +552,7 @@ imperativa.
|
|
|
540
552
|
| -------- | ----------- | ------ | ------------------------------------------------ |
|
|
541
553
|
| `title` | `ReactNode` | | Nomeia o aviso que exige reconhecimento. |
|
|
542
554
|
| `body` | `ReactNode` | | Apresenta contexto relevante no início do corpo. |
|
|
543
|
-
| `media` | `ReactNode` | | Exibe
|
|
555
|
+
| `media` | `ReactNode` | | Exibe o nó recebido em `DialogMedia`. |
|
|
544
556
|
| `action` | `string` | `'OK'` | Define o rótulo de reconhecimento. |
|
|
545
557
|
|
|
546
558
|
## Opções de dialog.confirm
|
|
@@ -549,7 +561,7 @@ imperativa.
|
|
|
549
561
|
| --------- | ----------------------- | ------------- | ------------------------------------------------------------------- |
|
|
550
562
|
| `title` | `ReactNode` | | Nomeia a decisão. |
|
|
551
563
|
| `body` | `ReactNode` | | Apresenta a consequência ou outro contexto necessário para decidir. |
|
|
552
|
-
| `media` | `ReactNode` | | Exibe
|
|
564
|
+
| `media` | `ReactNode` | | Exibe o nó recebido em `DialogMedia`. |
|
|
553
565
|
| `action` | `string` | `'Confirmar'` | Define o rótulo do resultado afirmativo. |
|
|
554
566
|
| `cancel` | `string` | `'Cancelar'` | Define o rótulo da resposta negativa. |
|
|
555
567
|
| `context` | `'primary' \| 'danger'` | `'primary'` | Define o contexto da ação afirmativa. |
|
|
@@ -560,7 +572,7 @@ imperativa.
|
|
|
560
572
|
| -------------- | ----------------------- | ------------- | ------------------------------------------------------------------ |
|
|
561
573
|
| `title` | `ReactNode` | | Nomeia a informação solicitada. |
|
|
562
574
|
| `body` | `ReactNode` | | Explica como a informação será usada quando isso mudar a resposta. |
|
|
563
|
-
| `media` | `ReactNode` | | Exibe
|
|
575
|
+
| `media` | `ReactNode` | | Exibe o nó recebido em `DialogMedia`. |
|
|
564
576
|
| `action` | `string` | `'Confirmar'` | Define o rótulo do resultado afirmativo. |
|
|
565
577
|
| `cancel` | `string` | `'Cancelar'` | Define o rótulo da resposta negativa. |
|
|
566
578
|
| `context` | `'primary' \| 'danger'` | `'primary'` | Define o contexto da ação afirmativa. |
|
|
@@ -573,7 +585,7 @@ imperativa.
|
|
|
573
585
|
| --------- | ------------------------- | ------ | ------------------------------------------------ |
|
|
574
586
|
| `title` | `ReactNode` | | Nomeia a escolha. |
|
|
575
587
|
| `body` | `ReactNode` | | Apresenta o contexto necessário antes das ações. |
|
|
576
|
-
| `media` | `ReactNode` | | Exibe
|
|
588
|
+
| `media` | `ReactNode` | | Exibe o nó recebido em `DialogMedia`. |
|
|
577
589
|
| `actions` | `readonly DialogChoice[]` | | Declara os resultados disponíveis. |
|
|
578
590
|
|
|
579
591
|
## Propriedades de DialogChoice
|
|
@@ -586,3 +598,33 @@ imperativa.
|
|
|
586
598
|
| `context` | `ButtonContext` | Última ação: `primary`; demais: `neutral` | Define o significado semântico. |
|
|
587
599
|
| `variant` | `ButtonVariant` | Última ação: `solid`; demais: `outline` | Define o tratamento visual. |
|
|
588
600
|
| `disabled` | `boolean` | `false` | Impede a escolha desta ação. |
|
|
601
|
+
|
|
602
|
+
## Intro separada do chrome
|
|
603
|
+
|
|
604
|
+
Quando o header contém apenas navegação, ações globais e o fechamento, coloque o título do
|
|
605
|
+
conteúdo no primeiro bloco de `DialogBody`. `DialogIntro` exige um `DialogTitle` e aceita um
|
|
606
|
+
`DialogIntroActions`; o body continua responsável pelo espaço antes, entre e depois dos blocos.
|
|
607
|
+
|
|
608
|
+
```tsx
|
|
609
|
+
<Dialog>
|
|
610
|
+
<DialogContent>
|
|
611
|
+
<DialogHeader>
|
|
612
|
+
<DialogActions>
|
|
613
|
+
<Button variant="ghost">Ajuda</Button>
|
|
614
|
+
</DialogActions>
|
|
615
|
+
</DialogHeader>
|
|
616
|
+
<DialogBody>
|
|
617
|
+
<DialogIntro>
|
|
618
|
+
<DialogTitle>Editar evento</DialogTitle>
|
|
619
|
+
<DialogIntroActions>
|
|
620
|
+
<Button variant="outline">Revisar</Button>
|
|
621
|
+
</DialogIntroActions>
|
|
622
|
+
</DialogIntro>
|
|
623
|
+
<form>…</form>
|
|
624
|
+
</DialogBody>
|
|
625
|
+
<DialogFooter>…</DialogFooter>
|
|
626
|
+
</DialogContent>
|
|
627
|
+
</Dialog>
|
|
628
|
+
```
|
|
629
|
+
|
|
630
|
+
No formato compacto, mantenha `DialogTitle` e `DialogActions` no próprio `DialogHeader`.
|