@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.
Files changed (286) hide show
  1. package/CHANGELOG.md +1616 -0
  2. package/LICENSE +21 -0
  3. package/README.md +113 -0
  4. package/bin/cli.mjs +528 -0
  5. package/bin/lib/check.mjs +307 -0
  6. package/bin/lib/components.mjs +151 -0
  7. package/bin/lib/create.mjs +208 -0
  8. package/bin/lib/db-check-runner.mjs +86 -0
  9. package/bin/lib/db-migrate-runner.mjs +89 -0
  10. package/bin/lib/db-scaffold-runner.mjs +84 -0
  11. package/bin/lib/db.mjs +261 -0
  12. package/bin/lib/docs-include.mjs +48 -0
  13. package/bin/lib/gen-dicts.mjs +134 -0
  14. package/bin/lib/gen-docs.mjs +288 -0
  15. package/bin/lib/gen-manifest.mjs +102 -0
  16. package/bin/lib/gen-openapi.mjs +195 -0
  17. package/bin/lib/gen-runner.mjs +472 -0
  18. package/bin/lib/gen-stubs.mjs +463 -0
  19. package/bin/lib/gen.mjs +311 -0
  20. package/bin/lib/init.mjs +514 -0
  21. package/bin/lib/introspect.mjs +107 -0
  22. package/bin/lib/mcp.mjs +85 -0
  23. package/bin/lib/postinstall.mjs +56 -0
  24. package/docs/chat-event-protocol.md +85 -0
  25. package/docs/code-style.md +16 -0
  26. package/docs/data-layer.md +246 -0
  27. package/docs/ownership-vs-shadcn-lock.md +102 -0
  28. package/docs/protocol.md +2053 -0
  29. package/docs/releasing.md +110 -0
  30. package/docs/shellnav.md +131 -0
  31. package/package.json +338 -0
  32. package/registry/hooks/hooks.json +26 -0
  33. package/registry/hooks/link-memory-on-start.mjs +46 -0
  34. package/registry/hooks/opus-check-on-stop.mjs +114 -0
  35. package/registry/skills/create-action/SKILL.md +49 -0
  36. package/registry/skills/create-action/scaffold.mjs +122 -0
  37. package/registry/templates/app/_gitignore +3 -0
  38. package/registry/templates/app/_npmrc +1 -0
  39. package/registry/templates/app/_opus/_gitignore +5 -0
  40. package/registry/templates/app/_prettierrc.json +6 -0
  41. package/registry/templates/app/index.html +13 -0
  42. package/registry/templates/app/opus.config.ts +16 -0
  43. package/registry/templates/app/package.json +43 -0
  44. package/registry/templates/app/pnpm-workspace.yaml +11 -0
  45. package/registry/templates/app/public/favicon.svg +4 -0
  46. package/registry/templates/app/src/App.tsx +37 -0
  47. package/registry/templates/app/src/domains/tasks/actions/list.test.ts +34 -0
  48. package/registry/templates/app/src/domains/tasks/actions/list.ts +33 -0
  49. package/registry/templates/app/src/domains/tasks/index.ts +13 -0
  50. package/registry/templates/app/src/index.css +18 -0
  51. package/registry/templates/app/src/main.tsx +25 -0
  52. package/registry/templates/app/tsconfig.json +20 -0
  53. package/registry/templates/app/vite.config.ts +46 -0
  54. package/registry/templates/monorepo/_gitignore +3 -0
  55. package/registry/templates/monorepo/_npmrc +1 -0
  56. package/registry/templates/monorepo/package.json +9 -0
  57. package/registry/templates/monorepo/pnpm-workspace.yaml +14 -0
  58. package/src/ai/ask.ts +64 -0
  59. package/src/ai/drivers/anthropic.ts +309 -0
  60. package/src/ai/index.ts +17 -0
  61. package/src/audit/drivers/console.ts +117 -0
  62. package/src/audit/drivers/pg.ts +172 -0
  63. package/src/audit/index.ts +51 -0
  64. package/src/auth/drivers/better-auth.ts +103 -0
  65. package/src/auth/drivers/jwt.ts +188 -0
  66. package/src/auth/index.ts +9 -0
  67. package/src/client/drivers/fetch.ts +202 -0
  68. package/src/client/index.ts +22 -0
  69. package/src/core/actions.ts +110 -0
  70. package/src/core/audit.ts +239 -0
  71. package/src/core/contracts.ts +137 -0
  72. package/src/core/domain.ts +310 -0
  73. package/src/core/errors.ts +181 -0
  74. package/src/core/index.ts +174 -0
  75. package/src/core/logical-type.ts +31 -0
  76. package/src/core/reactions.ts +81 -0
  77. package/src/core/runtime.ts +1167 -0
  78. package/src/core/schedules.ts +41 -0
  79. package/src/core/types.ts +1356 -0
  80. package/src/data/drivers/kysely.ts +389 -0
  81. package/src/data/index.ts +10 -0
  82. package/src/data/readonly-pool.ts +160 -0
  83. package/src/dsl/eval.ts +136 -0
  84. package/src/dsl/index.ts +29 -0
  85. package/src/dsl/kysely.ts +230 -0
  86. package/src/dsl/loads.ts +123 -0
  87. package/src/dsl/parser.ts +423 -0
  88. package/src/dsl/types.ts +113 -0
  89. package/src/events/drivers/mitt.ts +70 -0
  90. package/src/events/index.ts +9 -0
  91. package/src/log/drivers/pino.ts +57 -0
  92. package/src/log/index.ts +9 -0
  93. package/src/mcp/index.ts +62 -0
  94. package/src/queue/drivers/bullmq.ts +190 -0
  95. package/src/queue/index.ts +9 -0
  96. package/src/scheduler/drivers/node-cron.ts +93 -0
  97. package/src/scheduler/every.ts +45 -0
  98. package/src/scheduler/index.ts +9 -0
  99. package/src/schema/drivers/zod.ts +765 -0
  100. package/src/schema/entity.ts +439 -0
  101. package/src/schema/format/locale.ts +144 -0
  102. package/src/schema/index.ts +65 -0
  103. package/src/schema/openapi.ts +302 -0
  104. package/src/schema/scaffold.ts +160 -0
  105. package/src/server/drivers/fastify.ts +224 -0
  106. package/src/server/drivers/node.ts +386 -0
  107. package/src/server/index.ts +142 -0
  108. package/src/storage/drivers/fs.ts +90 -0
  109. package/src/storage/drivers/s3.ts +117 -0
  110. package/src/storage/index.ts +27 -0
  111. package/src/testing/fake.ts +298 -0
  112. package/src/testing/index.ts +324 -0
  113. package/src/ui/components/patterns/action-form-card.tsx +48 -0
  114. package/src/ui/components/patterns/action-list-dialog.tsx +93 -0
  115. package/src/ui/components/patterns/app-shell.tsx +227 -0
  116. package/src/ui/components/patterns/confirm.tsx +226 -0
  117. package/src/ui/components/patterns/data-state.tsx +75 -0
  118. package/src/ui/components/patterns/form-dialog.tsx +64 -0
  119. package/src/ui/components/patterns/form.tsx +584 -0
  120. package/src/ui/components/patterns/list.tsx +1488 -0
  121. package/src/ui/components/patterns/page.tsx +46 -0
  122. package/src/ui/components/patterns/section-shell.tsx +246 -0
  123. package/src/ui/components/patterns/shell-nav.tsx +150 -0
  124. package/src/ui/components/patterns/sidebar.tsx +89 -0
  125. package/src/ui/components/patterns/split.tsx +93 -0
  126. package/src/ui/components/patterns/trigger.tsx +196 -0
  127. package/src/ui/components/patterns/view.tsx +84 -0
  128. package/src/ui/components/primitives/accordion.tsx +64 -0
  129. package/src/ui/components/primitives/alert-dialog.tsx +190 -0
  130. package/src/ui/components/primitives/alert.tsx +116 -0
  131. package/src/ui/components/primitives/aspect-ratio.tsx +9 -0
  132. package/src/ui/components/primitives/avatar.tsx +107 -0
  133. package/src/ui/components/primitives/badge.tsx +37 -0
  134. package/src/ui/components/primitives/breadcrumb.tsx +109 -0
  135. package/src/ui/components/primitives/button-group.tsx +83 -0
  136. package/src/ui/components/primitives/button.tsx +102 -0
  137. package/src/ui/components/primitives/calendar.tsx +218 -0
  138. package/src/ui/components/primitives/card.tsx +56 -0
  139. package/src/ui/components/primitives/carousel.tsx +239 -0
  140. package/src/ui/components/primitives/chat.tsx +407 -0
  141. package/src/ui/components/primitives/checkbox.tsx +30 -0
  142. package/src/ui/components/primitives/collapsible.tsx +31 -0
  143. package/src/ui/components/primitives/command.tsx +182 -0
  144. package/src/ui/components/primitives/composer.tsx +121 -0
  145. package/src/ui/components/primitives/copyable.tsx +50 -0
  146. package/src/ui/components/primitives/dialog.tsx +147 -0
  147. package/src/ui/components/primitives/drawer.tsx +141 -0
  148. package/src/ui/components/primitives/empty.tsx +104 -0
  149. package/src/ui/components/primitives/field.tsx +246 -0
  150. package/src/ui/components/primitives/icon-picker.tsx +180 -0
  151. package/src/ui/components/primitives/input-group.tsx +168 -0
  152. package/src/ui/components/primitives/input-otp.tsx +75 -0
  153. package/src/ui/components/primitives/input.tsx +72 -0
  154. package/src/ui/components/primitives/item.tsx +193 -0
  155. package/src/ui/components/primitives/kbd.tsx +28 -0
  156. package/src/ui/components/primitives/label.tsx +22 -0
  157. package/src/ui/components/primitives/markdown.tsx +35 -0
  158. package/src/ui/components/primitives/menu.tsx +255 -0
  159. package/src/ui/components/primitives/pagination.tsx +127 -0
  160. package/src/ui/components/primitives/popover.tsx +87 -0
  161. package/src/ui/components/primitives/progress.tsx +29 -0
  162. package/src/ui/components/primitives/radio-group.tsx +43 -0
  163. package/src/ui/components/primitives/resizable.tsx +51 -0
  164. package/src/ui/components/primitives/scroll-area.tsx +56 -0
  165. package/src/ui/components/primitives/select.tsx +479 -0
  166. package/src/ui/components/primitives/separator.tsx +26 -0
  167. package/src/ui/components/primitives/skeleton.tsx +13 -0
  168. package/src/ui/components/primitives/slider.tsx +61 -0
  169. package/src/ui/components/primitives/sonner.tsx +46 -0
  170. package/src/ui/components/primitives/spinner.tsx +29 -0
  171. package/src/ui/components/primitives/switch.tsx +33 -0
  172. package/src/ui/components/primitives/table.tsx +114 -0
  173. package/src/ui/components/primitives/tabs.tsx +104 -0
  174. package/src/ui/components/primitives/textarea.tsx +18 -0
  175. package/src/ui/components/primitives/toggle-group.tsx +81 -0
  176. package/src/ui/components/primitives/toggle.tsx +45 -0
  177. package/src/ui/components/primitives/tooltip.tsx +55 -0
  178. package/src/ui/components/primitives/truncate.tsx +49 -0
  179. package/src/ui/docs/DocBrowser.tsx +90 -0
  180. package/src/ui/docs/changelog.tsx +80 -0
  181. package/src/ui/docs/content/accordion.md +86 -0
  182. package/src/ui/docs/content/action-form-card.md +24 -0
  183. package/src/ui/docs/content/action-form-dialog.md +30 -0
  184. package/src/ui/docs/content/action-form.md +125 -0
  185. package/src/ui/docs/content/action-list-dialog.md +68 -0
  186. package/src/ui/docs/content/action-list.md +194 -0
  187. package/src/ui/docs/content/action-trigger.md +72 -0
  188. package/src/ui/docs/content/action-view.md +47 -0
  189. package/src/ui/docs/content/actions.md +138 -0
  190. package/src/ui/docs/content/ai.md +112 -0
  191. package/src/ui/docs/content/alert-dialog.md +73 -0
  192. package/src/ui/docs/content/alert.md +69 -0
  193. package/src/ui/docs/content/app-shell.md +155 -0
  194. package/src/ui/docs/content/aspect-ratio.md +66 -0
  195. package/src/ui/docs/content/audit.md +84 -0
  196. package/src/ui/docs/content/auth.md +70 -0
  197. package/src/ui/docs/content/avatar.md +94 -0
  198. package/src/ui/docs/content/badge.md +48 -0
  199. package/src/ui/docs/content/breadcrumb.md +87 -0
  200. package/src/ui/docs/content/button-group.md +71 -0
  201. package/src/ui/docs/content/button.md +60 -0
  202. package/src/ui/docs/content/calendar.md +62 -0
  203. package/src/ui/docs/content/card.md +49 -0
  204. package/src/ui/docs/content/carousel.md +85 -0
  205. package/src/ui/docs/content/chat.md +69 -0
  206. package/src/ui/docs/content/checkbox.md +75 -0
  207. package/src/ui/docs/content/cli.md +58 -0
  208. package/src/ui/docs/content/collapsible.md +64 -0
  209. package/src/ui/docs/content/command.md +56 -0
  210. package/src/ui/docs/content/composer.md +50 -0
  211. package/src/ui/docs/content/confirm.md +120 -0
  212. package/src/ui/docs/content/copyable.md +30 -0
  213. package/src/ui/docs/content/customization.md +110 -0
  214. package/src/ui/docs/content/cycle.md +34 -0
  215. package/src/ui/docs/content/data-state.md +47 -0
  216. package/src/ui/docs/content/data.md +99 -0
  217. package/src/ui/docs/content/dialog.md +60 -0
  218. package/src/ui/docs/content/drawer.md +55 -0
  219. package/src/ui/docs/content/empty.md +66 -0
  220. package/src/ui/docs/content/events.md +61 -0
  221. package/src/ui/docs/content/field.md +58 -0
  222. package/src/ui/docs/content/getting-started.md +109 -0
  223. package/src/ui/docs/content/icon-picker.md +51 -0
  224. package/src/ui/docs/content/input-group.md +78 -0
  225. package/src/ui/docs/content/input-otp.md +72 -0
  226. package/src/ui/docs/content/input.md +78 -0
  227. package/src/ui/docs/content/item.md +84 -0
  228. package/src/ui/docs/content/kbd.md +62 -0
  229. package/src/ui/docs/content/label.md +32 -0
  230. package/src/ui/docs/content/log.md +55 -0
  231. package/src/ui/docs/content/markdown.md +41 -0
  232. package/src/ui/docs/content/mcp.md +44 -0
  233. package/src/ui/docs/content/menu.md +114 -0
  234. package/src/ui/docs/content/microcopy.md +83 -0
  235. package/src/ui/docs/content/page.md +34 -0
  236. package/src/ui/docs/content/pagination.md +99 -0
  237. package/src/ui/docs/content/popover.md +49 -0
  238. package/src/ui/docs/content/progress.md +69 -0
  239. package/src/ui/docs/content/queue.md +62 -0
  240. package/src/ui/docs/content/radio-group.md +77 -0
  241. package/src/ui/docs/content/resizable.md +86 -0
  242. package/src/ui/docs/content/router.md +56 -0
  243. package/src/ui/docs/content/runtime.md +77 -0
  244. package/src/ui/docs/content/scheduler.md +66 -0
  245. package/src/ui/docs/content/scroll-area.md +89 -0
  246. package/src/ui/docs/content/section-shell.md +121 -0
  247. package/src/ui/docs/content/select.md +342 -0
  248. package/src/ui/docs/content/separator.md +33 -0
  249. package/src/ui/docs/content/sidebar.md +38 -0
  250. package/src/ui/docs/content/skeleton.md +34 -0
  251. package/src/ui/docs/content/slider.md +64 -0
  252. package/src/ui/docs/content/spinner.md +37 -0
  253. package/src/ui/docs/content/split.md +33 -0
  254. package/src/ui/docs/content/storage.md +69 -0
  255. package/src/ui/docs/content/switch.md +69 -0
  256. package/src/ui/docs/content/table.md +102 -0
  257. package/src/ui/docs/content/tabs.md +94 -0
  258. package/src/ui/docs/content/testing.md +89 -0
  259. package/src/ui/docs/content/textarea.md +30 -0
  260. package/src/ui/docs/content/toast.md +67 -0
  261. package/src/ui/docs/content/toggle-group.md +81 -0
  262. package/src/ui/docs/content/toggle.md +72 -0
  263. package/src/ui/docs/content/tokens.md +171 -0
  264. package/src/ui/docs/content/tooltip.md +50 -0
  265. package/src/ui/docs/content/truncate.md +37 -0
  266. package/src/ui/docs/content/ui.md +40 -0
  267. package/src/ui/docs/content/upgrading.md +48 -0
  268. package/src/ui/docs/doc-client.tsx +214 -0
  269. package/src/ui/docs/doc.tsx +301 -0
  270. package/src/ui/docs/folder.tsx +149 -0
  271. package/src/ui/docs/index.ts +21 -0
  272. package/src/ui/docs/markdown.tsx +130 -0
  273. package/src/ui/docs/md-raw.d.ts +4 -0
  274. package/src/ui/docs/plugin.ts +104 -0
  275. package/src/ui/docs/registry.tsx +424 -0
  276. package/src/ui/docs/standalone.tsx +107 -0
  277. package/src/ui/drivers/react.tsx +627 -0
  278. package/src/ui/index.ts +92 -0
  279. package/src/ui/lib/cn.ts +10 -0
  280. package/src/ui/lib/zod-pt-br.ts +38 -0
  281. package/src/ui/meta.ts +412 -0
  282. package/src/ui/react.tsx +235 -0
  283. package/src/ui/router.ts +96 -0
  284. package/src/ui/theme.css +234 -0
  285. package/src/vite/design.ts +652 -0
  286. package/src/vite/index.ts +8 -0
