@softize/opus 13.0.0 → 14.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/PROMOTED.md +46 -0
- package/README.md +28 -19
- package/bin/cli.mjs +87 -216
- package/bin/lib/cli-shared.mjs +131 -0
- package/bin/lib/copy.mjs +276 -6
- 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/code-style.md +4 -1
- package/docs/ownership-vs-shadcn-lock.md +2 -3
- package/docs/protocol.md +7 -7
- package/docs/releasing.md +8 -2
- package/package.json +7 -3
- package/registry/instructions/opus.md +3 -3
- package/registry/templates/app/package.json +1 -1
- package/registry/templates/app/src/App.tsx +11 -6
- 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 +5 -6
- 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/action-list-dialog.tsx +10 -3
- package/src/ui/components/patterns/confirm.tsx +2 -31
- package/src/ui/components/patterns/content-header.tsx +44 -137
- package/src/ui/components/patterns/data-state.tsx +42 -68
- package/src/ui/components/patterns/dock.tsx +20 -3
- package/src/ui/components/patterns/form.tsx +26 -22
- package/src/ui/components/patterns/list.tsx +18 -12
- package/src/ui/components/patterns/page-state.tsx +39 -51
- package/src/ui/components/patterns/page.tsx +37 -54
- package/src/ui/components/patterns/sidebar.tsx +17 -6
- package/src/ui/components/patterns/state-surface.tsx +148 -0
- package/src/ui/components/patterns/surface-header.tsx +119 -0
- package/src/ui/components/patterns/trigger.tsx +21 -25
- package/src/ui/components/patterns/view.tsx +29 -22
- package/src/ui/components/primitives/alert.tsx +1 -27
- package/src/ui/components/primitives/ask.tsx +3 -3
- package/src/ui/components/primitives/avatar.tsx +15 -5
- package/src/ui/components/primitives/badge.tsx +5 -41
- package/src/ui/components/primitives/breadcrumb.tsx +2 -2
- package/src/ui/components/primitives/button.tsx +39 -30
- 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 +72 -0
- package/src/ui/components/primitives/copyable.tsx +1 -1
- package/src/ui/components/primitives/dialog.tsx +12 -7
- package/src/ui/components/primitives/dot.tsx +1 -25
- package/src/ui/components/primitives/drawer.tsx +10 -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 +12 -9
- 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 -1
- package/src/ui/components/primitives/menu.tsx +1 -7
- package/src/ui/components/primitives/pagination.tsx +16 -8
- 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 +6 -6
- package/src/ui/components/primitives/slider.tsx +5 -1
- package/src/ui/components/primitives/sonner.tsx +3 -0
- package/src/ui/components/primitives/spinner.tsx +13 -16
- package/src/ui/components/primitives/switch.tsx +5 -1
- package/src/ui/components/primitives/tabs.tsx +6 -3
- package/src/ui/components/primitives/textarea.tsx +1 -1
- package/src/ui/components/primitives/toggle.tsx +9 -4
- package/src/ui/components/primitives/tooltip.tsx +1 -0
- package/src/ui/docs/changelog.tsx +1 -1
- package/src/ui/docs/content/action-form.md +36 -3
- package/src/ui/docs/content/action-list-dialog.md +2 -2
- package/src/ui/docs/content/action-list.md +13 -2
- package/src/ui/docs/content/action-trigger.md +12 -5
- package/src/ui/docs/content/action-view.md +11 -3
- package/src/ui/docs/content/ask.md +11 -0
- package/src/ui/docs/content/avatar.md +7 -3
- package/src/ui/docs/content/button.md +30 -14
- package/src/ui/docs/content/calendar.md +13 -0
- package/src/ui/docs/content/card.md +26 -0
- package/src/ui/docs/content/chat.md +20 -0
- package/src/ui/docs/content/cli.md +71 -19
- package/src/ui/docs/content/communication.md +36 -0
- package/src/ui/docs/content/composer.md +15 -0
- package/src/ui/docs/content/content.md +17 -1
- package/src/ui/docs/content/copyable.md +8 -0
- package/src/ui/docs/content/data-state.md +17 -13
- package/src/ui/docs/content/detail.md +19 -1
- package/src/ui/docs/content/dialog.md +1 -4
- package/src/ui/docs/content/dictionary-value.md +9 -2
- package/src/ui/docs/content/dock.md +8 -0
- package/src/ui/docs/content/dot.md +8 -0
- package/src/ui/docs/content/empty.md +2 -2
- package/src/ui/docs/content/getting-started.md +2 -2
- package/src/ui/docs/content/icon-picker.md +11 -0
- package/src/ui/docs/content/input.md +1 -1
- package/src/ui/docs/content/item.md +1 -1
- package/src/ui/docs/content/label.md +7 -0
- package/src/ui/docs/content/menu.md +6 -0
- package/src/ui/docs/content/metric-card.md +13 -0
- package/src/ui/docs/content/page.md +20 -4
- package/src/ui/docs/content/pagination.md +11 -9
- package/src/ui/docs/content/popover.md +6 -0
- package/src/ui/docs/content/progress.md +8 -11
- package/src/ui/docs/content/select.md +5 -5
- package/src/ui/docs/content/semantic-context.md +5 -4
- package/src/ui/docs/content/sidebar.md +13 -47
- package/src/ui/docs/content/skeleton.md +6 -0
- package/src/ui/docs/content/spinner.md +9 -6
- package/src/ui/docs/content/split.md +21 -0
- package/src/ui/docs/content/switch.md +1 -1
- package/src/ui/docs/content/tabs.md +1 -1
- package/src/ui/docs/content/textarea.md +7 -0
- package/src/ui/docs/content/toggle.md +1 -1
- package/src/ui/docs/content/tokens.md +4 -4
- package/src/ui/docs/content/truncate.md +8 -0
- package/src/ui/docs/content/ui.md +14 -0
- package/src/ui/docs/doc-client.tsx +5 -5
- package/src/ui/docs/doc.tsx +26 -14
- package/src/ui/docs/registry.tsx +5 -5
- package/src/ui/docs/standalone.tsx +2 -2
- package/src/ui/drivers/react.tsx +12 -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 +8 -8
- package/src/ui/react.tsx +10 -16
- package/src/ui/theme.css +10 -8
- package/src/vite/design.ts +6 -18
- package/src/ui/components/patterns/shell-nav.tsx +0 -147
|
@@ -1,147 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* <ShellNav /> — o menu como primitivo PIVOTÁVEL. Um nav (grupos → itens, com heading e
|
|
3
|
-
* âncora inferior) que serve os DOIS lares do chrome sem flag:
|
|
4
|
-
*
|
|
5
|
-
* - dentro de <Sidebar> → recolhe pra ícone-só (com tooltip) junto com a coluna;
|
|
6
|
-
* - fora de <Sidebar> → permanece expandido.
|
|
7
|
-
*
|
|
8
|
-
* "Tanto faz onde": o componente se adapta ao lugar, sem "modo" configurado.
|
|
9
|
-
*
|
|
10
|
-
* Presentacional e CONTROLADO — o app é dono do `activeId`, do clique e do roteamento.
|
|
11
|
-
* v1 PLANA (grupos → itens); aninhamento (accordion/pasta) e DnD COMPOSTO entram quando o
|
|
12
|
-
* primeiro consumidor de árvore migrar — ver `docs/shellnav.md`.
|
|
13
|
-
*/
|
|
14
|
-
|
|
15
|
-
import type { ReactNode } from 'react'
|
|
16
|
-
import { cn } from '../../lib/cn.ts'
|
|
17
|
-
import { useSidebarCollapsed } from './sidebar.tsx'
|
|
18
|
-
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '../primitives/tooltip.tsx'
|
|
19
|
-
|
|
20
|
-
export interface ShellNavItem {
|
|
21
|
-
/** Coordenada estável — volta em `onSelect` e casa com `activeId`. Único em toda a nav. */
|
|
22
|
-
id: string
|
|
23
|
-
label: string
|
|
24
|
-
/** Ícone à esquerda (é o que sobra no modo recolhido — vira o alvo, com o label no tooltip). */
|
|
25
|
-
icon?: ReactNode
|
|
26
|
-
/** Selo à direita (contagem, `beta`). Some no recolhido. */
|
|
27
|
-
badge?: ReactNode
|
|
28
|
-
/** Visível mas inerte. */
|
|
29
|
-
disabled?: boolean
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
export interface ShellNavGroup {
|
|
33
|
-
/** Cabeçalho do grupo. Ausente/vazio = itens soltos, sem rótulo. Some no recolhido. */
|
|
34
|
-
label?: string
|
|
35
|
-
items: ShellNavItem[]
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
export interface ShellNavProps {
|
|
39
|
-
groups: ShellNavGroup[]
|
|
40
|
-
/** `id` do item ativo. Ausente = nenhum destacado. */
|
|
41
|
-
activeId?: string
|
|
42
|
-
onSelect: (id: string) => void
|
|
43
|
-
/** Topo do nav — título, busca, botão (ex.: o "+" do Relatórios). Some no recolhido. Ver <ShellNavHeading>. */
|
|
44
|
-
heading?: ReactNode
|
|
45
|
-
/** Grupos ANCORADOS embaixo (ex.: Configurações no app), mesmo renderer, separados por filete. */
|
|
46
|
-
footer?: ShellNavGroup[]
|
|
47
|
-
/** Rótulo da landmark `<nav>`. */
|
|
48
|
-
navLabel?: string
|
|
49
|
-
/** Classes da raiz (a coluna). A largura vem do pane/sidebar que a contém. */
|
|
50
|
-
className?: string
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
/** Rótulo só existe se tiver texto — vazio não vira cabeçalho fantasma. */
|
|
54
|
-
const titled = (label?: string): boolean => (label ?? '').trim() !== ''
|
|
55
|
-
|
|
56
|
-
/** Selo vazio não vira pílula sem texto. `0` conta (contagem legítima). */
|
|
57
|
-
const shown = (badge: ReactNode): boolean => {
|
|
58
|
-
if (badge === undefined || badge === null || badge === false || badge === '') return false
|
|
59
|
-
if (typeof badge === 'number' && Number.isNaN(badge)) return false
|
|
60
|
-
return !(Array.isArray(badge) && badge.length === 0)
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
/** Grupo sem item não abre buraco no `space-y` nem deixa rótulo pairando sobre nada. */
|
|
64
|
-
const filled = (group: ShellNavGroup): boolean => group.items.length > 0
|
|
65
|
-
|
|
66
|
-
function renderItem(item: ShellNavItem, activeId: string | undefined, onSelect: (id: string) => void, railed: boolean): React.ReactElement {
|
|
67
|
-
const active = item.id === activeId
|
|
68
|
-
const button = (
|
|
69
|
-
<button
|
|
70
|
-
type="button"
|
|
71
|
-
disabled={item.disabled}
|
|
72
|
-
aria-current={active ? 'page' : undefined}
|
|
73
|
-
onClick={() => onSelect(item.id)}
|
|
74
|
-
className={cn(
|
|
75
|
-
'flex w-full items-center gap-2.5 rounded-md py-1.5 text-left text-sm transition-colors',
|
|
76
|
-
'disabled:pointer-events-none disabled:opacity-40',
|
|
77
|
-
'outline-none focus-visible:ring-2 focus-visible:ring-ring/50',
|
|
78
|
-
railed ? 'justify-center px-0' : 'px-2.5',
|
|
79
|
-
active ? 'bg-muted font-medium text-foreground' : 'text-foreground/80 hover:bg-muted/60',
|
|
80
|
-
)}
|
|
81
|
-
>
|
|
82
|
-
{item.icon !== undefined && <span className="flex shrink-0">{item.icon}</span>}
|
|
83
|
-
{!railed && <span className="min-w-0 flex-1 truncate">{item.label}</span>}
|
|
84
|
-
{!railed && shown(item.badge) && <span className="shrink-0">{item.badge}</span>}
|
|
85
|
-
</button>
|
|
86
|
-
)
|
|
87
|
-
if (!railed) return <div key={item.id}>{button}</div>
|
|
88
|
-
// Recolhido: o label migra pro tooltip (à direita) — sem ele, a coluna vira ícones adivinháveis.
|
|
89
|
-
return (
|
|
90
|
-
<Tooltip key={item.id}>
|
|
91
|
-
<TooltipTrigger asChild>{button}</TooltipTrigger>
|
|
92
|
-
<TooltipContent side="right">{item.label}</TooltipContent>
|
|
93
|
-
</Tooltip>
|
|
94
|
-
)
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
function renderGroup(group: ShellNavGroup, gi: number, activeId: string | undefined, onSelect: (id: string) => void, railed: boolean): React.ReactElement | null {
|
|
98
|
-
if (!filled(group)) return null
|
|
99
|
-
return (
|
|
100
|
-
<div key={gi} className="space-y-0.5">
|
|
101
|
-
{!railed && titled(group.label) && (
|
|
102
|
-
<div className="px-2.5 pb-1 text-xs font-medium text-muted-foreground/70">{group.label}</div>
|
|
103
|
-
)}
|
|
104
|
-
{group.items.map((item) => renderItem(item, activeId, onSelect, railed))}
|
|
105
|
-
</div>
|
|
106
|
-
)
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
export function ShellNav({ groups, activeId, onSelect, heading, footer, navLabel = 'Navegação', className }: ShellNavProps): React.ReactElement {
|
|
110
|
-
const railed = useSidebarCollapsed()
|
|
111
|
-
|
|
112
|
-
const body = (
|
|
113
|
-
<div data-slot="shell-nav" className={cn('flex h-full min-h-0 flex-col', className)}>
|
|
114
|
-
{!railed && heading}
|
|
115
|
-
<nav aria-label={navLabel} className={cn('min-h-0 flex-1 space-y-4 overflow-y-auto p-2', railed && 'px-1.5')}>
|
|
116
|
-
{groups.map((group, gi) => renderGroup(group, gi, activeId, onSelect, railed))}
|
|
117
|
-
</nav>
|
|
118
|
-
{footer !== undefined && footer.some(filled) && (
|
|
119
|
-
<div className={cn('space-y-4 border-t border-border p-2', railed && 'px-1.5')}>
|
|
120
|
-
{footer.map((group, gi) => renderGroup(group, gi, activeId, onSelect, railed))}
|
|
121
|
-
</div>
|
|
122
|
-
)}
|
|
123
|
-
</div>
|
|
124
|
-
)
|
|
125
|
-
|
|
126
|
-
// Recolhido usa tooltips — garante um provider (nested é ok se o app já tem um).
|
|
127
|
-
return railed ? <TooltipProvider delayDuration={200}>{body}</TooltipProvider> : body
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
export interface ShellNavHeadingProps {
|
|
131
|
-
/** Título da seção. */
|
|
132
|
-
title: ReactNode
|
|
133
|
-
/** Ação à direita — em geral um botão (o "+" de criar). */
|
|
134
|
-
action?: ReactNode
|
|
135
|
-
className?: string
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
/** Cabeçalho padrão do ShellNav: título + espaço pra um botão. É o gesto que hoje cada
|
|
139
|
-
* nav monta à mão (o "+" do Relatórios, o título de Configurações). */
|
|
140
|
-
export function ShellNavHeading({ title, action, className }: ShellNavHeadingProps): React.ReactElement {
|
|
141
|
-
return (
|
|
142
|
-
<div className={cn('flex h-12 shrink-0 items-center gap-1.5 border-b border-border px-4', className)}>
|
|
143
|
-
<span className="min-w-0 flex-1 truncate text-sm font-semibold">{title}</span>
|
|
144
|
-
{action !== undefined && <span className="shrink-0">{action}</span>}
|
|
145
|
-
</div>
|
|
146
|
-
)
|
|
147
|
-
}
|