@softize/opus 8.6.6
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 +1616 -0
- package/LICENSE +21 -0
- package/README.md +113 -0
- package/bin/cli.mjs +528 -0
- package/bin/lib/check.mjs +307 -0
- package/bin/lib/components.mjs +151 -0
- package/bin/lib/create.mjs +208 -0
- package/bin/lib/db-check-runner.mjs +86 -0
- package/bin/lib/db-migrate-runner.mjs +89 -0
- package/bin/lib/db-scaffold-runner.mjs +84 -0
- package/bin/lib/db.mjs +261 -0
- package/bin/lib/docs-include.mjs +48 -0
- package/bin/lib/gen-dicts.mjs +134 -0
- package/bin/lib/gen-docs.mjs +288 -0
- package/bin/lib/gen-manifest.mjs +102 -0
- package/bin/lib/gen-openapi.mjs +195 -0
- package/bin/lib/gen-runner.mjs +472 -0
- package/bin/lib/gen-stubs.mjs +463 -0
- package/bin/lib/gen.mjs +311 -0
- package/bin/lib/init.mjs +514 -0
- package/bin/lib/introspect.mjs +107 -0
- package/bin/lib/mcp.mjs +85 -0
- package/bin/lib/postinstall.mjs +56 -0
- package/docs/chat-event-protocol.md +85 -0
- package/docs/code-style.md +16 -0
- package/docs/data-layer.md +246 -0
- package/docs/ownership-vs-shadcn-lock.md +102 -0
- package/docs/protocol.md +2053 -0
- package/docs/releasing.md +110 -0
- package/docs/shellnav.md +131 -0
- package/package.json +338 -0
- package/registry/hooks/hooks.json +26 -0
- package/registry/hooks/link-memory-on-start.mjs +46 -0
- package/registry/hooks/opus-check-on-stop.mjs +114 -0
- package/registry/skills/create-action/SKILL.md +49 -0
- package/registry/skills/create-action/scaffold.mjs +122 -0
- package/registry/templates/app/_gitignore +3 -0
- package/registry/templates/app/_npmrc +1 -0
- package/registry/templates/app/_opus/_gitignore +5 -0
- package/registry/templates/app/_prettierrc.json +6 -0
- package/registry/templates/app/index.html +13 -0
- package/registry/templates/app/opus.config.ts +16 -0
- package/registry/templates/app/package.json +43 -0
- package/registry/templates/app/pnpm-workspace.yaml +11 -0
- package/registry/templates/app/public/favicon.svg +4 -0
- package/registry/templates/app/src/App.tsx +37 -0
- package/registry/templates/app/src/domains/tasks/actions/list.test.ts +34 -0
- package/registry/templates/app/src/domains/tasks/actions/list.ts +33 -0
- package/registry/templates/app/src/domains/tasks/index.ts +13 -0
- package/registry/templates/app/src/index.css +18 -0
- package/registry/templates/app/src/main.tsx +25 -0
- package/registry/templates/app/tsconfig.json +20 -0
- package/registry/templates/app/vite.config.ts +46 -0
- package/registry/templates/monorepo/_gitignore +3 -0
- package/registry/templates/monorepo/_npmrc +1 -0
- package/registry/templates/monorepo/package.json +9 -0
- package/registry/templates/monorepo/pnpm-workspace.yaml +14 -0
- package/src/ai/ask.ts +64 -0
- package/src/ai/drivers/anthropic.ts +309 -0
- package/src/ai/index.ts +17 -0
- package/src/audit/drivers/console.ts +117 -0
- package/src/audit/drivers/pg.ts +172 -0
- package/src/audit/index.ts +51 -0
- package/src/auth/drivers/better-auth.ts +103 -0
- package/src/auth/drivers/jwt.ts +188 -0
- package/src/auth/index.ts +9 -0
- package/src/client/drivers/fetch.ts +202 -0
- package/src/client/index.ts +22 -0
- package/src/core/actions.ts +110 -0
- package/src/core/audit.ts +239 -0
- package/src/core/contracts.ts +137 -0
- package/src/core/domain.ts +310 -0
- package/src/core/errors.ts +181 -0
- package/src/core/index.ts +174 -0
- package/src/core/logical-type.ts +31 -0
- package/src/core/reactions.ts +81 -0
- package/src/core/runtime.ts +1167 -0
- package/src/core/schedules.ts +41 -0
- package/src/core/types.ts +1356 -0
- package/src/data/drivers/kysely.ts +389 -0
- package/src/data/index.ts +10 -0
- package/src/data/readonly-pool.ts +160 -0
- package/src/dsl/eval.ts +136 -0
- package/src/dsl/index.ts +29 -0
- package/src/dsl/kysely.ts +230 -0
- package/src/dsl/loads.ts +123 -0
- package/src/dsl/parser.ts +423 -0
- package/src/dsl/types.ts +113 -0
- package/src/events/drivers/mitt.ts +70 -0
- package/src/events/index.ts +9 -0
- package/src/log/drivers/pino.ts +57 -0
- package/src/log/index.ts +9 -0
- package/src/mcp/index.ts +62 -0
- package/src/queue/drivers/bullmq.ts +190 -0
- package/src/queue/index.ts +9 -0
- package/src/scheduler/drivers/node-cron.ts +93 -0
- package/src/scheduler/every.ts +45 -0
- package/src/scheduler/index.ts +9 -0
- package/src/schema/drivers/zod.ts +765 -0
- package/src/schema/entity.ts +439 -0
- package/src/schema/format/locale.ts +144 -0
- package/src/schema/index.ts +65 -0
- package/src/schema/openapi.ts +302 -0
- package/src/schema/scaffold.ts +160 -0
- package/src/server/drivers/fastify.ts +224 -0
- package/src/server/drivers/node.ts +386 -0
- package/src/server/index.ts +142 -0
- package/src/storage/drivers/fs.ts +90 -0
- package/src/storage/drivers/s3.ts +117 -0
- package/src/storage/index.ts +27 -0
- package/src/testing/fake.ts +298 -0
- package/src/testing/index.ts +324 -0
- package/src/ui/components/patterns/action-form-card.tsx +48 -0
- package/src/ui/components/patterns/action-list-dialog.tsx +93 -0
- package/src/ui/components/patterns/app-shell.tsx +227 -0
- package/src/ui/components/patterns/confirm.tsx +226 -0
- package/src/ui/components/patterns/data-state.tsx +75 -0
- package/src/ui/components/patterns/form-dialog.tsx +64 -0
- package/src/ui/components/patterns/form.tsx +584 -0
- package/src/ui/components/patterns/list.tsx +1488 -0
- package/src/ui/components/patterns/page.tsx +46 -0
- package/src/ui/components/patterns/section-shell.tsx +246 -0
- package/src/ui/components/patterns/shell-nav.tsx +150 -0
- package/src/ui/components/patterns/sidebar.tsx +89 -0
- package/src/ui/components/patterns/split.tsx +93 -0
- package/src/ui/components/patterns/trigger.tsx +196 -0
- package/src/ui/components/patterns/view.tsx +84 -0
- package/src/ui/components/primitives/accordion.tsx +64 -0
- package/src/ui/components/primitives/alert-dialog.tsx +190 -0
- package/src/ui/components/primitives/alert.tsx +116 -0
- package/src/ui/components/primitives/aspect-ratio.tsx +9 -0
- package/src/ui/components/primitives/avatar.tsx +107 -0
- package/src/ui/components/primitives/badge.tsx +37 -0
- package/src/ui/components/primitives/breadcrumb.tsx +109 -0
- package/src/ui/components/primitives/button-group.tsx +83 -0
- package/src/ui/components/primitives/button.tsx +102 -0
- package/src/ui/components/primitives/calendar.tsx +218 -0
- package/src/ui/components/primitives/card.tsx +56 -0
- package/src/ui/components/primitives/carousel.tsx +239 -0
- package/src/ui/components/primitives/chat.tsx +407 -0
- package/src/ui/components/primitives/checkbox.tsx +30 -0
- package/src/ui/components/primitives/collapsible.tsx +31 -0
- package/src/ui/components/primitives/command.tsx +182 -0
- package/src/ui/components/primitives/composer.tsx +121 -0
- package/src/ui/components/primitives/copyable.tsx +50 -0
- package/src/ui/components/primitives/dialog.tsx +147 -0
- package/src/ui/components/primitives/drawer.tsx +141 -0
- package/src/ui/components/primitives/empty.tsx +104 -0
- package/src/ui/components/primitives/field.tsx +246 -0
- package/src/ui/components/primitives/icon-picker.tsx +180 -0
- package/src/ui/components/primitives/input-group.tsx +168 -0
- package/src/ui/components/primitives/input-otp.tsx +75 -0
- package/src/ui/components/primitives/input.tsx +72 -0
- package/src/ui/components/primitives/item.tsx +193 -0
- package/src/ui/components/primitives/kbd.tsx +28 -0
- package/src/ui/components/primitives/label.tsx +22 -0
- package/src/ui/components/primitives/markdown.tsx +35 -0
- package/src/ui/components/primitives/menu.tsx +255 -0
- package/src/ui/components/primitives/pagination.tsx +127 -0
- package/src/ui/components/primitives/popover.tsx +87 -0
- package/src/ui/components/primitives/progress.tsx +29 -0
- package/src/ui/components/primitives/radio-group.tsx +43 -0
- package/src/ui/components/primitives/resizable.tsx +51 -0
- package/src/ui/components/primitives/scroll-area.tsx +56 -0
- package/src/ui/components/primitives/select.tsx +479 -0
- package/src/ui/components/primitives/separator.tsx +26 -0
- package/src/ui/components/primitives/skeleton.tsx +13 -0
- package/src/ui/components/primitives/slider.tsx +61 -0
- package/src/ui/components/primitives/sonner.tsx +46 -0
- package/src/ui/components/primitives/spinner.tsx +29 -0
- package/src/ui/components/primitives/switch.tsx +33 -0
- package/src/ui/components/primitives/table.tsx +114 -0
- package/src/ui/components/primitives/tabs.tsx +104 -0
- package/src/ui/components/primitives/textarea.tsx +18 -0
- package/src/ui/components/primitives/toggle-group.tsx +81 -0
- package/src/ui/components/primitives/toggle.tsx +45 -0
- package/src/ui/components/primitives/tooltip.tsx +55 -0
- package/src/ui/components/primitives/truncate.tsx +49 -0
- package/src/ui/docs/DocBrowser.tsx +90 -0
- package/src/ui/docs/changelog.tsx +80 -0
- package/src/ui/docs/content/accordion.md +86 -0
- package/src/ui/docs/content/action-form-card.md +24 -0
- package/src/ui/docs/content/action-form-dialog.md +30 -0
- package/src/ui/docs/content/action-form.md +125 -0
- package/src/ui/docs/content/action-list-dialog.md +68 -0
- package/src/ui/docs/content/action-list.md +194 -0
- package/src/ui/docs/content/action-trigger.md +72 -0
- package/src/ui/docs/content/action-view.md +47 -0
- package/src/ui/docs/content/actions.md +138 -0
- package/src/ui/docs/content/ai.md +112 -0
- package/src/ui/docs/content/alert-dialog.md +73 -0
- package/src/ui/docs/content/alert.md +69 -0
- package/src/ui/docs/content/app-shell.md +155 -0
- package/src/ui/docs/content/aspect-ratio.md +66 -0
- package/src/ui/docs/content/audit.md +84 -0
- package/src/ui/docs/content/auth.md +70 -0
- package/src/ui/docs/content/avatar.md +94 -0
- package/src/ui/docs/content/badge.md +48 -0
- package/src/ui/docs/content/breadcrumb.md +87 -0
- package/src/ui/docs/content/button-group.md +71 -0
- package/src/ui/docs/content/button.md +60 -0
- package/src/ui/docs/content/calendar.md +62 -0
- package/src/ui/docs/content/card.md +49 -0
- package/src/ui/docs/content/carousel.md +85 -0
- package/src/ui/docs/content/chat.md +69 -0
- package/src/ui/docs/content/checkbox.md +75 -0
- package/src/ui/docs/content/cli.md +58 -0
- package/src/ui/docs/content/collapsible.md +64 -0
- package/src/ui/docs/content/command.md +56 -0
- package/src/ui/docs/content/composer.md +50 -0
- package/src/ui/docs/content/confirm.md +120 -0
- package/src/ui/docs/content/copyable.md +30 -0
- package/src/ui/docs/content/customization.md +110 -0
- package/src/ui/docs/content/cycle.md +34 -0
- package/src/ui/docs/content/data-state.md +47 -0
- package/src/ui/docs/content/data.md +99 -0
- package/src/ui/docs/content/dialog.md +60 -0
- package/src/ui/docs/content/drawer.md +55 -0
- package/src/ui/docs/content/empty.md +66 -0
- package/src/ui/docs/content/events.md +61 -0
- package/src/ui/docs/content/field.md +58 -0
- package/src/ui/docs/content/getting-started.md +109 -0
- package/src/ui/docs/content/icon-picker.md +51 -0
- package/src/ui/docs/content/input-group.md +78 -0
- package/src/ui/docs/content/input-otp.md +72 -0
- package/src/ui/docs/content/input.md +78 -0
- package/src/ui/docs/content/item.md +84 -0
- package/src/ui/docs/content/kbd.md +62 -0
- package/src/ui/docs/content/label.md +32 -0
- package/src/ui/docs/content/log.md +55 -0
- package/src/ui/docs/content/markdown.md +41 -0
- package/src/ui/docs/content/mcp.md +44 -0
- package/src/ui/docs/content/menu.md +114 -0
- package/src/ui/docs/content/microcopy.md +83 -0
- package/src/ui/docs/content/page.md +34 -0
- package/src/ui/docs/content/pagination.md +99 -0
- package/src/ui/docs/content/popover.md +49 -0
- package/src/ui/docs/content/progress.md +69 -0
- package/src/ui/docs/content/queue.md +62 -0
- package/src/ui/docs/content/radio-group.md +77 -0
- package/src/ui/docs/content/resizable.md +86 -0
- package/src/ui/docs/content/router.md +56 -0
- package/src/ui/docs/content/runtime.md +77 -0
- package/src/ui/docs/content/scheduler.md +66 -0
- package/src/ui/docs/content/scroll-area.md +89 -0
- package/src/ui/docs/content/section-shell.md +121 -0
- package/src/ui/docs/content/select.md +342 -0
- package/src/ui/docs/content/separator.md +33 -0
- package/src/ui/docs/content/sidebar.md +38 -0
- package/src/ui/docs/content/skeleton.md +34 -0
- package/src/ui/docs/content/slider.md +64 -0
- package/src/ui/docs/content/spinner.md +37 -0
- package/src/ui/docs/content/split.md +33 -0
- package/src/ui/docs/content/storage.md +69 -0
- package/src/ui/docs/content/switch.md +69 -0
- package/src/ui/docs/content/table.md +102 -0
- package/src/ui/docs/content/tabs.md +94 -0
- package/src/ui/docs/content/testing.md +89 -0
- package/src/ui/docs/content/textarea.md +30 -0
- package/src/ui/docs/content/toast.md +67 -0
- package/src/ui/docs/content/toggle-group.md +81 -0
- package/src/ui/docs/content/toggle.md +72 -0
- package/src/ui/docs/content/tokens.md +171 -0
- package/src/ui/docs/content/tooltip.md +50 -0
- package/src/ui/docs/content/truncate.md +37 -0
- package/src/ui/docs/content/ui.md +40 -0
- package/src/ui/docs/content/upgrading.md +48 -0
- package/src/ui/docs/doc-client.tsx +214 -0
- package/src/ui/docs/doc.tsx +301 -0
- package/src/ui/docs/folder.tsx +149 -0
- package/src/ui/docs/index.ts +21 -0
- package/src/ui/docs/markdown.tsx +130 -0
- package/src/ui/docs/md-raw.d.ts +4 -0
- package/src/ui/docs/plugin.ts +104 -0
- package/src/ui/docs/registry.tsx +424 -0
- package/src/ui/docs/standalone.tsx +107 -0
- package/src/ui/drivers/react.tsx +627 -0
- package/src/ui/index.ts +92 -0
- package/src/ui/lib/cn.ts +10 -0
- package/src/ui/lib/zod-pt-br.ts +38 -0
- package/src/ui/meta.ts +412 -0
- package/src/ui/react.tsx +235 -0
- package/src/ui/router.ts +96 -0
- package/src/ui/theme.css +234 -0
- package/src/vite/design.ts +652 -0
- package/src/vite/index.ts +8 -0
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
## Básico
|
|
2
|
+
|
|
3
|
+
Sempre em par com Label (htmlFor↔id) — clicar no texto alterna a chave. defaultChecked pro modo não controlado.
|
|
4
|
+
|
|
5
|
+
```tsx preview
|
|
6
|
+
<div className="flex items-center gap-2">
|
|
7
|
+
<Switch id="boot-preview" defaultChecked />
|
|
8
|
+
<Label htmlFor="boot-preview">Subir o preview ao abrir a sessão</Label>
|
|
9
|
+
</div>
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
## Controlado
|
|
13
|
+
|
|
14
|
+
onCheckedChange recebe um boolean — pareie com checked pra guardar o estado no componente que decide.
|
|
15
|
+
|
|
16
|
+
```tsx preview
|
|
17
|
+
const [autoReview, setAutoReview] = useState(true)
|
|
18
|
+
|
|
19
|
+
render(
|
|
20
|
+
<div className="flex items-center gap-2">
|
|
21
|
+
<Switch
|
|
22
|
+
id="auto-review"
|
|
23
|
+
checked={autoReview}
|
|
24
|
+
onCheckedChange={setAutoReview}
|
|
25
|
+
/>
|
|
26
|
+
<Label htmlFor="auto-review">Acionar o revisor ao abrir o handoff</Label>
|
|
27
|
+
</div>,
|
|
28
|
+
)
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## Tamanho sm
|
|
32
|
+
|
|
33
|
+
size=sm encolhe a chave — pra densidade em linha de lista, como cada repositório do workspace.
|
|
34
|
+
|
|
35
|
+
```tsx preview col-start
|
|
36
|
+
<div className="flex items-center gap-2">
|
|
37
|
+
<Switch id="sync-empresa-x-api" size="sm" defaultChecked />
|
|
38
|
+
<Label htmlFor="sync-empresa-x-api">empresa-x-api</Label>
|
|
39
|
+
</div>
|
|
40
|
+
<div className="flex items-center gap-2">
|
|
41
|
+
<Switch id="sync-empresa-x-web" size="sm" />
|
|
42
|
+
<Label htmlFor="sync-empresa-x-web">empresa-x-web</Label>
|
|
43
|
+
</div>
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## Desabilitado
|
|
47
|
+
|
|
48
|
+
disabled esmaece e bloqueia a chave — ligada ou desligada — e o rótulo em par esmaece junto (peer-disabled).
|
|
49
|
+
|
|
50
|
+
```tsx preview col-start
|
|
51
|
+
<div className="flex items-center gap-2">
|
|
52
|
+
<Switch id="sync-multica" disabled />
|
|
53
|
+
<Label htmlFor="sync-multica">Sincronizar com o Multica</Label>
|
|
54
|
+
</div>
|
|
55
|
+
<div className="flex items-center gap-2">
|
|
56
|
+
<Switch id="opus" disabled defaultChecked />
|
|
57
|
+
<Label htmlFor="opus">Opus inicializado</Label>
|
|
58
|
+
</div>
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
## Props
|
|
62
|
+
|
|
63
|
+
| Prop | Tipo | Default | Descrição |
|
|
64
|
+
|---|---|---|---|
|
|
65
|
+
| `checked` | `boolean` | | O estado, no modo controlado — parear com onCheckedChange. |
|
|
66
|
+
| `onCheckedChange` | `(checked: boolean) => void` | | Chamado a cada alternância, com o novo estado. |
|
|
67
|
+
| `defaultChecked` | `boolean` | `false` | Estado inicial no modo não controlado. |
|
|
68
|
+
| `size` | `'sm' \| 'default'` | `'default'` | Tamanho da chave — sm pra densidade em linha de lista. |
|
|
69
|
+
| `disabled` | `boolean` | `false` | Esmaece e bloqueia — o Label em par esmaece junto (peer-disabled). |
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
## Tabela de domínio
|
|
2
|
+
|
|
3
|
+
A Table vem SEM borda externa — só as divisórias de linha (a última o TableBody zera). Coluna numérica alinha à direita (text-right no TableHead E no TableCell). A TableCaption fica embaixo (caption-bottom) e descreve a tabela.
|
|
4
|
+
|
|
5
|
+
```tsx preview col
|
|
6
|
+
<Table>
|
|
7
|
+
<TableCaption>Sessões recentes do workspace Empresa X.</TableCaption>
|
|
8
|
+
<TableHeader>
|
|
9
|
+
<TableRow>
|
|
10
|
+
<TableHead>Sessão</TableHead>
|
|
11
|
+
<TableHead>Agente</TableHead>
|
|
12
|
+
<TableHead>Status</TableHead>
|
|
13
|
+
<TableHead className="text-right">Duração</TableHead>
|
|
14
|
+
</TableRow>
|
|
15
|
+
</TableHeader>
|
|
16
|
+
<TableBody>
|
|
17
|
+
<TableRow>
|
|
18
|
+
<TableCell className="font-medium">Importar pedidos da transportadora</TableCell>
|
|
19
|
+
<TableCell>developer</TableCell>
|
|
20
|
+
<TableCell><Badge variant="info">Em sessão</Badge></TableCell>
|
|
21
|
+
<TableCell className="text-right">42 min</TableCell>
|
|
22
|
+
</TableRow>
|
|
23
|
+
<TableRow>
|
|
24
|
+
<TableCell className="font-medium">Revisar contrato de rastreio</TableCell>
|
|
25
|
+
<TableCell>reviewer</TableCell>
|
|
26
|
+
<TableCell><Badge variant="warning">Aguardando revisor</Badge></TableCell>
|
|
27
|
+
<TableCell className="text-right">18 min</TableCell>
|
|
28
|
+
</TableRow>
|
|
29
|
+
<TableRow>
|
|
30
|
+
<TableCell className="font-medium">Ajustar microcopy do painel</TableCell>
|
|
31
|
+
<TableCell>designer</TableCell>
|
|
32
|
+
<TableCell><Badge variant="success">Concluída</Badge></TableCell>
|
|
33
|
+
<TableCell className="text-right">7 min</TableCell>
|
|
34
|
+
</TableRow>
|
|
35
|
+
</TableBody>
|
|
36
|
+
</Table>
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## Moldura (o datagrid da casa)
|
|
40
|
+
|
|
41
|
+
A borda externa NÃO é do componente: é um wrapper `overflow-hidden rounded-lg border border-border` por fora — o estilo padrão de datagrid do back-office. O `overflow-hidden` recorta os cantos e contém o scroll horizontal; a última linha já vem sem divisória, então o quadro fecha limpo. O ActionList aplica a moldura sozinho na tabela derivada; em tabela montada à mão, é você quem embrulha.
|
|
42
|
+
|
|
43
|
+
```tsx preview col
|
|
44
|
+
<div className="w-full overflow-hidden rounded-lg border border-border">
|
|
45
|
+
<Table>
|
|
46
|
+
<TableHeader>
|
|
47
|
+
<TableRow>
|
|
48
|
+
<TableHead>Sessão</TableHead>
|
|
49
|
+
<TableHead>Agente</TableHead>
|
|
50
|
+
<TableHead className="text-right">Duração</TableHead>
|
|
51
|
+
</TableRow>
|
|
52
|
+
</TableHeader>
|
|
53
|
+
<TableBody>
|
|
54
|
+
<TableRow>
|
|
55
|
+
<TableCell className="font-medium">Importar pedidos da transportadora</TableCell>
|
|
56
|
+
<TableCell>developer</TableCell>
|
|
57
|
+
<TableCell className="text-right">42 min</TableCell>
|
|
58
|
+
</TableRow>
|
|
59
|
+
<TableRow>
|
|
60
|
+
<TableCell className="font-medium">Revisar contrato de rastreio</TableCell>
|
|
61
|
+
<TableCell>reviewer</TableCell>
|
|
62
|
+
<TableCell className="text-right">18 min</TableCell>
|
|
63
|
+
</TableRow>
|
|
64
|
+
</TableBody>
|
|
65
|
+
</Table>
|
|
66
|
+
</div>
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
## Com rodapé (TableFooter)
|
|
70
|
+
|
|
71
|
+
TableFooter fecha a tabela com a linha de agregação — fundo muted e peso de fonte já vêm prontos.
|
|
72
|
+
|
|
73
|
+
```tsx preview col
|
|
74
|
+
<Table>
|
|
75
|
+
<TableHeader>
|
|
76
|
+
<TableRow>
|
|
77
|
+
<TableHead>Agente</TableHead>
|
|
78
|
+
<TableHead className="text-right">Skills vinculadas</TableHead>
|
|
79
|
+
</TableRow>
|
|
80
|
+
</TableHeader>
|
|
81
|
+
<TableBody>
|
|
82
|
+
<TableRow>
|
|
83
|
+
<TableCell className="font-medium">developer</TableCell>
|
|
84
|
+
<TableCell className="text-right">6</TableCell>
|
|
85
|
+
</TableRow>
|
|
86
|
+
<TableRow>
|
|
87
|
+
<TableCell className="font-medium">reviewer</TableCell>
|
|
88
|
+
<TableCell className="text-right">4</TableCell>
|
|
89
|
+
</TableRow>
|
|
90
|
+
<TableRow>
|
|
91
|
+
<TableCell className="font-medium">designer</TableCell>
|
|
92
|
+
<TableCell className="text-right">3</TableCell>
|
|
93
|
+
</TableRow>
|
|
94
|
+
</TableBody>
|
|
95
|
+
<TableFooter>
|
|
96
|
+
<TableRow>
|
|
97
|
+
<TableCell>Total</TableCell>
|
|
98
|
+
<TableCell className="text-right">13</TableCell>
|
|
99
|
+
</TableRow>
|
|
100
|
+
</TableFooter>
|
|
101
|
+
</Table>
|
|
102
|
+
```
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
## Padrão (pill)
|
|
2
|
+
|
|
3
|
+
O value do TabsTrigger pareia com o do TabsContent. defaultValue deixa o estado com o componente; pra controlar, use value + onValueChange.
|
|
4
|
+
|
|
5
|
+
```tsx preview col
|
|
6
|
+
<Tabs defaultValue="sessions">
|
|
7
|
+
<TabsList>
|
|
8
|
+
<TabsTrigger value="overview">Visão geral</TabsTrigger>
|
|
9
|
+
<TabsTrigger value="sessions">Sessões</TabsTrigger>
|
|
10
|
+
<TabsTrigger value="skills">Skills</TabsTrigger>
|
|
11
|
+
</TabsList>
|
|
12
|
+
<TabsContent value="overview">
|
|
13
|
+
<p className="text-sm text-muted-foreground">Resumo do workspace Empresa X.</p>
|
|
14
|
+
</TabsContent>
|
|
15
|
+
<TabsContent value="sessions">
|
|
16
|
+
<p className="text-sm text-muted-foreground">3 sessões nesta semana, 1 em andamento.</p>
|
|
17
|
+
</TabsContent>
|
|
18
|
+
<TabsContent value="skills">
|
|
19
|
+
<p className="text-sm text-muted-foreground">6 skills vinculadas aos agentes do workspace.</p>
|
|
20
|
+
</TabsContent>
|
|
21
|
+
</Tabs>
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## Variante line
|
|
25
|
+
|
|
26
|
+
variant=line na TabsList: fundo transparente, o ativo é marcado pelo traço embaixo — bom pra cabeçalho de página, onde o pill pesaria.
|
|
27
|
+
|
|
28
|
+
```tsx preview col
|
|
29
|
+
<Tabs defaultValue="agents">
|
|
30
|
+
<TabsList variant="line">
|
|
31
|
+
<TabsTrigger value="agents">Agentes</TabsTrigger>
|
|
32
|
+
<TabsTrigger value="repos">Repositórios</TabsTrigger>
|
|
33
|
+
<TabsTrigger value="settings">Configurações</TabsTrigger>
|
|
34
|
+
</TabsList>
|
|
35
|
+
<TabsContent value="agents">
|
|
36
|
+
<p className="text-sm text-muted-foreground">developer, reviewer e designer ativos.</p>
|
|
37
|
+
</TabsContent>
|
|
38
|
+
<TabsContent value="repos">
|
|
39
|
+
<p className="text-sm text-muted-foreground">empresa-x-api e empresa-x-web vinculados.</p>
|
|
40
|
+
</TabsContent>
|
|
41
|
+
<TabsContent value="settings">
|
|
42
|
+
<p className="text-sm text-muted-foreground">Preferências do workspace.</p>
|
|
43
|
+
</TabsContent>
|
|
44
|
+
</Tabs>
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## Vertical
|
|
48
|
+
|
|
49
|
+
orientation=vertical no Tabs: a lista vira coluna e o traço da variante line migra pra lateral direita do trigger.
|
|
50
|
+
|
|
51
|
+
```tsx preview col
|
|
52
|
+
<Tabs defaultValue="prompt" orientation="vertical">
|
|
53
|
+
<TabsList>
|
|
54
|
+
<TabsTrigger value="prompt">Prompt</TabsTrigger>
|
|
55
|
+
<TabsTrigger value="skills">Skills</TabsTrigger>
|
|
56
|
+
<TabsTrigger value="history">Histórico</TabsTrigger>
|
|
57
|
+
</TabsList>
|
|
58
|
+
<TabsContent value="prompt">
|
|
59
|
+
<p className="text-sm text-muted-foreground">O prompt do agente developer.</p>
|
|
60
|
+
</TabsContent>
|
|
61
|
+
<TabsContent value="skills">
|
|
62
|
+
<p className="text-sm text-muted-foreground">Skills vinculadas a este agente.</p>
|
|
63
|
+
</TabsContent>
|
|
64
|
+
<TabsContent value="history">
|
|
65
|
+
<p className="text-sm text-muted-foreground">Sessões anteriores deste agente.</p>
|
|
66
|
+
</TabsContent>
|
|
67
|
+
</Tabs>
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
## Densidade (size)
|
|
71
|
+
|
|
72
|
+
`size="sm"` no `Tabs` baixa a lista de h-9 (36px) pra h-8 (32px) — o par do `sm` que Button e Select já têm, pra uma fileira densa (toolbar, header) onde o segmento não pode ficar mais alto que os irmãos.
|
|
73
|
+
|
|
74
|
+
```tsx preview col
|
|
75
|
+
<Tabs defaultValue="preview" size="sm">
|
|
76
|
+
<TabsList>
|
|
77
|
+
<TabsTrigger value="preview" className="text-xs">Preview</TabsTrigger>
|
|
78
|
+
<TabsTrigger value="code" className="text-xs">Código</TabsTrigger>
|
|
79
|
+
<TabsTrigger value="ai" className="text-xs">IA</TabsTrigger>
|
|
80
|
+
</TabsList>
|
|
81
|
+
</Tabs>
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
## Props
|
|
85
|
+
|
|
86
|
+
| Prop | Tipo | Default | Descrição |
|
|
87
|
+
|---|---|---|---|
|
|
88
|
+
| `defaultValue (Tabs)` | `string` | | A aba inicial no modo não-controlado. |
|
|
89
|
+
| `value (Tabs)` | `string` | | A aba ativa no modo controlado — pareie com onValueChange. |
|
|
90
|
+
| `onValueChange (Tabs)` | `(value: string) => void` | | Chamado quando o usuário troca de aba. |
|
|
91
|
+
| `size (Tabs)` | `'default' \| 'sm'` | `'default'` | Altura da lista: default (h-9) ou sm (h-8), o par do sm de Button/Select. Flui pra TabsList por contexto. |
|
|
92
|
+
| `orientation (Tabs)` | `'horizontal' \| 'vertical'` | `'horizontal'` | Direção da lista de abas — vertical vira coluna lateral. |
|
|
93
|
+
| `variant (TabsList)` | `'default' \| 'line'` | `'default'` | default é o pill (fundo muted); line é a barra sublinhada, sem fundo. |
|
|
94
|
+
| `value (TabsTrigger/TabsContent)` | `string` | | Identificador que pareia o trigger com o painel correspondente. |
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Testes de action
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# Testes de action
|
|
6
|
+
|
|
7
|
+
A unidade natural de teste no Opus é a **action** — o contrato: input → output/erro,
|
|
8
|
+
bordas do schema, autorização fail-closed. `@softize/opus/testing` roda esse contrato
|
|
9
|
+
em unidade, sem montar runtime nem mockar contexto à mão.
|
|
10
|
+
|
|
11
|
+
## runAction — o contrato em unidade
|
|
12
|
+
|
|
13
|
+
O harness executa o **mesmo pipeline do runtime**: valida o input → cobra o gate
|
|
14
|
+
`public` → avalia o `authorize` (string DSL ou closure, semântica idêntica) → roda o
|
|
15
|
+
handler → valida o output. Falha estoura o mesmo `ActionError` tipado do runtime
|
|
16
|
+
(`validation.invalid_input`, `auth.unauthenticated`, `auth.forbidden`…).
|
|
17
|
+
|
|
18
|
+
```ts
|
|
19
|
+
import { runAction } from '@softize/opus/testing'
|
|
20
|
+
import { taskList } from './list.ts'
|
|
21
|
+
|
|
22
|
+
it('lista as fixtures com o shape do contrato', async () => {
|
|
23
|
+
const { output } = await runAction(taskList, {}, { user: { id: 'u1' } })
|
|
24
|
+
expect(output.total).toBe(2)
|
|
25
|
+
})
|
|
26
|
+
|
|
27
|
+
it('sem usuário, barra: a action não é pública', async () => {
|
|
28
|
+
await expect(runAction(taskList, {})).rejects.toMatchObject({ code: 'auth.unauthenticated' })
|
|
29
|
+
})
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
O terceiro argumento configura o contexto e substitui os loaders (que não rodam em
|
|
33
|
+
unidade): `{ user, tenantId, can, db, storage, ai, loaded, meta }`. O `authorize` vê
|
|
34
|
+
o `loaded` como no runtime:
|
|
35
|
+
|
|
36
|
+
```ts
|
|
37
|
+
it('só a dona edita', async () => {
|
|
38
|
+
const opts = { loaded: { task: { ownerId: 'u1' } } }
|
|
39
|
+
await runAction(taskUpdate, { id: '1' }, { ...opts, user: { id: 'u1' } }) // passa
|
|
40
|
+
await expect(
|
|
41
|
+
runAction(taskUpdate, { id: '1' }, { ...opts, user: { id: 'u2' } }),
|
|
42
|
+
).rejects.toMatchObject({ code: 'auth.forbidden' })
|
|
43
|
+
})
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## Contexto observável
|
|
47
|
+
|
|
48
|
+
`runAction` (e `testContext`, pra quem quer só o ctx) devolve os efeitos capturados —
|
|
49
|
+
o teste afirma o que importa:
|
|
50
|
+
|
|
51
|
+
```ts
|
|
52
|
+
const { output, emitted, logged } = await runAction(taskDone, { id: '1' }, { user })
|
|
53
|
+
expect(emitted).toEqual([{ event: 'task.done', data: { id: '1' } }])
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## memStorage
|
|
57
|
+
|
|
58
|
+
`StorageAdapter` em memória com a mesma régua de key dos drivers reais — pra handler
|
|
59
|
+
que anexa arquivo:
|
|
60
|
+
|
|
61
|
+
```ts
|
|
62
|
+
import { memStorage, runAction } from '@softize/opus/testing'
|
|
63
|
+
|
|
64
|
+
const storage = memStorage()
|
|
65
|
+
await runAction(notaAnexar, { id: '9' }, { user, storage })
|
|
66
|
+
expect(storage.keys()).toEqual(['notas/9.pdf'])
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
## fake — fixtures do schema
|
|
70
|
+
|
|
71
|
+
`fake(schema)` / `fakeMany(schema, n)` geram dado sintético **determinístico** que satisfaz o
|
|
72
|
+
schema zod — matéria-prima do `mockHandler` (modo design) e de fixtures de teste. Semeado
|
|
73
|
+
(mesma `seed` → mesma saída, sem `Math.random`), com heurística por check do zod (email, uuid,
|
|
74
|
+
url, datetime) e por nome de campo (email, id, `*At`→data, telefone, cpf/cnpj, nome…), sabor pt-BR.
|
|
75
|
+
|
|
76
|
+
```ts
|
|
77
|
+
import { fake, fakeMany } from '@softize/opus/testing'
|
|
78
|
+
|
|
79
|
+
const one = fake(EventEntity.zod()) // 1 evento válido (safeParse passa)
|
|
80
|
+
const many = fakeMany(EventEntity.zod(), 20) // 20, estáveis entre execuções
|
|
81
|
+
fake(schema, { seed: 7 }) // seed própria
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
## O que fica de fora
|
|
85
|
+
|
|
86
|
+
De propósito — é harness de **unidade**: loaders reais (passe `loaded` pronto), audit,
|
|
87
|
+
reactions em cadeia e o servidor. Fluxo completo é teste de integração com o runtime.
|
|
88
|
+
`requires` é declarativo no protocolo (o runtime não o executa) — no harness idem;
|
|
89
|
+
handler que chama `ctx.can` responde ao `can` das options.
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
## Básico
|
|
2
|
+
|
|
3
|
+
Cresce com o conteúdo a partir da altura mínima (field-sizing-content) — digite e veja.
|
|
4
|
+
|
|
5
|
+
```tsx preview col md
|
|
6
|
+
<Textarea placeholder="Descreva o que o agente deve fazer nesta sessão." />
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
## Com Label
|
|
10
|
+
|
|
11
|
+
O mesmo par htmlFor↔id dos outros campos — o overview do handoff é o caso típico.
|
|
12
|
+
|
|
13
|
+
```tsx preview col md
|
|
14
|
+
<div className="grid gap-2">
|
|
15
|
+
<Label htmlFor="overview">Overview da task</Label>
|
|
16
|
+
<Textarea
|
|
17
|
+
id="overview"
|
|
18
|
+
defaultValue="Ajustar a microcopy do handoff: frases com maiúscula e ponto, labels curtos sem ponto."
|
|
19
|
+
/>
|
|
20
|
+
</div>
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Estados
|
|
24
|
+
|
|
25
|
+
aria-invalid pinta borda e anel destructive; disabled esmaece e bloqueia a edição.
|
|
26
|
+
|
|
27
|
+
```tsx preview col md
|
|
28
|
+
<Textarea aria-invalid placeholder="Conte o contexto da mudança." />
|
|
29
|
+
<Textarea disabled defaultValue="Sessão encerrada — o brief não pode mais ser editado." />
|
|
30
|
+
```
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
## Tipos
|
|
2
|
+
|
|
3
|
+
Cada tipo já vem com o ícone lucide do Opus. O título é label (sem ponto); a description, frase (com ponto).
|
|
4
|
+
|
|
5
|
+
```tsx preview
|
|
6
|
+
<Button variant="outline" onClick={() => toast.success('Workspace criado')}>Sucesso</Button>
|
|
7
|
+
<Button
|
|
8
|
+
variant="outline"
|
|
9
|
+
onClick={() => toast.error('Falha no push', { description: 'O Multica não respondeu — tente de novo.' })}
|
|
10
|
+
>
|
|
11
|
+
Erro
|
|
12
|
+
</Button>
|
|
13
|
+
<Button variant="outline" onClick={() => toast.info('Base atualizada')}>Info</Button>
|
|
14
|
+
<Button
|
|
15
|
+
variant="outline"
|
|
16
|
+
onClick={() => toast.warning('Preview parado', { description: 'Inicie o ambiente pra ver a sessão.' })}
|
|
17
|
+
>
|
|
18
|
+
Aviso
|
|
19
|
+
</Button>
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## Ação e progresso
|
|
23
|
+
|
|
24
|
+
action põe um botão no toast (ex.: desfazer); toast.promise acompanha uma operação — loading vira sucesso ou erro sozinho.
|
|
25
|
+
|
|
26
|
+
```tsx preview
|
|
27
|
+
<Button
|
|
28
|
+
variant="outline"
|
|
29
|
+
onClick={() =>
|
|
30
|
+
toast('Sessão arquivada', {
|
|
31
|
+
action: { label: 'Desfazer', onClick: () => toast.success('Sessão restaurada') },
|
|
32
|
+
})
|
|
33
|
+
}
|
|
34
|
+
>
|
|
35
|
+
Com ação
|
|
36
|
+
</Button>
|
|
37
|
+
<Button
|
|
38
|
+
variant="outline"
|
|
39
|
+
onClick={() =>
|
|
40
|
+
toast.promise(new Promise((resolve) => setTimeout(resolve, 1800)), {
|
|
41
|
+
loading: 'Publicando no Multica…',
|
|
42
|
+
success: 'Agentes publicados',
|
|
43
|
+
error: 'Falha ao publicar',
|
|
44
|
+
})
|
|
45
|
+
}
|
|
46
|
+
>
|
|
47
|
+
Promise
|
|
48
|
+
</Button>
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## Toaster no root
|
|
52
|
+
|
|
53
|
+
Monte uma vez, fora do App. Divergência declarada: sem next-themes — o tema vem por prop (default 'system'); a elevação dark usa bg-popover.
|
|
54
|
+
|
|
55
|
+
```tsx
|
|
56
|
+
/* main.tsx do app — uma vez. */
|
|
57
|
+
<App />
|
|
58
|
+
<Toaster />
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
## Props
|
|
62
|
+
|
|
63
|
+
| Prop | Tipo | Default | Descrição |
|
|
64
|
+
|---|---|---|---|
|
|
65
|
+
| `Toaster.theme` | `'light' \| 'dark' \| 'system'` | `'system'` | Força o tema dos toasts — sem next-themes, a escolha é do app. |
|
|
66
|
+
| `Toaster.position` | `'bottom-right' \| 'top-center' \| …` | `'bottom-right'` | Canto onde os toasts aparecem (sonner). |
|
|
67
|
+
| `toast(title, opts)` | `{ description?, action?, duration?, … }` | | A API de disparo (sonner): descrição, botão de ação e duração por toast. |
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
## Escolha única
|
|
2
|
+
|
|
3
|
+
type=single deixa um item ativo por vez; value é uma string. Controlado por value + onValueChange — bom pra alternar a visão de um workspace.
|
|
4
|
+
|
|
5
|
+
```tsx preview
|
|
6
|
+
const [view, setView] = useState('sessions')
|
|
7
|
+
|
|
8
|
+
render(
|
|
9
|
+
<ToggleGroup type="single" value={view} onValueChange={(v) => v && setView(v)}>
|
|
10
|
+
<ToggleGroupItem value="overview">Visão geral</ToggleGroupItem>
|
|
11
|
+
<ToggleGroupItem value="sessions">Sessões</ToggleGroupItem>
|
|
12
|
+
<ToggleGroupItem value="skills">Skills</ToggleGroupItem>
|
|
13
|
+
</ToggleGroup>,
|
|
14
|
+
)
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Escolha múltipla
|
|
18
|
+
|
|
19
|
+
type=multiple permite vários ativos ao mesmo tempo; value é um array de strings. O padrão pra uma barra de formatação.
|
|
20
|
+
|
|
21
|
+
```tsx preview
|
|
22
|
+
const [marks, setMarks] = useState(['bold'])
|
|
23
|
+
|
|
24
|
+
render(
|
|
25
|
+
<ToggleGroup type="multiple" value={marks} onValueChange={setMarks}>
|
|
26
|
+
<ToggleGroupItem value="bold" aria-label="Negrito">
|
|
27
|
+
<Bold />
|
|
28
|
+
</ToggleGroupItem>
|
|
29
|
+
<ToggleGroupItem value="italic" aria-label="Itálico">
|
|
30
|
+
<Italic />
|
|
31
|
+
</ToggleGroupItem>
|
|
32
|
+
<ToggleGroupItem value="underline" aria-label="Sublinhado">
|
|
33
|
+
<Underline />
|
|
34
|
+
</ToggleGroupItem>
|
|
35
|
+
</ToggleGroup>,
|
|
36
|
+
)
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## Variante outline
|
|
40
|
+
|
|
41
|
+
variant=outline emoldura o grupo com borda; size e o variant definidos no ToggleGroup descem pra cada ToggleGroupItem via contexto.
|
|
42
|
+
|
|
43
|
+
```tsx preview
|
|
44
|
+
<ToggleGroup type="single" variant="outline" defaultValue="left" aria-label="Alinhamento">
|
|
45
|
+
<ToggleGroupItem value="left" aria-label="Esquerda">
|
|
46
|
+
<AlignLeft />
|
|
47
|
+
</ToggleGroupItem>
|
|
48
|
+
<ToggleGroupItem value="center" aria-label="Centro">
|
|
49
|
+
<AlignCenter />
|
|
50
|
+
</ToggleGroupItem>
|
|
51
|
+
<ToggleGroupItem value="right" aria-label="Direita">
|
|
52
|
+
<AlignRight />
|
|
53
|
+
</ToggleGroupItem>
|
|
54
|
+
</ToggleGroup>
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## Com espaçamento
|
|
58
|
+
|
|
59
|
+
spacing afasta os itens (em unidades de spacing do tema) — sem ele os botões ficam colados num bloco único.
|
|
60
|
+
|
|
61
|
+
```tsx preview
|
|
62
|
+
<ToggleGroup type="single" variant="outline" spacing={2} defaultValue="developer">
|
|
63
|
+
<ToggleGroupItem value="developer">developer</ToggleGroupItem>
|
|
64
|
+
<ToggleGroupItem value="reviewer">reviewer</ToggleGroupItem>
|
|
65
|
+
<ToggleGroupItem value="designer">designer</ToggleGroupItem>
|
|
66
|
+
</ToggleGroup>
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
## Props
|
|
70
|
+
|
|
71
|
+
| Prop | Tipo | Default | Descrição |
|
|
72
|
+
|---|---|---|---|
|
|
73
|
+
| `type (ToggleGroup)` | `'single' \| 'multiple'` | | single mantém um item ativo (value: string); multiple permite vários (value: string[]). |
|
|
74
|
+
| `value (ToggleGroup)` | `string \| string[]` | | O(s) item(ns) ativo(s) no modo controlado — pareie com onValueChange. O tipo segue o type. |
|
|
75
|
+
| `onValueChange (ToggleGroup)` | `(value: string \| string[]) => void` | | Chamado quando a seleção muda. No single, vem string vazia ao desmarcar o ativo. |
|
|
76
|
+
| `defaultValue (ToggleGroup)` | `string \| string[]` | | A seleção inicial no modo não controlado. |
|
|
77
|
+
| `variant (ToggleGroup)` | `'default' \| 'outline'` | `'default'` | default é sem moldura; outline emoldura o grupo com borda. Desce pros itens via contexto. |
|
|
78
|
+
| `size (ToggleGroup)` | `'default' \| 'sm' \| 'lg'` | `'default'` | Altura e respiro dos itens. Desce pros itens via contexto. |
|
|
79
|
+
| `spacing (ToggleGroup)` | `number` | `0` | Distância entre os itens (unidades de spacing). 0 cola tudo num bloco único. |
|
|
80
|
+
| `value (ToggleGroupItem)` | `string` | | Identificador do item — é o que entra no value do grupo quando ativado. |
|
|
81
|
+
| `disabled (ToggleGroupItem)` | `boolean` | `false` | Esmaece e bloqueia um item específico do grupo. |
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
## Básico
|
|
2
|
+
|
|
3
|
+
Um botão que lembra se está ligado. defaultPressed deixa o estado com o componente; o filho costuma ser um ícone.
|
|
4
|
+
|
|
5
|
+
```tsx preview
|
|
6
|
+
<Toggle defaultPressed aria-label="Negrito">
|
|
7
|
+
<Bold />
|
|
8
|
+
</Toggle>
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Controlado
|
|
12
|
+
|
|
13
|
+
pressed + onPressedChange tiram o estado do componente — o booleano fica no seu store. Bom pra alternar o modo somente-leitura de uma sessão.
|
|
14
|
+
|
|
15
|
+
```tsx preview
|
|
16
|
+
const [readOnly, setReadOnly] = useState(true)
|
|
17
|
+
|
|
18
|
+
render(
|
|
19
|
+
<Toggle
|
|
20
|
+
variant="outline"
|
|
21
|
+
pressed={readOnly}
|
|
22
|
+
onPressedChange={setReadOnly}
|
|
23
|
+
>
|
|
24
|
+
<Eye />
|
|
25
|
+
Somente leitura
|
|
26
|
+
</Toggle>,
|
|
27
|
+
)
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## Variantes e tamanhos
|
|
31
|
+
|
|
32
|
+
variant default não tem borda (o fundo só aparece ativo); outline carrega a borda. size sm/default/lg ajusta a altura.
|
|
33
|
+
|
|
34
|
+
```tsx preview
|
|
35
|
+
<Toggle aria-label="Quebra de linha">
|
|
36
|
+
<WrapText />
|
|
37
|
+
</Toggle>
|
|
38
|
+
<Toggle variant="outline" aria-label="Quebra de linha">
|
|
39
|
+
<WrapText />
|
|
40
|
+
</Toggle>
|
|
41
|
+
<Toggle variant="outline" size="sm" defaultPressed>
|
|
42
|
+
Compacto
|
|
43
|
+
</Toggle>
|
|
44
|
+
<Toggle variant="outline" size="lg" defaultPressed>
|
|
45
|
+
Confortável
|
|
46
|
+
</Toggle>
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## Desabilitado
|
|
50
|
+
|
|
51
|
+
disabled esmaece e bloqueia o clique — o estado pressed permanece visível.
|
|
52
|
+
|
|
53
|
+
```tsx preview
|
|
54
|
+
<Toggle disabled aria-label="Negrito">
|
|
55
|
+
<Bold />
|
|
56
|
+
</Toggle>
|
|
57
|
+
<Toggle disabled defaultPressed variant="outline">
|
|
58
|
+
<Eye />
|
|
59
|
+
Somente leitura
|
|
60
|
+
</Toggle>
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## Props
|
|
64
|
+
|
|
65
|
+
| Prop | Tipo | Default | Descrição |
|
|
66
|
+
|---|---|---|---|
|
|
67
|
+
| `pressed` | `boolean` | | O estado ligado/desligado no modo controlado — parear com onPressedChange. |
|
|
68
|
+
| `onPressedChange` | `(pressed: boolean) => void` | | Chamado a cada alternância, com o novo estado. |
|
|
69
|
+
| `defaultPressed` | `boolean` | `false` | Estado inicial no modo não controlado. |
|
|
70
|
+
| `variant` | `'default' \| 'outline'` | `'default'` | default não tem borda (fundo só quando ativo); outline carrega a borda. |
|
|
71
|
+
| `size` | `'sm' \| 'default' \| 'lg'` | `'default'` | Altura do botão — sm pra toolbar densa, lg pra alvo mais confortável. |
|
|
72
|
+
| `disabled` | `boolean` | `false` | Esmaece e bloqueia o clique, preservando o estado visual. |
|