@softize/opus 12.11.0 → 13.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 +76 -0
- package/PROMOTED.md +46 -0
- package/README.md +28 -19
- package/bin/cli.mjs +87 -216
- package/bin/lib/check.mjs +2 -7
- package/bin/lib/cli-shared.mjs +131 -0
- package/bin/lib/copy.mjs +1 -5
- package/bin/lib/db.mjs +16 -74
- package/bin/lib/gen-openapi.mjs +3 -3
- package/bin/lib/gen-runner.mjs +1 -1
- package/bin/lib/gen.mjs +14 -69
- package/bin/lib/mcp.mjs +3 -1
- package/bin/lib/seed.mjs +5 -62
- package/docs/adr/0005-structural-surfaces-share-an-explicit-anatomy.md +93 -10
- package/docs/adr/0007-toast-actions-form-an-ordered-collection.md +63 -0
- package/docs/adr/0008-hierarchical-navigation-is-composed-at-the-consumer-boundary.md +71 -0
- package/docs/ownership-vs-shadcn-lock.md +2 -3
- package/docs/protocol.md +7 -7
- package/docs/radius-scale.md +1 -1
- package/docs/releasing.md +8 -2
- package/package.json +7 -3
- package/registry/skills/maintain-opus-docs/SKILL.md +83 -0
- package/registry/skills/maintain-opus-docs/agents/openai.yaml +4 -0
- package/registry/skills/maintain-opus-docs/references/editorial-standard.md +85 -0
- package/registry/skills/maintain-opus-docs/references/evaluations.md +34 -0
- package/registry/skills/maintain-opus-docs/scripts/audit-docs.mjs +81 -0
- package/registry/templates/app/package.json +1 -1
- package/registry/templates/app/src/main.tsx +4 -4
- package/src/audit/drivers/console.ts +1 -0
- package/src/auth/drivers/better-auth.ts +1 -0
- package/src/auth/drivers/jwt.ts +1 -0
- package/src/cache/drivers/memory.ts +1 -0
- package/src/client/drivers/fetch.ts +2 -1
- package/src/core/actions.ts +6 -1
- package/src/core/audit.ts +9 -3
- package/src/core/contracts.ts +7 -0
- package/src/core/domain.ts +1 -1
- package/src/core/errors.ts +18 -15
- package/src/core/index.ts +4 -2
- package/src/core/package-version.ts +26 -0
- package/src/core/reactions.ts +1 -1
- package/src/core/runtime.ts +33 -23
- package/src/core/schedules.ts +1 -1
- package/src/core/types.ts +2 -2
- package/src/dsl/eval.ts +2 -2
- package/src/dsl/kysely.ts +2 -2
- package/src/dsl/loads.ts +1 -1
- package/src/dsl/parser.ts +5 -5
- package/src/events/drivers/mitt.ts +1 -0
- package/src/mcp/index.ts +2 -1
- package/src/observability/drivers/opentelemetry.ts +1 -0
- package/src/queue/drivers/bullmq.ts +3 -3
- package/src/scheduler/drivers/node-cron.ts +3 -2
- package/src/scheduler/every.ts +7 -7
- package/src/schema/openapi.ts +3 -3
- package/src/seed/index.ts +29 -0
- package/src/server/drivers/fastify.ts +5 -2
- package/src/server/drivers/node.ts +9 -6
- package/src/server/index.ts +3 -1
- package/src/storage/drivers/fs.ts +1 -0
- package/src/testing/index.ts +3 -3
- package/src/ui/components/patterns/confirm.tsx +142 -42
- package/src/ui/components/patterns/content-header.tsx +7 -1
- package/src/ui/components/patterns/data-state.tsx +1 -1
- package/src/ui/components/patterns/dock.tsx +20 -3
- package/src/ui/components/patterns/form.tsx +12 -8
- package/src/ui/components/patterns/list.tsx +36 -41
- package/src/ui/components/patterns/page-state.tsx +2 -2
- package/src/ui/components/patterns/page.tsx +19 -1
- package/src/ui/components/patterns/shell-nav.tsx +10 -3
- package/src/ui/components/patterns/sidebar.tsx +43 -32
- package/src/ui/components/patterns/trigger.tsx +39 -38
- package/src/ui/components/patterns/view.tsx +26 -17
- package/src/ui/components/primitives/alert.tsx +14 -8
- package/src/ui/components/primitives/ask.tsx +3 -3
- package/src/ui/components/primitives/badge.tsx +11 -6
- package/src/ui/components/primitives/breadcrumb.tsx +2 -2
- package/src/ui/components/primitives/button.tsx +16 -3
- package/src/ui/components/primitives/calendar.tsx +28 -2
- package/src/ui/components/primitives/carousel.tsx +3 -3
- package/src/ui/components/primitives/chat.tsx +1 -1
- package/src/ui/components/primitives/checkbox.tsx +1 -1
- package/src/ui/components/primitives/command.tsx +2 -2
- package/src/ui/components/primitives/control.ts +12 -0
- package/src/ui/components/primitives/copyable.tsx +1 -1
- package/src/ui/components/primitives/dialog.tsx +202 -40
- package/src/ui/components/primitives/dot.tsx +5 -0
- package/src/ui/components/primitives/drawer.tsx +18 -8
- package/src/ui/components/primitives/empty.tsx +3 -3
- package/src/ui/components/primitives/field.tsx +3 -3
- package/src/ui/components/primitives/icon-picker.tsx +3 -1
- package/src/ui/components/primitives/input-group.tsx +1 -1
- package/src/ui/components/primitives/input-otp.tsx +1 -1
- package/src/ui/components/primitives/input.tsx +2 -2
- package/src/ui/components/primitives/item.tsx +3 -3
- package/src/ui/components/primitives/progress.tsx +32 -3
- package/src/ui/components/primitives/radio-group.tsx +1 -1
- package/src/ui/components/primitives/resizable.tsx +3 -1
- package/src/ui/components/primitives/select.tsx +5 -5
- package/src/ui/components/primitives/slider.tsx +5 -1
- package/src/ui/components/primitives/sonner.tsx +190 -8
- package/src/ui/components/primitives/switch.tsx +1 -0
- package/src/ui/components/primitives/tabs.tsx +1 -0
- package/src/ui/components/primitives/textarea.tsx +1 -1
- package/src/ui/components/primitives/toggle.tsx +1 -1
- package/src/ui/components/primitives/tooltip.tsx +1 -0
- package/src/ui/docs/DocBrowser.tsx +102 -23
- package/src/ui/docs/changelog.tsx +1 -1
- package/src/ui/docs/content/accordion.md +22 -16
- package/src/ui/docs/content/action-form-card.md +8 -8
- package/src/ui/docs/content/action-form-dialog.md +9 -9
- package/src/ui/docs/content/action-form.md +37 -36
- package/src/ui/docs/content/action-list-dialog.md +11 -6
- package/src/ui/docs/content/action-list.md +73 -39
- package/src/ui/docs/content/action-trigger.md +29 -15
- package/src/ui/docs/content/action-view.md +17 -10
- package/src/ui/docs/content/actions.md +9 -9
- package/src/ui/docs/content/ai.md +3 -3
- package/src/ui/docs/content/alert.md +14 -12
- package/src/ui/docs/content/ask.md +11 -0
- package/src/ui/docs/content/aspect-ratio.md +4 -4
- package/src/ui/docs/content/audit.md +2 -2
- package/src/ui/docs/content/auth.md +3 -3
- package/src/ui/docs/content/avatar.md +34 -14
- package/src/ui/docs/content/badge.md +3 -3
- package/src/ui/docs/content/breadcrumb.md +13 -8
- package/src/ui/docs/content/button.md +81 -6
- package/src/ui/docs/content/calendar.md +18 -5
- package/src/ui/docs/content/card.md +27 -1
- package/src/ui/docs/content/carousel.md +16 -11
- package/src/ui/docs/content/chat.md +23 -3
- package/src/ui/docs/content/checkbox.md +7 -7
- package/src/ui/docs/content/cli.md +74 -22
- package/src/ui/docs/content/collapsible.md +8 -8
- package/src/ui/docs/content/command.md +16 -8
- package/src/ui/docs/content/composer.md +17 -2
- package/src/ui/docs/content/content.md +17 -2
- package/src/ui/docs/content/copyable.md +12 -3
- package/src/ui/docs/content/customization.md +5 -5
- package/src/ui/docs/content/cycle.md +3 -3
- package/src/ui/docs/content/data-state.md +11 -12
- package/src/ui/docs/content/data.md +26 -33
- package/src/ui/docs/content/detail.md +22 -4
- package/src/ui/docs/content/dialog.md +339 -31
- package/src/ui/docs/content/dictionary-value.md +17 -10
- package/src/ui/docs/content/dock.md +11 -3
- package/src/ui/docs/content/dot.md +8 -0
- package/src/ui/docs/content/drawer.md +27 -14
- package/src/ui/docs/content/empty-value.md +2 -2
- package/src/ui/docs/content/empty.md +19 -12
- package/src/ui/docs/content/events.md +4 -4
- package/src/ui/docs/content/field.md +34 -12
- package/src/ui/docs/content/getting-started.md +3 -3
- package/src/ui/docs/content/icon-picker.md +19 -4
- package/src/ui/docs/content/input-otp.md +20 -12
- package/src/ui/docs/content/input.md +121 -9
- package/src/ui/docs/content/item.md +27 -13
- package/src/ui/docs/content/kbd.md +19 -11
- package/src/ui/docs/content/label.md +12 -3
- package/src/ui/docs/content/log.md +4 -4
- package/src/ui/docs/content/markdown.md +7 -6
- package/src/ui/docs/content/mcp.md +13 -15
- package/src/ui/docs/content/menu.md +40 -16
- package/src/ui/docs/content/metric-card.md +13 -0
- package/src/ui/docs/content/observability.md +2 -2
- package/src/ui/docs/content/page.md +59 -6
- package/src/ui/docs/content/pagination.md +22 -17
- package/src/ui/docs/content/popover.md +22 -8
- package/src/ui/docs/content/progress.md +15 -16
- package/src/ui/docs/content/queue.md +5 -5
- package/src/ui/docs/content/radio-group.md +20 -12
- package/src/ui/docs/content/router.md +11 -6
- package/src/ui/docs/content/scheduler.md +4 -5
- package/src/ui/docs/content/scroll-area.md +12 -7
- package/src/ui/docs/content/select.md +47 -34
- package/src/ui/docs/content/semantic-context.md +2 -2
- package/src/ui/docs/content/separator.md +5 -5
- package/src/ui/docs/content/sidebar.md +329 -54
- package/src/ui/docs/content/skeleton.md +9 -2
- package/src/ui/docs/content/slider.md +8 -7
- package/src/ui/docs/content/spinner.md +8 -8
- package/src/ui/docs/content/split.md +29 -5
- package/src/ui/docs/content/storage.md +6 -8
- package/src/ui/docs/content/switch.md +8 -7
- package/src/ui/docs/content/table.md +13 -3
- package/src/ui/docs/content/tabs.md +28 -14
- package/src/ui/docs/content/testing.md +9 -11
- package/src/ui/docs/content/textarea.md +12 -4
- package/src/ui/docs/content/toast.md +47 -13
- package/src/ui/docs/content/toggle.md +75 -7
- package/src/ui/docs/content/tokens.md +7 -7
- package/src/ui/docs/content/tooltip.md +19 -11
- package/src/ui/docs/content/truncate.md +15 -8
- package/src/ui/docs/content/ui.md +24 -9
- package/src/ui/docs/content/upgrading.md +7 -8
- package/src/ui/docs/doc-client.tsx +5 -5
- package/src/ui/docs/doc.tsx +26 -14
- package/src/ui/docs/registry.tsx +25 -42
- package/src/ui/docs/standalone.tsx +2 -2
- package/src/ui/drivers/react.tsx +17 -12
- package/src/ui/lib/action-errors.ts +45 -0
- package/src/ui/lib/zod-pt-br.ts +31 -4
- package/src/ui/meta.ts +65 -95
- package/src/ui/react.tsx +17 -16
- package/src/ui/theme.css +60 -8
- package/src/vite/design.ts +6 -18
- package/src/ui/components/primitives/alert-dialog.tsx +0 -192
- package/src/ui/docs/content/alert-dialog.md +0 -73
- package/src/ui/docs/content/button-group.md +0 -71
- package/src/ui/docs/content/confirm.md +0 -120
- package/src/ui/docs/content/input-group.md +0 -79
- package/src/ui/docs/content/page-state.md +0 -45
- package/src/ui/docs/content/toggle-group.md +0 -81
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
##
|
|
1
|
+
## Carregar um recurso
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
Use `ActionView` para carregar um recurso por uma `ViewAction` e manter carregamento, erro e vazio no
|
|
4
|
+
mesmo fluxo. No exemplo, alterne entre os workspaces para observar o carregamento e a recuperação de
|
|
5
|
+
erro. O consumidor compõe somente o conteúdo disponível.
|
|
6
6
|
|
|
7
7
|
```tsx preview col
|
|
8
8
|
const [id, setId] = useState('empresa-x')
|
|
@@ -35,13 +35,20 @@ render(
|
|
|
35
35
|
)
|
|
36
36
|
```
|
|
37
37
|
|
|
38
|
-
##
|
|
38
|
+
## useViewAction
|
|
39
39
|
|
|
40
|
-
|
|
40
|
+
`ActionView` é uma composição sobre `useViewAction(action, input)`, que devolve `data`, `error`,
|
|
41
|
+
`isLoading` e `refetch` sob o `QueryClientProvider`. Use o hook direto quando o recurso alimenta
|
|
42
|
+
mais de uma região da tela ou quando o carregamento precisa ser orquestrado por outro componente.
|
|
43
|
+
|
|
44
|
+
## Propriedades de ActionView
|
|
45
|
+
|
|
46
|
+
| Propriedade | Tipo | Padrão | Descrição |
|
|
41
47
|
|---|---|---|---|
|
|
42
48
|
| `action` | `ViewAction<TInput, TData>` | | A ViewAction do Opus (kind view, 1 recurso). |
|
|
43
49
|
| `input` | `TInput` | | Geralmente { id } — mudou, recarrega. |
|
|
44
|
-
| `children` | `(data: TData, refetch) => ReactNode` | |
|
|
45
|
-
| `render` | `(data: TData, refetch) => ReactNode` | | Alias de
|
|
46
|
-
| `loading
|
|
47
|
-
| `
|
|
50
|
+
| `children` | `(data: TData, refetch) => ReactNode` | | Conteúdo apresentado quando os dados estão disponíveis. `refetch` permite recarregar por código. |
|
|
51
|
+
| `render` | `(data: TData, refetch) => ReactNode` | | Alias de compatibilidade de `children`; `children` tem precedência. |
|
|
52
|
+
| `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. |
|
|
53
|
+
| `empty` | `ReactNode` | `nada` | Sobrescreve o estado vazio (200 sem dado). |
|
|
54
|
+
| `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. |
|
|
@@ -10,7 +10,7 @@ o handler e a web usa a mesma definição para executar ou renderizar a operaç
|
|
|
10
10
|
|
|
11
11
|
## Contrato primeiro
|
|
12
12
|
|
|
13
|
-
> `defineContract` no `shared/` — entidades, schemas (zod + `t.*`
|
|
13
|
+
> `defineContract` no `shared/` — entidades, schemas (zod + `t.*` para tipos lógicos) e os
|
|
14
14
|
> metadados da action. `api` e `web` importam; nada se duplica.
|
|
15
15
|
|
|
16
16
|
```ts
|
|
@@ -64,18 +64,18 @@ name → kind → (label / summary / messages / tags…)
|
|
|
64
64
|
→ invalidates
|
|
65
65
|
```
|
|
66
66
|
|
|
67
|
-
Fail-closed por padrão: `input`/`output` via `z.object` + `t.*`
|
|
67
|
+
Fail-closed por padrão: `input`/`output` via `z.object` + `t.*` para os tipos lógicos; `authorize`
|
|
68
68
|
declarado ou gate explícito do adapter.
|
|
69
69
|
|
|
70
|
-
Os átomos do catálogo servem
|
|
70
|
+
Os átomos do catálogo servem também dentro dos schemas de input/output — não re-escreva
|
|
71
71
|
regex do que o Opus já valida: `z.object({ tag: t.slug().zod(), contato: t.email().zod() })`.
|
|
72
72
|
O `.zod()` devolve o schema zod subjacente do tipo lógico (slug, email, phone, money…).
|
|
73
73
|
|
|
74
74
|
## Modo design — o mock mora no contrato
|
|
75
75
|
|
|
76
76
|
Um `mockHandler` no contrato deixa a UI rodar com dado realista **sem backend nem banco**: em
|
|
77
|
-
`OPUS_MODE=design` o runtime roteia o `execute`
|
|
78
|
-
ausente). Como ele fica no
|
|
77
|
+
`OPUS_MODE=design` o runtime roteia o `execute` para o `mockHandler` (cai no `handler` real se
|
|
78
|
+
ausente). Como ele fica no contrato, e não no `bindAction`, é isomorfo — o design autora, o
|
|
79
79
|
handoff pluga o handler, e o mock nem toca `ctx.db`.
|
|
80
80
|
|
|
81
81
|
Alimente com `fake`/`fakeMany` (fixtures determinísticas do próprio schema — ver [Testes](testing)):
|
|
@@ -92,15 +92,15 @@ export const eventGet = defineContract({
|
|
|
92
92
|
})
|
|
93
93
|
// listas: `mockHandler: () => fakeMany(EventEntity.zod(), 20)`
|
|
94
94
|
|
|
95
|
-
// o handoff, depois, só pluga o real —
|
|
95
|
+
// o handoff, depois, só pluga o real — mesmo contrato:
|
|
96
96
|
export const eventGetImpl = bindAction(eventGet, { handler: async (ctx, input) => { /* db */ } })
|
|
97
97
|
```
|
|
98
98
|
|
|
99
99
|
O `mockHandler` roda no **servidor em modo design** (`OPUS_MODE=design`), não no cliente — e
|
|
100
100
|
quem sobe esse servidor é o próprio dev server: o plugin `opusDesign()` (`@softize/opus/vite`)
|
|
101
101
|
monta o runtime Opus DENTRO do vite e serve `/api` in-process, com os mocks respondendo e
|
|
102
|
-
qualquer `server.proxy`
|
|
103
|
-
503 em envelope — nada vaza
|
|
102
|
+
qualquer `server.proxy` para backend externo desligado (prefixo ex-proxy sem cobertura responde
|
|
103
|
+
503 em envelope — nada vaza para prod). A SPA chama `/api` normal e recebe o dado fake, isolado:
|
|
104
104
|
|
|
105
105
|
```ts
|
|
106
106
|
// vite.config.ts
|
|
@@ -118,7 +118,7 @@ persistindo, o envelope traz a mensagem-guia apontando o entry.
|
|
|
118
118
|
|
|
119
119
|
Como o contrato é isomorfo, o `mockHandler` também acompanha o **bundle web** — peso morto lá
|
|
120
120
|
(a SPA nunca o chama; o dado é fake). Tirá-lo do bundle de prod é um transform de build
|
|
121
|
-
(deferido); **não** dá
|
|
121
|
+
(deferido); **não** dá para gatear no call-site com `import.meta.env` sem quebrar o servidor
|
|
122
122
|
(não existe em Node). É a materialização Opus-nativa do "mock = contrato": o design não é
|
|
123
123
|
descartável — vira o contrato que o backend honra.
|
|
124
124
|
|
|
@@ -64,10 +64,10 @@ handler: async (ctx, input) => {
|
|
|
64
64
|
Marque uma action com `ai: { enabled: true }` no contrato e ela vira uma **tool** que o
|
|
65
65
|
modelo pode chamar. Aí `ctx.ai.run(prompt)` roda o loop agêntico sobre as actions `ai:enabled`:
|
|
66
66
|
o modelo escolhe a tool → o runtime executa a action **como o usuário logado** (limitado pelo
|
|
67
|
-
`ctx.can`) → o resultado volta
|
|
67
|
+
`ctx.can`) → o resultado volta para o modelo → repete até a resposta em texto.
|
|
68
68
|
|
|
69
69
|
```ts
|
|
70
|
-
// A action opta por entrar
|
|
70
|
+
// A action opta por entrar; o schema do contrato também descreve a ferramenta:
|
|
71
71
|
export const buscarNotas = defineContract({
|
|
72
72
|
name: 'nota.buscar',
|
|
73
73
|
kind: 'list',
|
|
@@ -76,7 +76,7 @@ export const buscarNotas = defineContract({
|
|
|
76
76
|
ai: { enabled: true, description: 'Busca notas por cliente e mês.' },
|
|
77
77
|
})
|
|
78
78
|
|
|
79
|
-
// No handler — ou fora dele, via runtime.aiFor(base),
|
|
79
|
+
// No handler — ou fora dele, via runtime.aiFor(base), para o backend de um chat:
|
|
80
80
|
const { text } = await ctx.ai!.run('Quantas notas a Empresa X emitiu em junho?')
|
|
81
81
|
// o modelo chamou nota.buscar sozinho, como o usuário logado, e respondeu em texto.
|
|
82
82
|
```
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
## Forma curta
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Use a forma curta quando o aviso tiver ícone, título e uma frase. Declare `title`, `description` e
|
|
4
|
+
`icon`; o componente monta os slots e anuncia o conteúdo com `role="alert"`.
|
|
4
5
|
|
|
5
6
|
```tsx preview col
|
|
6
7
|
<Alert icon={<Info />} title="Opus 2.8.0" description="Este workspace usa a versão pinada em opus.json." />
|
|
@@ -37,10 +38,9 @@ borda e texto; o conteúdo comunica o significado sem depender somente da cor.
|
|
|
37
38
|
## Mídia é opcional
|
|
38
39
|
|
|
39
40
|
Sem `icon` o alert mantém somente a coluna de texto. Com ele, a forma curta materializa
|
|
40
|
-
`AlertMedia` à esquerda e `AlertHeader` à direita. A mídia
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
uma descrição.
|
|
41
|
+
`AlertMedia` à esquerda e `AlertHeader` à direita. A mídia mantém uma moldura quadrada de tamanho
|
|
42
|
+
estável, mesmo quando o título ou a descrição ocupam mais linhas. Texto solto como filho também
|
|
43
|
+
vale (`<Alert>Sincronizado.</Alert>`) e se torna uma descrição.
|
|
44
44
|
|
|
45
45
|
```tsx preview col
|
|
46
46
|
<Alert title="Sem provider próprio" description="As conversas usam o padrão do sistema." />
|
|
@@ -51,7 +51,8 @@ uma descrição.
|
|
|
51
51
|
|
|
52
52
|
Quando a mensagem precisa de conteúdo rico, componha os slots da família. `AlertMedia`,
|
|
53
53
|
`AlertHeader` e `AlertActions` são filhos diretos de `Alert`; `AlertTitle` e
|
|
54
|
-
`AlertDescription` pertencem ao header.
|
|
54
|
+
`AlertDescription` pertencem ao header. As ações ficam no fim lógico da superfície e centralizadas
|
|
55
|
+
verticalmente na mesma linha do conteúdo — a mesma posição usada pelas ações do Toast.
|
|
55
56
|
|
|
56
57
|
```tsx preview col
|
|
57
58
|
<Alert context="danger">
|
|
@@ -59,21 +60,22 @@ Quando a mensagem precisa de conteúdo rico, componha os slots da família. `Ale
|
|
|
59
60
|
<CircleAlert />
|
|
60
61
|
</AlertMedia>
|
|
61
62
|
<AlertHeader>
|
|
62
|
-
<AlertTitle>Não deu
|
|
63
|
+
<AlertTitle>Não deu para publicar</AlertTitle>
|
|
63
64
|
<AlertDescription>
|
|
64
65
|
<p>O registry recusou a versão 3.0.0 — ela já existe.</p>
|
|
65
66
|
<p>Suba o patch e tente de novo.</p>
|
|
66
67
|
</AlertDescription>
|
|
67
68
|
</AlertHeader>
|
|
68
69
|
<AlertActions>
|
|
69
|
-
<Button size="sm"
|
|
70
|
+
<Button size="sm">
|
|
70
71
|
Tentar novamente
|
|
71
72
|
</Button>
|
|
72
73
|
</AlertActions>
|
|
73
74
|
</Alert>
|
|
74
75
|
```
|
|
75
76
|
|
|
76
|
-
Os dois modos convivem: com `title
|
|
77
|
+
Os dois modos convivem: com `title` ou `description`, `children` entra depois da mensagem e recebe a
|
|
78
|
+
ação.
|
|
77
79
|
|
|
78
80
|
```tsx preview col
|
|
79
81
|
<Alert
|
|
@@ -81,15 +83,15 @@ Os dois modos convivem: com `title`/`description` preenchidos, `children` entra
|
|
|
81
83
|
title="Sessão presa"
|
|
82
84
|
description="O ambiente não subiu no tempo esperado."
|
|
83
85
|
>
|
|
84
|
-
<Button size="sm"
|
|
86
|
+
<Button size="sm">
|
|
85
87
|
Reiniciar
|
|
86
88
|
</Button>
|
|
87
89
|
</Alert>
|
|
88
90
|
```
|
|
89
91
|
|
|
90
|
-
##
|
|
92
|
+
## Propriedades de Alert
|
|
91
93
|
|
|
92
|
-
|
|
|
94
|
+
| Propriedade | Tipo | Padrão | Descrição |
|
|
93
95
|
| ------------- | ----------------------------------------------------------- | ----------- | --------------------------------------------------------------------------------------------------------------------------------------- |
|
|
94
96
|
| `title` | `React.ReactNode` | | Título do alert (a forma curta). Não é o atributo `title` do HTML — esse é tooltip nativo, banido na casa, e o componente não o aceita. |
|
|
95
97
|
| `description` | `React.ReactNode` | | A frase. Sozinha, dispensa título. |
|
|
@@ -29,3 +29,14 @@ render(
|
|
|
29
29
|
```
|
|
30
30
|
|
|
31
31
|
Cada pergunta exige pelo menos uma opção válida selecionada **ou** texto livre não vazio. `busy` mostra o progresso no botão e trava os controles; `disabled` apenas trava a interação. A ordem de `answers` acompanha a ordem de `questions`, e o `header` de cada resposta é derivado de `question.header` (ou do próprio enunciado quando o header estiver vazio).
|
|
32
|
+
|
|
33
|
+
## Propriedades de Ask
|
|
34
|
+
|
|
35
|
+
| Propriedade | Tipo | Padrão | Descrição |
|
|
36
|
+
|---|---|---|---|
|
|
37
|
+
| `questions` | `AskQuestion[]` | | Uma a quatro perguntas do contrato de elicitação; fora dessa faixa o envio é bloqueado. |
|
|
38
|
+
| `answers` | `AskAnswer[]` | | Respostas controladas, na mesma ordem de `questions`; entradas ausentes contam como vazias. |
|
|
39
|
+
| `onChange` | `(answers: AskAnswer[]) => void` | | Recebe a lista completa a cada alteração. |
|
|
40
|
+
| `onSubmit` | `(answers: AskAnswer[]) => void` | | Dispara somente quando toda pergunta tem uma opção ou texto livre. |
|
|
41
|
+
| `disabled` | `boolean` | `false` | Trava as opções e o envio. |
|
|
42
|
+
| `busy` | `boolean` | `false` | Envio em andamento: o botão mostra o spinner e desabilita. |
|
|
@@ -15,7 +15,7 @@ contêiner (o pai): a altura o componente deriva sozinho.
|
|
|
15
15
|
|
|
16
16
|
## Quadrado (1/1)
|
|
17
17
|
|
|
18
|
-
ratio={1} trava
|
|
18
|
+
ratio={1} trava em um quadrado — o formato dos avatares de agente e dos ícones de skill, onde a
|
|
19
19
|
moldura precisa ser previsível.
|
|
20
20
|
|
|
21
21
|
```tsx preview col-start
|
|
@@ -57,10 +57,10 @@ layout quando o preview carrega.
|
|
|
57
57
|
</div>
|
|
58
58
|
```
|
|
59
59
|
|
|
60
|
-
##
|
|
60
|
+
## Propriedades de AspectRatio
|
|
61
61
|
|
|
62
|
-
|
|
|
62
|
+
| Propriedade | Tipo | Padrão | Descrição |
|
|
63
63
|
|---|---|---|---|
|
|
64
|
-
| `ratio` | `number` | `1` | A razão largura/altura. 16/9
|
|
64
|
+
| `ratio` | `number` | `1` | A razão largura/altura. 16/9 para vídeo/preview, 1 para quadrado, 4/3 para clássico. |
|
|
65
65
|
| `children` | `React.ReactNode` | | O conteúdo a enquadrar (img, iframe, div) — preencha com h-full w-full e object-cover. |
|
|
66
66
|
| `className` | `string` | | Estilo do bloco — borda, rounded e overflow-hidden moram aqui, não no filho. |
|
|
@@ -5,7 +5,7 @@ title: Auditoria
|
|
|
5
5
|
# Auditoria
|
|
6
6
|
|
|
7
7
|
Toda action executada vira um registro imutável: quem, o quê, quando, com que entrada e
|
|
8
|
-
resultado. O runtime emite um `AuditRecord` por execução
|
|
8
|
+
resultado. O runtime emite um `AuditRecord` por execução para o(s) sink(s) configurado(s) — de
|
|
9
9
|
graça, sem o handler pedir. O contrato é o `AuditSink`.
|
|
10
10
|
|
|
11
11
|
## O contrato
|
|
@@ -43,7 +43,7 @@ interface AuditRecord {
|
|
|
43
43
|
import { consoleAudit } from '@softize/opus/audit/console'
|
|
44
44
|
import { pgAudit } from '@softize/opus/audit/pg'
|
|
45
45
|
|
|
46
|
-
// Dev: uma linha por action (pretty
|
|
46
|
+
// Dev: uma linha por action (pretty em um TTY, json senão).
|
|
47
47
|
const dev = consoleAudit()
|
|
48
48
|
|
|
49
49
|
// Produção: grava na tabela audit_log (Postgres).
|
|
@@ -7,7 +7,7 @@ title: Autenticação
|
|
|
7
7
|
Quem é o usuário, de qual tenant, e o que ele pode. O contrato é um adapter do core
|
|
8
8
|
(`AuthAdapter`): a cada request o runtime chama `resolveContext` e injeta o resultado no
|
|
9
9
|
handler — `ctx.user`, `ctx.tenantId`, `ctx.can`. O Opus **não** implementa RBAC/ABAC; ele
|
|
10
|
-
delega a decisão
|
|
10
|
+
delega a decisão para o `can` que o driver pluga.
|
|
11
11
|
|
|
12
12
|
## O contrato
|
|
13
13
|
|
|
@@ -31,7 +31,7 @@ política usada por ela.
|
|
|
31
31
|
import { jwtAuth } from '@softize/opus/auth/jwt'
|
|
32
32
|
import { betterAuthSession } from '@softize/opus/auth/better-auth'
|
|
33
33
|
|
|
34
|
-
// JWT: valida o token (HS256 por padrão) e mapeia o payload
|
|
34
|
+
// JWT: valida o token (HS256 por padrão) e mapeia o payload para o User.
|
|
35
35
|
const jwt = jwtAuth({ secret: process.env.JWT_SECRET! })
|
|
36
36
|
|
|
37
37
|
// better-auth: valida a sessão contra um IdP better-auth remoto.
|
|
@@ -44,7 +44,7 @@ const idp = betterAuthSession({
|
|
|
44
44
|
|
|
45
45
|
O `jwt` procura o token no `Authorization: Bearer`, em cookie ou custom (via `getToken`); o
|
|
46
46
|
`secret` pode ser string ou um resolver async por `kid`. O `betterAuthSession` faz fetch da
|
|
47
|
-
sessão no IdP (`timeoutMs`, default 5s) e mapeia
|
|
47
|
+
sessão no IdP (`timeoutMs`, default 5s) e mapeia para o `User`/tenant/can (o `can` default nega
|
|
48
48
|
tudo — plugue o seu).
|
|
49
49
|
|
|
50
50
|
## No runtime
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
##
|
|
1
|
+
## Retrato com imagem
|
|
2
2
|
|
|
3
3
|
AvatarImage com src/alt e AvatarFallback com as iniciais — o fallback aparece enquanto a imagem
|
|
4
4
|
carrega ou se ela falha.
|
|
@@ -12,8 +12,8 @@ carrega ou se ela falha.
|
|
|
12
12
|
|
|
13
13
|
## Fallback de iniciais
|
|
14
14
|
|
|
15
|
-
Sem AvatarImage (ou com src quebrado), só o AvatarFallback renderiza — iniciais
|
|
16
|
-
|
|
15
|
+
Sem AvatarImage (ou com src quebrado), só o AvatarFallback renderiza — iniciais para pessoa, ícone
|
|
16
|
+
para agente.
|
|
17
17
|
|
|
18
18
|
```tsx preview
|
|
19
19
|
<Avatar>
|
|
@@ -28,7 +28,7 @@ pra agente.
|
|
|
28
28
|
|
|
29
29
|
## Tamanhos
|
|
30
30
|
|
|
31
|
-
size sm/default/lg — o fallback acompanha o tamanho. sm
|
|
31
|
+
size sm/default/lg — o fallback acompanha o tamanho. sm para listas densas, lg para cabeçalho de
|
|
32
32
|
workspace.
|
|
33
33
|
|
|
34
34
|
```tsx preview
|
|
@@ -45,8 +45,8 @@ workspace.
|
|
|
45
45
|
|
|
46
46
|
## Com selo de status
|
|
47
47
|
|
|
48
|
-
AvatarBadge é o ponto no canto inferior — verde
|
|
49
|
-
|
|
48
|
+
AvatarBadge é o ponto no canto inferior — verde para o agente developer rodando uma sessão, cinza
|
|
49
|
+
para o ocioso. Tinja com className.
|
|
50
50
|
|
|
51
51
|
```tsx preview
|
|
52
52
|
<Avatar>
|
|
@@ -82,13 +82,33 @@ excedente — os membros do workspace Empresa X.
|
|
|
82
82
|
</AvatarGroup>
|
|
83
83
|
```
|
|
84
84
|
|
|
85
|
-
##
|
|
85
|
+
## Propriedades de Avatar
|
|
86
86
|
|
|
87
|
-
|
|
|
87
|
+
| Propriedade | Tipo | Padrão | Descrição |
|
|
88
88
|
|---|---|---|---|
|
|
89
|
-
| `size`
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
|
94
|
-
|
|
89
|
+
| `size` | `'sm' \| 'default' \| 'lg'` | `'default'` | Diâmetro do retrato; o fallback e o selo acompanham a escala. |
|
|
90
|
+
|
|
91
|
+
## Propriedades de AvatarImage
|
|
92
|
+
|
|
93
|
+
| Propriedade | Tipo | Padrão | Descrição |
|
|
94
|
+
|---|---|---|---|
|
|
95
|
+
| `src` | `string` | | URL da imagem. Enquanto ela carrega ou quando falha, `AvatarFallback` ocupa o lugar. |
|
|
96
|
+
| `alt` | `string` | | Texto alternativo que identifica a pessoa ou o agente. |
|
|
97
|
+
|
|
98
|
+
## Propriedades de AvatarFallback
|
|
99
|
+
|
|
100
|
+
| Propriedade | Tipo | Padrão | Descrição |
|
|
101
|
+
|---|---|---|---|
|
|
102
|
+
| `children` | `React.ReactNode` | | Iniciais ou ícone exibido quando a imagem não está disponível. |
|
|
103
|
+
|
|
104
|
+
## Propriedades de AvatarBadge
|
|
105
|
+
|
|
106
|
+
| Propriedade | Tipo | Padrão | Descrição |
|
|
107
|
+
|---|---|---|---|
|
|
108
|
+
| `className` | `string` | | Classes usadas para comunicar visualmente o status no selo. |
|
|
109
|
+
|
|
110
|
+
## Propriedades de AvatarGroupCount
|
|
111
|
+
|
|
112
|
+
| Propriedade | Tipo | Padrão | Descrição |
|
|
113
|
+
|---|---|---|---|
|
|
114
|
+
| `children` | `React.ReactNode` | | Quantidade excedente no fim do grupo, como `+3`. |
|
|
@@ -24,7 +24,7 @@ decisão em cada tela.
|
|
|
24
24
|
|
|
25
25
|
## Com ícone
|
|
26
26
|
|
|
27
|
-
Um svg filho ganha size-3 automaticamente — bom
|
|
27
|
+
Um svg filho ganha size-3 automaticamente — bom para reforçar o estado sem crescer o rótulo.
|
|
28
28
|
|
|
29
29
|
```tsx preview
|
|
30
30
|
<Badge context="success"><CircleCheck /> Regressão verde</Badge>
|
|
@@ -41,9 +41,9 @@ variantes.
|
|
|
41
41
|
</Badge>
|
|
42
42
|
```
|
|
43
43
|
|
|
44
|
-
##
|
|
44
|
+
## Propriedades de Badge
|
|
45
45
|
|
|
46
|
-
|
|
|
46
|
+
| Propriedade | Tipo | Padrão | Descrição |
|
|
47
47
|
|---|---|---|---|
|
|
48
48
|
| `context` | `'neutral' \| 'primary' \| 'info' \| 'success' \| 'warning' \| 'danger'` | `'neutral'` | O significado ou destaque contextual. |
|
|
49
49
|
| `variant` | `'solid' \| 'subtle' \| 'outline'` | `'subtle'` | O tratamento visual aplicado ao contexto. |
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
##
|
|
1
|
+
## Caminho atual
|
|
2
2
|
|
|
3
3
|
A composição é manual: BreadcrumbLink nos níveis navegáveis, BreadcrumbPage no atual (não
|
|
4
4
|
clicável, aria-current=page) e um BreadcrumbSeparator entre cada item.
|
|
@@ -23,7 +23,7 @@ clicável, aria-current=page) e um BreadcrumbSeparator entre cada item.
|
|
|
23
23
|
|
|
24
24
|
## Com ícone e separador custom
|
|
25
25
|
|
|
26
|
-
O primeiro nível pode levar um ícone do lucide. BreadcrumbSeparator aceita children
|
|
26
|
+
O primeiro nível pode levar um ícone do lucide. BreadcrumbSeparator aceita children para trocar o
|
|
27
27
|
chevron padrão por outro glifo (aqui, uma barra).
|
|
28
28
|
|
|
29
29
|
```tsx preview col-start
|
|
@@ -53,7 +53,7 @@ chevron padrão por outro glifo (aqui, uma barra).
|
|
|
53
53
|
|
|
54
54
|
## Colapsado
|
|
55
55
|
|
|
56
|
-
Trilha funda demais
|
|
56
|
+
Trilha funda demais para o espaço: BreadcrumbEllipsis substitui os níveis do meio (que viram um
|
|
57
57
|
menu/popover) e mantém só a raiz e o destino.
|
|
58
58
|
|
|
59
59
|
```tsx preview col-start
|
|
@@ -78,10 +78,15 @@ menu/popover) e mantém só a raiz e o destino.
|
|
|
78
78
|
</Breadcrumb>
|
|
79
79
|
```
|
|
80
80
|
|
|
81
|
-
##
|
|
81
|
+
## Propriedades de BreadcrumbLink
|
|
82
82
|
|
|
83
|
-
|
|
|
83
|
+
| Propriedade | Tipo | Padrão | Descrição |
|
|
84
84
|
|---|---|---|---|
|
|
85
|
-
| `asChild`
|
|
86
|
-
| `href`
|
|
87
|
-
|
|
85
|
+
| `asChild` | `boolean` | `false` | Repassa as propriedades ao filho para integrar o link do roteador no lugar de `<a>`. |
|
|
86
|
+
| `href` | `string` | | Destino do nível navegável. |
|
|
87
|
+
|
|
88
|
+
## Propriedades de BreadcrumbSeparator
|
|
89
|
+
|
|
90
|
+
| Propriedade | Tipo | Padrão | Descrição |
|
|
91
|
+
|---|---|---|---|
|
|
92
|
+
| `children` | `React.ReactNode` | `<ChevronRight />` | Elemento entre os itens. Omita para usar o chevron padrão ou passe outro ícone. |
|
|
@@ -31,7 +31,7 @@ O tamanho icon exige `aria-label`, porque não há texto visível. Os botões s
|
|
|
31
31
|
|
|
32
32
|
busy = ação em andamento (DEPOIS do clique): o Spinner e o disabled vêm do botão. Com icon, o
|
|
33
33
|
Spinner TROCA o ícone (não soma). Não confunda com carregar conteúdo (ANTES) — isso é Spinner
|
|
34
|
-
centralizado/Skeleton
|
|
34
|
+
centralizado/Skeleton em um nível de página.
|
|
35
35
|
|
|
36
36
|
```tsx preview
|
|
37
37
|
<Button disabled>Desabilitado</Button>
|
|
@@ -43,7 +43,7 @@ centralizado/Skeleton num nível de página.
|
|
|
43
43
|
## Como outro elemento (asChild)
|
|
44
44
|
|
|
45
45
|
Âncora com cara de botão: asChild renderiza o filho (Radix Slot) — sem forkar estilo.
|
|
46
|
-
buttonVariants serve
|
|
46
|
+
buttonVariants serve para o caso sem filho único.
|
|
47
47
|
|
|
48
48
|
```tsx preview
|
|
49
49
|
<Button asChild variant="outline">
|
|
@@ -51,13 +51,88 @@ buttonVariants serve pro caso sem filho único.
|
|
|
51
51
|
</Button>
|
|
52
52
|
```
|
|
53
53
|
|
|
54
|
-
##
|
|
54
|
+
## Propriedades de Button
|
|
55
55
|
|
|
56
|
-
|
|
|
56
|
+
| Propriedade | Tipo | Padrão | Descrição |
|
|
57
57
|
|---|---|---|---|
|
|
58
58
|
| `context` | `'neutral' \| 'primary' \| 'danger'` | `'primary'` | A hierarquia ou o risco comunicado pela ação. |
|
|
59
59
|
| `variant` | `'solid' \| 'subtle' \| 'outline' \| 'ghost' \| 'link'` | `'solid'` | O tratamento visual aplicado ao contexto. |
|
|
60
60
|
| `size` | `'default' \| 'sm' \| 'lg' \| 'icon' \| 'icon-sm' \| 'icon-xs'` | `'default'` | O tamanho. Os icon* são quadrados (2.25/2/1.5rem) para botões só de ícone, com `aria-label`. |
|
|
61
|
-
| `asChild` | `boolean` | `false` | Renderiza como o filho (Radix Slot) em vez de `<button>` —
|
|
62
|
-
| `busy` | `boolean` | `false` | Ação em andamento (depois do clique): mostra Spinner + desabilita. Não é "carregando" de conteúdo (que é Spinner/Skeleton
|
|
61
|
+
| `asChild` | `boolean` | `false` | Renderiza como o filho (Radix Slot) em vez de `<button>` — para âncoras e afins. |
|
|
62
|
+
| `busy` | `boolean` | `false` | Ação em andamento (depois do clique): mostra Spinner + desabilita. Não é "carregando" de conteúdo (que é Spinner/Skeleton em um nível de página). |
|
|
63
63
|
| `icon` | `React.ElementType` | | Ícone à esquerda (ex.: icon={Plus}). No busy é trocado pelo Spinner — não soma. |
|
|
64
|
+
|
|
65
|
+
## ButtonGroup
|
|
66
|
+
|
|
67
|
+
Use `ButtonGroup` quando ações relacionadas precisarem formar um bloco contínuo. As bordas internas
|
|
68
|
+
colapsam e somente as pontas externas permanecem arredondadas. Mantenha a mesma variante nos filhos
|
|
69
|
+
para preservar a unidade visual.
|
|
70
|
+
|
|
71
|
+
```tsx preview
|
|
72
|
+
<ButtonGroup>
|
|
73
|
+
<Button variant="outline">Visão geral</Button>
|
|
74
|
+
<Button variant="outline">Sessões</Button>
|
|
75
|
+
<Button variant="outline">Habilidades</Button>
|
|
76
|
+
</ButtonGroup>
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
### Ação dividida
|
|
80
|
+
|
|
81
|
+
Combine a ação principal, um separador e um botão de ícone quando o mesmo comando oferecer
|
|
82
|
+
variações.
|
|
83
|
+
|
|
84
|
+
```tsx preview
|
|
85
|
+
<ButtonGroup>
|
|
86
|
+
<Button icon={Play}>Rodar agente developer</Button>
|
|
87
|
+
<ButtonGroupSeparator />
|
|
88
|
+
<Button size="icon" aria-label="Mais opções">
|
|
89
|
+
<ChevronDown />
|
|
90
|
+
</Button>
|
|
91
|
+
</ButtonGroup>
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
### Com rótulo
|
|
95
|
+
|
|
96
|
+
`ButtonGroupText` adiciona um contexto inerte ao grupo. Ele também aceita `asChild` para assumir a
|
|
97
|
+
semântica de outro elemento, como `label`.
|
|
98
|
+
|
|
99
|
+
```tsx preview
|
|
100
|
+
<ButtonGroup>
|
|
101
|
+
<ButtonGroupText>
|
|
102
|
+
<GitBranch />
|
|
103
|
+
empresa-x-api
|
|
104
|
+
</ButtonGroupText>
|
|
105
|
+
<Button variant="outline" icon={RotateCw}>Sincronizar</Button>
|
|
106
|
+
</ButtonGroup>
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
### Vertical
|
|
110
|
+
|
|
111
|
+
`orientation="vertical"` empilha os filhos e transfere a junção das bordas para o eixo vertical.
|
|
112
|
+
|
|
113
|
+
```tsx preview col-start
|
|
114
|
+
<ButtonGroup orientation="vertical">
|
|
115
|
+
<Button variant="outline" size="icon" aria-label="Rodar sessão"><Play /></Button>
|
|
116
|
+
<Button variant="outline" size="icon" aria-label="Pausar sessão"><Pause /></Button>
|
|
117
|
+
<Button variant="outline" size="icon" aria-label="Reiniciar sessão"><RotateCw /></Button>
|
|
118
|
+
</ButtonGroup>
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
### Propriedades de ButtonGroup
|
|
122
|
+
|
|
123
|
+
| Propriedade | Tipo | Padrão | Descrição |
|
|
124
|
+
|---|---|---|---|
|
|
125
|
+
| `orientation` | `'horizontal' \| 'vertical'` | `'horizontal'` | Direção do bloco e do colapso das bordas. |
|
|
126
|
+
| `shape` | `'default' \| 'pill'` | `'default'` | Geometria das extremidades externas do grupo. |
|
|
127
|
+
|
|
128
|
+
### Propriedades de ButtonGroupSeparator
|
|
129
|
+
|
|
130
|
+
| Propriedade | Tipo | Padrão | Descrição |
|
|
131
|
+
|---|---|---|---|
|
|
132
|
+
| `orientation` | `'horizontal' \| 'vertical'` | `'vertical'` | Direção do traço divisor; use vertical em grupos horizontais. |
|
|
133
|
+
|
|
134
|
+
### Propriedades de ButtonGroupText
|
|
135
|
+
|
|
136
|
+
| Propriedade | Tipo | Padrão | Descrição |
|
|
137
|
+
|---|---|---|---|
|
|
138
|
+
| `asChild` | `boolean` | `false` | Renderiza como o filho para assumir outra semântica sem perder o estilo. |
|
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
O calendário fala pt-BR por padrão: nomes de mês e de dia vêm do `locale` (`ptBR` de
|
|
2
|
+
`date-fns/locale`) e os controles de navegação têm rótulos acessíveis em português. Passe outro
|
|
3
|
+
`locale` para trocar o idioma; `labels` sobrescreve rótulos individualmente.
|
|
4
|
+
|
|
1
5
|
## Dia único
|
|
2
6
|
|
|
3
7
|
mode=single guarda uma Date — controle por selected/onSelect. defaultMonth abre o calendário no mês certo sem mexer na seleção.
|
|
@@ -17,7 +21,7 @@ render(
|
|
|
17
21
|
|
|
18
22
|
## Intervalo
|
|
19
23
|
|
|
20
|
-
mode=range guarda { from, to } — o padrão
|
|
24
|
+
mode=range guarda { from, to } — o padrão para filtrar sessões por janela de datas. O primeiro clique fixa o início; o segundo, o fim.
|
|
21
25
|
|
|
22
26
|
```tsx preview
|
|
23
27
|
const [week, setWeek] = useState<DateRange | undefined>({
|
|
@@ -37,7 +41,7 @@ render(
|
|
|
37
41
|
|
|
38
42
|
## Navegação por dropdown
|
|
39
43
|
|
|
40
|
-
captionLayout=dropdown troca o título do mês por seletores de mês e ano — bom
|
|
44
|
+
captionLayout=dropdown troca o título do mês por seletores de mês e ano — bom para pular para um período distante (ex.: histórico de um repositório) sem clicar mês a mês.
|
|
41
45
|
|
|
42
46
|
```tsx preview
|
|
43
47
|
<Calendar
|
|
@@ -47,16 +51,25 @@ captionLayout=dropdown troca o título do mês por seletores de mês e ano — b
|
|
|
47
51
|
/>
|
|
48
52
|
```
|
|
49
53
|
|
|
50
|
-
##
|
|
54
|
+
## Propriedades de Calendar
|
|
51
55
|
|
|
52
|
-
|
|
|
56
|
+
| Propriedade | Tipo | Padrão | Descrição |
|
|
53
57
|
|---|---|---|---|
|
|
54
58
|
| `mode` | `'single' \| 'multiple' \| 'range'` | | O tipo de seleção — define o formato de selected/onSelect (Date, Date[] ou { from, to }). |
|
|
55
59
|
| `selected` | `Date \| Date[] \| DateRange` | | A seleção atual no modo controlado — o formato segue o mode. Pareie com onSelect. |
|
|
56
60
|
| `onSelect` | `(selected) => void` | | Chamado quando o usuário escolhe uma data. O argumento segue o mode. |
|
|
57
61
|
| `defaultMonth` | `Date` | | O mês exibido ao montar, sem afetar a seleção. |
|
|
58
62
|
| `captionLayout` | `'label' \| 'dropdown' \| 'dropdown-months' \| 'dropdown-years'` | `'label'` | Como o título do mês aparece — label é texto fixo; dropdown vira seletores de mês e ano. |
|
|
59
|
-
| `numberOfMonths` | `number` | `1` | Quantos meses mostrar lado a lado — útil
|
|
63
|
+
| `numberOfMonths` | `number` | `1` | Quantos meses mostrar lado a lado — útil para escolher um intervalo longo. |
|
|
60
64
|
| `disabled` | `Matcher` | | Datas não selecionáveis — uma Date, um array, um { from, to } ou um predicado (date) => boolean. |
|
|
61
65
|
| `buttonVariant` | `Button['variant']` | `'ghost'` | A variante dos botões de navegação (anterior/próximo). |
|
|
62
66
|
| `showOutsideDays` | `boolean` | `true` | Mostra os dias do mês vizinho que completam a primeira e a última semana. |
|
|
67
|
+
| `locale` | `Locale` | `ptBR` | Idioma dos nomes de mês e de dia (um locale do date-fns). |
|
|
68
|
+
| `labels` | `Partial<Labels>` | rótulos em pt-BR | Rótulos acessíveis da navegação e dos seletores; mescla sobre o padrão. |
|
|
69
|
+
|
|
70
|
+
## CalendarDayButton
|
|
71
|
+
|
|
72
|
+
Cada dia é um `CalendarDayButton` — um `Button` ghost quadrado que recebe os modificadores do
|
|
73
|
+
dia (`selected`, `range-start`, `today`…). Use `components={{ DayButton: … }}` para
|
|
74
|
+
decorar o dia (um marcador de evento, por exemplo) partindo dele em vez de reimplementar o
|
|
75
|
+
foco e a seleção.
|
|
@@ -10,7 +10,7 @@ O uso mais comum: a superfície de conteúdo em repouso (`rounded-xl` + `border`
|
|
|
10
10
|
|
|
11
11
|
## Estruturado (header / conteúdo / rodapé)
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
Para painel com estrutura: cada slot é dono do próprio padding (como o Dialog). CardTitle/CardDescription no header; CardFooter alinha as ações.
|
|
14
14
|
|
|
15
15
|
```tsx preview col
|
|
16
16
|
<Card>
|
|
@@ -47,3 +47,29 @@ Pra painel com estrutura: cada slot é dono do próprio padding (como o Dialog).
|
|
|
47
47
|
</CardFooter>
|
|
48
48
|
</Card>
|
|
49
49
|
```
|
|
50
|
+
|
|
51
|
+
## Ação no cabeçalho
|
|
52
|
+
|
|
53
|
+
`CardAction` é o slot de ação do header (um botão ou menu). Quem compõe posiciona — em geral um
|
|
54
|
+
`CardHeader` em `flex-row` com o título de um lado e a ação do outro.
|
|
55
|
+
|
|
56
|
+
```tsx preview col
|
|
57
|
+
<Card>
|
|
58
|
+
<CardHeader className="flex-row items-start justify-between">
|
|
59
|
+
<div>
|
|
60
|
+
<CardTitle>Empresa X</CardTitle>
|
|
61
|
+
<CardDescription>3 agentes vinculados.</CardDescription>
|
|
62
|
+
</div>
|
|
63
|
+
<CardAction>
|
|
64
|
+
<Button size="sm" variant="outline">Editar</Button>
|
|
65
|
+
</CardAction>
|
|
66
|
+
</CardHeader>
|
|
67
|
+
</Card>
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
## Propriedades de Card
|
|
71
|
+
|
|
72
|
+
| Propriedade | Tipo | Padrão | Descrição |
|
|
73
|
+
|---|---|---|---|
|
|
74
|
+
| `asChild` | `boolean` | `false` | Renderiza o filho com a superfície do Card (ex.: um `<button>` clicável inteiro). |
|
|
75
|
+
| `className` | `string` | | Compõe sobre a superfície; os slots (`CardHeader`, `CardBody`, `CardContent`, `CardFooter`, `CardAction`) são donos do próprio padding. |
|