@@ -0,0 +1,235 @@
1
+ /**
2
+ * @softize/opus/ui/react — a superfície React da UI: Provider + hooks (driver de action)
3
+ * + componentes + cn. O consumidor importa tudo daqui.
4
+ *
5
+ * `meta` de cada componente NÃO é re-exportado aqui de propósito — é metadado de
6
+ * build-time (lido pelo manifesto/MCP da fonte), fora do bundle de runtime.
7
+ */
8
+ export * from './drivers/react.tsx'
9
+
10
+ // Utilitário
11
+ export { cn } from './lib/cn.ts'
12
+
13
+ // Primitivos
14
+ export { Button, buttonVariants } from './components/primitives/button.tsx'
15
+ export type { ButtonProps } from './components/primitives/button.tsx'
16
+
17
+ export { Input } from './components/primitives/input.tsx'
18
+
19
+ export { Chat } from './components/primitives/chat.tsx'
20
+ export type { ChatProps, ChatMessage, ChatArtifact, ChatTranscriptItem } from './components/primitives/chat.tsx'
21
+ export { Composer } from './components/primitives/composer.tsx'
22
+ export type { ComposerProps } from './components/primitives/composer.tsx'
23
+ export { Copyable } from './components/primitives/copyable.tsx'
24
+ export type { CopyableProps } from './components/primitives/copyable.tsx'
25
+ export { IconPicker, iconPickerIcons } from './components/primitives/icon-picker.tsx'
26
+ export type { IconPickerProps } from './components/primitives/icon-picker.tsx'
27
+
28
+ export {
29
+ Command,
30
+ CommandDialog,
31
+ CommandInput,
32
+ CommandList,
33
+ CommandEmpty,
34
+ CommandGroup,
35
+ CommandItem,
36
+ CommandSeparator,
37
+ CommandShortcut,
38
+ } from './components/primitives/command.tsx'
39
+
40
+ export { Textarea } from './components/primitives/textarea.tsx'
41
+
42
+ export { Label } from './components/primitives/label.tsx'
43
+
44
+ export { Badge, badgeVariants } from './components/primitives/badge.tsx'
45
+ export type { BadgeProps } from './components/primitives/badge.tsx'
46
+
47
+ export {
48
+ Card,
49
+ CardHeader,
50
+ CardTitle,
51
+ CardDescription,
52
+ CardAction,
53
+ CardContent,
54
+ CardFooter,
55
+ } from './components/primitives/card.tsx'
56
+
57
+ export { Alert, AlertTitle, AlertDescription, alertVariants } from './components/primitives/alert.tsx'
58
+ export type { AlertProps } from './components/primitives/alert.tsx'
59
+
60
+ export {
61
+ Dialog,
62
+ DialogTrigger,
63
+ DialogPortal,
64
+ DialogClose,
65
+ DialogOverlay,
66
+ DialogContent,
67
+ DialogHeader,
68
+ DialogBody,
69
+ DialogFooter,
70
+ DialogTitle,
71
+ DialogDescription,
72
+ } from './components/primitives/dialog.tsx'
73
+
74
+ export {
75
+ Menu,
76
+ MenuTrigger,
77
+ MenuGroup,
78
+ MenuPortal,
79
+ MenuSub,
80
+ MenuRadioGroup,
81
+ MenuSubTrigger,
82
+ MenuSubContent,
83
+ MenuContent,
84
+ MenuItem,
85
+ MenuCheckboxItem,
86
+ MenuRadioItem,
87
+ MenuLabel,
88
+ MenuSeparator,
89
+ MenuShortcut,
90
+ } from './components/primitives/menu.tsx'
91
+
92
+ export {
93
+ Popover,
94
+ PopoverTrigger,
95
+ PopoverAnchor,
96
+ PopoverContent,
97
+ PopoverHeader,
98
+ PopoverTitle,
99
+ PopoverDescription,
100
+ } from './components/primitives/popover.tsx'
101
+
102
+ export {
103
+ TooltipProvider,
104
+ Tooltip,
105
+ TooltipTrigger,
106
+ TooltipContent,
107
+ } from './components/primitives/tooltip.tsx'
108
+
109
+ export { Checkbox } from './components/primitives/checkbox.tsx'
110
+
111
+ export { Separator } from './components/primitives/separator.tsx'
112
+
113
+ export {
114
+ Tabs,
115
+ TabsList,
116
+ TabsTrigger,
117
+ TabsContent,
118
+ } from './components/primitives/tabs.tsx'
119
+
120
+ export { Skeleton } from './components/primitives/skeleton.tsx'
121
+
122
+ export { Spinner } from './components/primitives/spinner.tsx'
123
+ export type { SpinnerProps } from './components/primitives/spinner.tsx'
124
+
125
+ export {
126
+ Table,
127
+ TableHeader,
128
+ TableBody,
129
+ TableFooter,
130
+ TableRow,
131
+ TableHead,
132
+ TableCell,
133
+ TableCaption,
134
+ } from './components/primitives/table.tsx'
135
+
136
+ // UM seletor: `native` (menu do SO), `searchable` (busca), `multiple` (chips) e
137
+ // `variant="ghost"` (barra de composer) são PROPS, não componentes. Ver select.tsx.
138
+ export { Select } from './components/primitives/select.tsx'
139
+ export type { SelectProps, SelectOption } from './components/primitives/select.tsx'
140
+
141
+ export { Toaster, toast } from './components/primitives/sonner.tsx'
142
+ export { Markdown } from './components/primitives/markdown.tsx'
143
+
144
+ // shadcn (lote inicial — byte-fiéis via registry JSON, locked no registry.lock.json)
145
+ export { Accordion, AccordionContent, AccordionItem, AccordionTrigger } from './components/primitives/accordion.tsx'
146
+ export { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogMedia, AlertDialogOverlay, AlertDialogPortal, AlertDialogTitle, AlertDialogTrigger } from './components/primitives/alert-dialog.tsx'
147
+ export { AspectRatio } from './components/primitives/aspect-ratio.tsx'
148
+ export { Avatar, AvatarBadge, AvatarFallback, AvatarGroup, AvatarGroupCount, AvatarImage } from './components/primitives/avatar.tsx'
149
+ export { Breadcrumb, BreadcrumbEllipsis, BreadcrumbItem, BreadcrumbLink, BreadcrumbList, BreadcrumbPage, BreadcrumbSeparator } from './components/primitives/breadcrumb.tsx'
150
+ export { ButtonGroup, ButtonGroupSeparator, ButtonGroupText, buttonGroupVariants } from './components/primitives/button-group.tsx'
151
+ export { Calendar, CalendarDayButton } from './components/primitives/calendar.tsx'
152
+ export { Carousel, CarouselContent, CarouselItem, CarouselNext, CarouselPrevious } from './components/primitives/carousel.tsx'
153
+ export { Collapsible, CollapsibleContent, CollapsibleTrigger } from './components/primitives/collapsible.tsx'
154
+ export { Drawer, DrawerClose, DrawerContent, DrawerDescription, DrawerFooter, DrawerHeader, DrawerTitle, DrawerTrigger } from './components/primitives/drawer.tsx'
155
+ export { Empty, EmptyContent, EmptyDescription, EmptyHeader, EmptyMedia, EmptyTitle } from './components/primitives/empty.tsx'
156
+ export { Field, FieldContent, FieldDescription, FieldError, FieldGroup, FieldLabel, FieldLegend, FieldSeparator, FieldSet, FieldTitle } from './components/primitives/field.tsx'
157
+ export { InputGroup, InputGroupAddon, InputGroupButton, InputGroupInput, InputGroupText, InputGroupTextarea } from './components/primitives/input-group.tsx'
158
+ export { InputOTP, InputOTPGroup, InputOTPSeparator, InputOTPSlot } from './components/primitives/input-otp.tsx'
159
+ export { Item, ItemActions, ItemContent, ItemDescription, ItemFooter, ItemGroup, ItemHeader, ItemMedia, ItemSeparator, ItemTitle } from './components/primitives/item.tsx'
160
+ export { Kbd, KbdGroup } from './components/primitives/kbd.tsx'
161
+ export { Pagination, PaginationContent, PaginationEllipsis, PaginationItem, PaginationLink, PaginationNext, PaginationPrevious } from './components/primitives/pagination.tsx'
162
+ export { Progress } from './components/primitives/progress.tsx'
163
+ export { RadioGroup, RadioGroupItem } from './components/primitives/radio-group.tsx'
164
+ export { ResizableHandle, ResizablePanel, ResizablePanelGroup } from './components/primitives/resizable.tsx'
165
+ export { ScrollArea, ScrollBar } from './components/primitives/scroll-area.tsx'
166
+ export { Slider } from './components/primitives/slider.tsx'
167
+ export { Switch } from './components/primitives/switch.tsx'
168
+ export { Toggle, toggleVariants } from './components/primitives/toggle.tsx'
169
+ export { ToggleGroup, ToggleGroupItem } from './components/primitives/toggle-group.tsx'
170
+ export { Truncate } from './components/primitives/truncate.tsx'
171
+ export type { TruncateProps } from './components/primitives/truncate.tsx'
172
+
173
+ // Patterns (renderizam actions a partir do spec)
174
+ export { ActionForm, ActionFormField, useActionFormContext } from './components/patterns/form.tsx'
175
+ export type { ActionFormProps, ActionFormFieldProps, ActionFormContextValue } from './components/patterns/form.tsx'
176
+
177
+ export { ActionFormDialog } from './components/patterns/form-dialog.tsx'
178
+ export type { ActionFormDialogProps } from './components/patterns/form-dialog.tsx'
179
+
180
+ export { ActionFormCard } from './components/patterns/action-form-card.tsx'
181
+ export type { ActionFormCardProps } from './components/patterns/action-form-card.tsx'
182
+
183
+ export { ActionList, emptyListState, presetRange, listParamsToState, listStateToParams } from './components/patterns/list.tsx'
184
+ export type { ActionListProps, ActionListColumn, ActionListState, ActionListView, ActionListBatchAction, ListActionLike } from './components/patterns/list.tsx'
185
+
186
+ export { ActionView } from './components/patterns/view.tsx'
187
+ export type { ActionViewProps } from './components/patterns/view.tsx'
188
+
189
+ export { ActionTrigger } from './components/patterns/trigger.tsx'
190
+ export { dialog, DialogHost, confirm, ConfirmHost } from './components/patterns/confirm.tsx'
191
+ export type { AlertOptions, ConfirmOptions, PromptOptions } from './components/patterns/confirm.tsx'
192
+ export type { ActionTriggerProps } from './components/patterns/trigger.tsx'
193
+
194
+ // Listagem em modal: ListAction query-backed + chrome (toolbar/estados derivados).
195
+ export { ActionListDialog } from './components/patterns/action-list-dialog.tsx'
196
+ export type { ActionListDialogProps } from './components/patterns/action-list-dialog.tsx'
197
+
198
+ // Estado de carga (carregando/vazio/erro → conteúdo) — o "antes" do conteúdo.
199
+ export { DataState } from './components/patterns/data-state.tsx'
200
+ export type { DataStateProps } from './components/patterns/data-state.tsx'
201
+
202
+ // Esqueleto de página do back-office (main + container + header título/descrição/ação).
203
+ export { Page } from './components/patterns/page.tsx'
204
+ export type { PageProps } from './components/patterns/page.tsx'
205
+
206
+ // Chrome da aplicação (sidebar + conteúdo + rail opcional redimensionável).
207
+ export { AppShell, AppShellBar, AppShellTrigger, useAppShell, useSidebarSlot } from './components/patterns/app-shell.tsx'
208
+ export type { AppShellProps } from './components/patterns/app-shell.tsx'
209
+
210
+ // Layout composicional: Split decide a relação espacial; Pane carrega conteúdo com inset.
211
+ export { Split, Pane } from './components/patterns/split.tsx'
212
+ export type { SplitProps, PaneProps } from './components/patterns/split.tsx'
213
+
214
+ // Barra lateral composicional: header/conteúdo/footer e navegação, sem possuir o layout.
215
+ export { PaneHeader, PaneContent, PaneFooter, Sidebar, SidebarHeader, SidebarContent, SidebarFooter, SidebarItem, SidebarNav } from './components/patterns/sidebar.tsx'
216
+ export type { SidebarProps, SidebarItemProps, SidebarNavGroup } from './components/patterns/sidebar.tsx'
217
+
218
+ // Seção com navegação própria (nav w-56 + painel) — o nível entre o AppShell e a Page.
219
+ export { SectionShell } from './components/patterns/section-shell.tsx'
220
+ export type {
221
+ SectionShellProps,
222
+ SectionNavGroup,
223
+ SectionNavSubgroup,
224
+ SectionNavItem,
225
+ } from './components/patterns/section-shell.tsx'
226
+
227
+ // O menu como primitivo PIVOTÁVEL: mesmo nav na sidebar do AppShell ou dentro do conteúdo
228
+ // (colapso por CSS via o grupo `sidebar`). Ver docs/shellnav.md.
229
+ export { ShellNav, ShellNavHeading } from './components/patterns/shell-nav.tsx'
230
+ export type { ShellNavProps, ShellNavGroup, ShellNavItem, ShellNavHeadingProps } from './components/patterns/shell-nav.tsx'
231
+
232
+ // Roteamento history-based (o pathname É o estado). Escopo pequeno de propósito: leitura
233
+ // reativa da URL + navigate — sem tabela de rotas. Ver src/ui/router.ts.
234
+ export { navigate, usePathname, useSegments, useSearchParams } from './router.ts'
235
+ export type { NavigateOptions } from './router.ts'
@@ -0,0 +1,96 @@
1
+ /**
2
+ * Roteamento history-based — o pathname É o estado.
3
+ *
4
+ * Nasceu por REINCIDÊNCIA: o mesmo mecanismo estava reimplementado à mão em quatro
5
+ * lugares, três deles dentro da casa (o `DocBrowser` daqui, o site do Opus e o
6
+ * back-office da Empresa X). As cópias divergiam no que importa — só uma usava
7
+ * `useSyncExternalStore` (as outras leem `window.location` em `useState`, que sofre
8
+ * tearing no modo concurrent), e cada uma notificava de um jeito.
9
+ *
10
+ * Escopo deliberadamente PEQUENO: não há tabela de rotas, `<Route>`, params tipados nem
11
+ * carregamento de dados. Isto é a leitura reativa da URL + um `navigate` — quem decide o
12
+ * que renderizar é o app, com `if`/`switch` sobre os segmentos. Se um dia o caso pedir
13
+ * casamento de padrão e params, aí é outra conversa (e provavelmente outra biblioteca).
14
+ *
15
+ * import { navigate, useSegments } from '@softize/opus/ui/react'
16
+ *
17
+ * const segments = useSegments() // '/settings/users' → ['settings','users']
18
+ * navigate('/settings/users') // pushState + notifica
19
+ * navigate('/x', { replace: true }) // troca a entrada corrente
20
+ */
21
+
22
+ import { useMemo, useSyncExternalStore } from 'react'
23
+
24
+ /** `popstate` é o ÚNICO canal de notificação, e de propósito: cobre voltar/avançar do
25
+ * browser, o `navigate` daqui e quem ainda notifica na unha por evento sintético. Um
26
+ * `Set` de assinantes em escopo de módulo pareceria mais direto e seria pior — ele mora
27
+ * numa instância do bundle, então código não-migrado (que escuta o evento) e uma segunda
28
+ * cópia do pacote no `node_modules` ficariam de fora. O `window` é um só. */
29
+ function subscribe(callback: () => void): () => void {
30
+ window.addEventListener('popstate', callback)
31
+ return () => window.removeEventListener('popstate', callback)
32
+ }
33
+
34
+ /** SSR / build estático: sem `window` não há URL a ler. O snapshot de servidor é
35
+ * constante de propósito — o primeiro render no cliente reconcilia com a URL real. */
36
+ const SERVER_PATHNAME = '/'
37
+ const SERVER_SEARCH = ''
38
+
39
+ export interface NavigateOptions {
40
+ /** Troca a entrada corrente (`replaceState`) em vez de empilhar. Para estado que não é
41
+ * história — um rascunho que ganha id no meio do fluxo, um filtro que não merece uma
42
+ * volta do botão "voltar". */
43
+ replace?: boolean
44
+ }
45
+
46
+ /**
47
+ * Navega e notifica. No-op se já estiver exatamente no destino — sem isso, clicar duas
48
+ * vezes no mesmo item empilha entradas idênticas e o "voltar" não sai do lugar.
49
+ *
50
+ * "Exatamente" cobra normalizar: comparar o argumento CRU contra `window.location` erra
51
+ * em duas frentes. O hash — estando em `/a#secao`, `navigate('/a')` pareceria repetido e a
52
+ * âncora nunca sairia. E o encoding — `/relatórios` sai do `location` percent-encodado, e
53
+ * a comparação crua nunca casaria, empilhando uma entrada por clique justamente no caso
54
+ * pt-BR. Resolver os dois lados com `new URL` e comparar `href` resolve as duas.
55
+ *
56
+ * O `path` é da PRÓPRIA origem (ex.: `/settings/users?q=ana`). Passar URL absoluta aqui é
57
+ * erro de uso — validar destino externo é problema de quem recebe input de terceiro
58
+ * (redirect pós-login, por exemplo), não desta função. Comparar `href` (e não só o
59
+ * caminho) preserva isso: destino de outra origem não vira no-op, segue para o
60
+ * `pushState` e estoura lá, que é onde o erro é legível.
61
+ */
62
+ export function navigate(path: string, options?: NavigateOptions): void {
63
+ if (new URL(path, window.location.origin).href === window.location.href) return
64
+ if (options?.replace === true) window.history.replaceState(null, '', path)
65
+ else window.history.pushState(null, '', path)
66
+ // `pushState` não dispara `popstate` — quem muda a URL por código tem que avisar. Um
67
+ // evento (e não uma lista privada) é o que faz host não-migrado continuar acompanhando.
68
+ window.dispatchEvent(new PopStateEvent('popstate'))
69
+ }
70
+
71
+ /** O pathname como estado reativo. */
72
+ export function usePathname(): string {
73
+ return useSyncExternalStore(
74
+ subscribe,
75
+ () => window.location.pathname,
76
+ () => SERVER_PATHNAME,
77
+ )
78
+ }
79
+
80
+ /** Os segmentos do path: `/settings/users` → `['settings', 'users']`. Vazios caem fora,
81
+ * então `/` e `//` dão `[]`. */
82
+ export function useSegments(): string[] {
83
+ const pathname = usePathname()
84
+ return useMemo(() => pathname.split('/').filter(Boolean), [pathname])
85
+ }
86
+
87
+ /** A querystring como estado reativo — o lar natural do estado interno de uma seção
88
+ * (qual relatório está aberto, o recorte de uma lista). */
89
+ export function useSearchParams(): URLSearchParams {
90
+ const search = useSyncExternalStore(
91
+ subscribe,
92
+ () => window.location.search,
93
+ () => SERVER_SEARCH,
94
+ )
95
+ return useMemo(() => new URLSearchParams(search), [search])
96
+ }
@@ -0,0 +1,234 @@
1
+ /**
2
+ * Tema canônico do Opus (Tailwind v4, CSS-first). É o ENTRY de CSS da UI:
3
+ * importa o Tailwind + o tw-animate + define os tokens (cor inteira na var) e mapeia
4
+ * pro Tailwind via `@theme inline`. O app faz `@import '@softize/opus/ui/theme.css'`
5
+ * + um `@source` pros componentes do Opus (monorepo), e sobrescreve vars pra identidade.
6
+ *
7
+ * ── DIVERGÊNCIAS DECLARADAS vs shadcn upstream (regra: o que não está aqui é DRIFT
8
+ * e deve ser sincronizado; ver skill `shadcn-ui`) ─────────────────────────────────
9
+ * 1. Formato HSL nos tokens (upstream migrou pra oklch) — legibilidade/ferramentas
10
+ * nossas; os VALORES acompanham o upstream, só o formato difere.
11
+ * 2. Elevação dark: --card/--popover ACIMA de --background (10% vs 3.9%) — identidade
12
+ * da casa (upstream v4 também elevou; calibramos pelo site deles em 2026-06).
13
+ * 3. Radius mapeado (sm/md/lg/xl em @theme inline) preservando o sentido pré-v4 dos
14
+ * utilitários `rounded-*` — neutraliza o rename do v4.
15
+ * (A antiga nº 4 — escala shadow-* sobrescrita — foi APOSENTADA: a elevação da casa
16
+ * vive em namespace próprio, shadow-card/popover/dialog + ring-edge, sem tocar os
17
+ * defaults do Tailwind.)
18
+ * 5. Bordas mais leves no light: --border/--input em 92.5% (upstream 89.8%) — par do
19
+ * canvas quase-branco; a aresta de superfície elevada já é o ring-edge.
20
+ * Tudo o mais (escala neutra, radius base 0.625rem, semânticas) segue o upstream.
21
+ */
22
+ @import 'tailwindcss';
23
+ @import 'tw-animate-css';
24
+ @plugin '@tailwindcss/typography';
25
+
26
+ /* dark por classe (v4 é CSS-first) */
27
+ @custom-variant dark (&:is(.dark *));
28
+
29
+ :root {
30
+ /* Elevação POR PAPEL (par do bg-card/bg-popover): família Notion — camada curta +
31
+ longa, tinte 25/25/25 — e a ARESTA (--edge-value): o anel hairline que SUBSTITUI a
32
+ borda em superfície elevada (ring-1 ring-edge). Papel novo = token novo; os
33
+ defaults shadow-* do Tailwind ficam INTACTOS (sem pegadinha). */
34
+ --edge-value: rgba(42, 28, 0, 0.07);
35
+ --elevation-card: 0 1px 2px rgba(25, 25, 25, 0.027), 0 3px 6px rgba(25, 25, 25, 0.05);
36
+ --elevation-popover: 0 5px 8px rgba(25, 25, 25, 0.027), 0 20px 24px rgba(25, 25, 25, 0.05);
37
+ --elevation-dialog: 0 4px 8px rgba(25, 25, 25, 0.03), 0 16px 24px rgba(25, 25, 25, 0.06);
38
+
39
+ /* Scrollbars e controles NATIVOS (date picker, autofill…) seguem o tema — sem
40
+ isto o browser assume light e pinta scrollbar branca no dark. */
41
+ color-scheme: light;
42
+ --background: hsl(0 0% 100%);
43
+ --foreground: hsl(0 0% 3.9%);
44
+ --card: hsl(0 0% 100%);
45
+ --card-foreground: hsl(0 0% 3.9%);
46
+ --popover: hsl(0 0% 100%);
47
+ --popover-foreground: hsl(0 0% 3.9%);
48
+ --primary: hsl(0 0% 9%);
49
+ --primary-foreground: hsl(0 0% 98%);
50
+ --secondary: hsl(0 0% 96.1%);
51
+ --secondary-foreground: hsl(0 0% 9%);
52
+ --muted: hsl(0 0% 96.1%);
53
+ --muted-foreground: hsl(0 0% 45.1%);
54
+ --accent: hsl(0 0% 96.1%);
55
+ --accent-foreground: hsl(0 0% 9%);
56
+ --destructive: hsl(0 84.2% 60.2%);
57
+ --destructive-foreground: hsl(0 0% 98%);
58
+ --border: hsl(0 0% 92.5%);
59
+ --input: hsl(0 0% 92.5%);
60
+ /* Ring de foco LEVE (pedido da casa): aro sutil, não um halo. Com ring-[3px] + /50,
61
+ ~86% encosta na borda (89.8%) — um sussurro de foco. */
62
+ --ring: hsl(0 0% 86%);
63
+ --radius: 0.625rem;
64
+ }
65
+
66
+ .dark {
67
+ --edge-value: rgba(255, 255, 255, 0.06);
68
+ --elevation-card: 0 1px 2px rgba(0, 0, 0, 0.16), 0 3px 6px rgba(0, 0, 0, 0.28);
69
+ --elevation-popover: 0 5px 8px rgba(0, 0, 0, 0.16), 0 20px 24px rgba(0, 0, 0, 0.3);
70
+ --elevation-dialog: 0 4px 8px rgba(0, 0, 0, 0.2), 0 16px 24px rgba(0, 0, 0, 0.35);
71
+ color-scheme: dark;
72
+ --background: hsl(0 0% 3.9%);
73
+ --foreground: hsl(0 0% 98%);
74
+ /* Elevação com contraste de verdade (dialog/card "sobem" da página, como no site
75
+ do shadcn): superfície ~10% sobre fundo 3.9%, borda um ponto acima pra definir. */
76
+ --card: hsl(0 0% 10%);
77
+ --card-foreground: hsl(0 0% 98%);
78
+ --popover: hsl(0 0% 10%);
79
+ --popover-foreground: hsl(0 0% 98%);
80
+ --primary: hsl(0 0% 98%);
81
+ --primary-foreground: hsl(0 0% 9%);
82
+ --secondary: hsl(0 0% 14.9%);
83
+ --secondary-foreground: hsl(0 0% 98%);
84
+ --muted: hsl(0 0% 14.9%);
85
+ --muted-foreground: hsl(0 0% 63.9%);
86
+ --accent: hsl(0 0% 14.9%);
87
+ --accent-foreground: hsl(0 0% 98%);
88
+ /* Vermelho CLARO no escuro (era 30.6% — calibrado só pra FUNDO, com texto branco).
89
+ Como o menu/alert/field/erros usam `text-destructive` como FOREGROUND, o valor
90
+ escuro dava ~1,7:1 sobre o popover — ilegível. ~58% passa o AA como texto e é o
91
+ que o success já fazia (dark:text-emerald-400 pula pro tom claro). Fundo sólido
92
+ (Button/Badge/toast destructive) fica mais vivo — igual ao light, com branco por
93
+ cima, como o shadcn novo. */
94
+ --destructive: hsl(0 72% 58%);
95
+ --destructive-foreground: hsl(0 0% 98%);
96
+ --border: hsl(0 0% 16.5%);
97
+ --input: hsl(0 0% 16.5%);
98
+ /* No escuro o 83.1% virava um halo quase branco; ~36% marca o foco sem brilhar. */
99
+ --ring: hsl(0 0% 36%);
100
+ }
101
+
102
+ /* Syntax highlighting (CodeBlock via prism-react-renderer): paleta calma mapeada por CSS
103
+ var — o prism theme referencia estes vars, então light/dark troca sozinho pelo cascade. */
104
+ :root {
105
+ --code-fg: hsl(0 0% 25%);
106
+ --code-comment: hsl(0 0% 55%);
107
+ --code-keyword: hsl(265 50% 47%);
108
+ --code-string: hsl(140 45% 32%);
109
+ --code-function: hsl(210 65% 45%);
110
+ --code-number: hsl(25 75% 45%);
111
+ --code-class: hsl(190 50% 35%);
112
+ --code-property: hsl(210 55% 42%);
113
+ --code-punctuation: hsl(0 0% 45%);
114
+ }
115
+
116
+ .dark {
117
+ --code-fg: hsl(0 0% 85%);
118
+ --code-comment: hsl(0 0% 50%);
119
+ --code-keyword: hsl(265 70% 78%);
120
+ --code-string: hsl(140 45% 68%);
121
+ --code-function: hsl(210 70% 72%);
122
+ --code-number: hsl(30 80% 70%);
123
+ --code-class: hsl(180 50% 68%);
124
+ --code-property: hsl(195 60% 72%);
125
+ --code-punctuation: hsl(0 0% 60%);
126
+ }
127
+
128
+ @theme inline {
129
+ --color-background: var(--background);
130
+ --color-foreground: var(--foreground);
131
+ --color-card: var(--card);
132
+ --color-card-foreground: var(--card-foreground);
133
+ --color-popover: var(--popover);
134
+ --color-popover-foreground: var(--popover-foreground);
135
+ --color-primary: var(--primary);
136
+ --color-primary-foreground: var(--primary-foreground);
137
+ --color-secondary: var(--secondary);
138
+ --color-secondary-foreground: var(--secondary-foreground);
139
+ --color-muted: var(--muted);
140
+ --color-muted-foreground: var(--muted-foreground);
141
+ --color-accent: var(--accent);
142
+ --color-accent-foreground: var(--accent-foreground);
143
+ --color-destructive: var(--destructive);
144
+ --color-destructive-foreground: var(--destructive-foreground);
145
+ --color-border: var(--border);
146
+ --color-input: var(--input);
147
+ --color-ring: var(--ring);
148
+
149
+ --radius-sm: calc(var(--radius) - 4px);
150
+ --radius-md: calc(var(--radius) - 2px);
151
+ --radius-lg: var(--radius);
152
+ --radius-xl: calc(var(--radius) + 4px);
153
+
154
+ /* Forma por papel (rounded-card/popover/dialog) — o papel de superfície carrega cor
155
+ (bg-*), elevação (shadow-*) E forma. Derivados de --radius: a identidade por app
156
+ (sobrescrever --radius) escala os papéis junto. Controles ficam na escala sm–xl. */
157
+ --radius-card: calc(var(--radius) + 6px);
158
+ --radius-popover: calc(var(--radius) - 2px);
159
+ --radius-dialog: calc(var(--radius) + 6px);
160
+
161
+ /* Elevação por papel (utilitários shadow-card/popover/dialog + ring-edge/border-edge)
162
+ — namespace PRÓPRIO: os shadow-* default do Tailwind seguem intactos. Superfície
163
+ elevada usa `ring-1 ring-edge` NO LUGAR de border (não combine os dois). */
164
+ --shadow-card: var(--elevation-card);
165
+ --shadow-popover: var(--elevation-popover);
166
+ --shadow-dialog: var(--elevation-dialog);
167
+ --color-edge: var(--edge-value);
168
+ }
169
+
170
+ /* Base canônica do consumidor — vem DAQUI, não do entry de cada app. Tailwind v4
171
+ * deixou a borda default em currentColor (preta): o reset aponta pro token (é o
172
+ * globals.css do shadcn). App que ainda tiver a cópia local: redundante, inofensivo. */
173
+ @layer base {
174
+ * {
175
+ border-color: var(--border);
176
+ }
177
+ /* Base 15px: o rem da casa — TODA a escala rem (texto, spacing, radius) deriva daqui,
178
+ então a UI densifica ~6% vs o default do browser (16px). Histórico (conferido no git):
179
+ até a 2.31.4 o pacote NÃO fixava rem (valia o 16px do browser); a 2.31.5 introduziu
180
+ 14px; a 2.35.0 assenta em 15px — valor INÉDITO, não é revert. O 15px veio da prática:
181
+ a Empresa X escolheu 15px por conta própria em DOIS apps, e a exceção reincidente
182
+ virou default. Quem quiser mais denso sobrescreve o `html` no próprio entry. */
183
+ html {
184
+ font-size: 15px;
185
+ }
186
+ /* Canvas da casa: quase-branco vem do BODY — o shell é transparente e as
187
+ superfícies (cards, miolo flush) pintam bg-background por cima. Tinte de 25%
188
+ de muted: separa a superfície do canvas sem virar cinza; segue o tema. */
189
+ body {
190
+ background-color: color-mix(in oklab, var(--muted) 25%, var(--background));
191
+ }
192
+ }
193
+
194
+ /* Markdown (componente `prose`) segue os tokens da casa — light/dark sozinho via as vars
195
+ (que já viram no `.dark`), então dispensa o `prose-invert`. O corpo é muted (como era na
196
+ versão à mão); headings/bold no foreground; bordas/regras no --border. */
197
+ .prose {
198
+ --tw-prose-body: var(--muted-foreground);
199
+ --tw-prose-headings: var(--foreground);
200
+ --tw-prose-lead: var(--muted-foreground);
201
+ --tw-prose-links: var(--foreground);
202
+ --tw-prose-bold: var(--foreground);
203
+ --tw-prose-counters: var(--muted-foreground);
204
+ --tw-prose-bullets: var(--border);
205
+ --tw-prose-hr: var(--border);
206
+ --tw-prose-quotes: var(--muted-foreground);
207
+ --tw-prose-quote-borders: var(--border);
208
+ --tw-prose-captions: var(--muted-foreground);
209
+ --tw-prose-code: var(--foreground);
210
+ --tw-prose-pre-code: var(--code-fg);
211
+ --tw-prose-pre-bg: var(--muted);
212
+ --tw-prose-th-borders: var(--border);
213
+ --tw-prose-td-borders: var(--border);
214
+ }
215
+
216
+ /* Code inline = chip da casa (bg-muted), sem as aspas que o prose injeta.
217
+ * O guard [class~='not-prose'] espelha o escopo do plugin typography: sem ele a
218
+ * regra custom vaza pra dentro do not-prose (o CodeBlock ganhava uma SEGUNDA
219
+ * borda no <pre>, colada na do contêiner — a "borda duplicada"). */
220
+ .prose :where(code):not(:where(pre code, [class~='not-prose'], [class~='not-prose'] *)) {
221
+ border-radius: calc(var(--radius) - 4px);
222
+ background: var(--muted);
223
+ padding: 0.125rem 0.375rem;
224
+ font-weight: 400;
225
+ }
226
+ .prose :where(code):not(:where(pre code, [class~='not-prose'], [class~='not-prose'] *))::before,
227
+ .prose :where(code):not(:where(pre code, [class~='not-prose'], [class~='not-prose'] *))::after {
228
+ content: none;
229
+ }
230
+
231
+ /* Code block = superfície da casa (borda + bg muted) — só o <pre> CRU do prose. */
232
+ .prose :where(pre):not(:where([class~='not-prose'], [class~='not-prose'] *)) {
233
+ border: 1px solid var(--border);
234
+ }