velloo 0.0.0 → 0.2.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.
Files changed (267) hide show
  1. package/BUN-LICENSE.md +91 -0
  2. package/LICENSE +202 -0
  3. package/NOTICE +9 -0
  4. package/README.md +288 -2
  5. package/THIRD-PARTY-NOTICES.md +467 -0
  6. package/assets/elsewhere-alps-9fqhv029.jpg +0 -0
  7. package/assets/elsewhere-bali-vp60g115.jpg +0 -0
  8. package/assets/elsewhere-forest-xgn23zrj.jpg +0 -0
  9. package/assets/elsewhere-japan-qs7qkbr2.jpg +0 -0
  10. package/assets/elsewhere-kyoto-map-n2bvkrya.svg +1 -0
  11. package/assets/elsewhere-kyoto-qemtn6nk.jpg +0 -0
  12. package/assets/elsewhere-room-g1gaw7cs.jpg +0 -0
  13. package/canvas/apple-touch-icon.png +0 -0
  14. package/canvas/assets/index-BCvDZiBo.css +2 -0
  15. package/canvas/assets/index-ClaBqcaS.js +28 -0
  16. package/canvas/assets/lucide-all-iIF-pmzN.js +1 -0
  17. package/canvas/assets/radix-C3HaOB-d.js +41 -0
  18. package/canvas/assets/react-D0Ec-185.js +9 -0
  19. package/canvas/assets/rolldown-runtime-hePW80VL.js +1 -0
  20. package/canvas/assets/vendor-CKmQ-Zst.js +53 -0
  21. package/canvas/favicon.ico +0 -0
  22. package/canvas/favicon.svg +12 -0
  23. package/canvas/fonts/OFL-1.1.txt +93 -0
  24. package/canvas/fonts/poppins-700.woff2 +0 -0
  25. package/canvas/icon-192.png +0 -0
  26. package/canvas/icon-512.png +0 -0
  27. package/canvas/index.html +22 -0
  28. package/canvas/site.webmanifest +11 -0
  29. package/chunk-08sv3k41.js +4 -0
  30. package/chunk-0fe83yzt.js +2 -0
  31. package/chunk-0t68szgr.js +3 -0
  32. package/chunk-1h55s5he.js +2 -0
  33. package/chunk-2c7jbx46.js +2 -0
  34. package/chunk-2smsg2ct.js +7 -0
  35. package/chunk-308ynsxd.js +2 -0
  36. package/chunk-3e8vez4d.js +1229 -0
  37. package/chunk-40xgcth8.js +63 -0
  38. package/chunk-4dn75m6t.js +3 -0
  39. package/chunk-4fj5tahv.js +3 -0
  40. package/chunk-6nqghjda.js +3 -0
  41. package/chunk-6tx68d90.js +3 -0
  42. package/chunk-6w6ch4ce.js +2 -0
  43. package/chunk-735ezz23.js +86 -0
  44. package/chunk-7eq7nx37.js +7 -0
  45. package/chunk-7eyb8yrf.js +6 -0
  46. package/chunk-80fjfyha.js +86 -0
  47. package/chunk-80r93t2e.js +4 -0
  48. package/chunk-94vx1yb0.js +3 -0
  49. package/chunk-9vg3yafz.js +3 -0
  50. package/chunk-a84n72m2.js +4 -0
  51. package/chunk-ampmdzz4.js +10 -0
  52. package/chunk-avns4dbf.js +2 -0
  53. package/chunk-ayrb3qnm.js +3 -0
  54. package/chunk-bwnvcncx.js +3 -0
  55. package/chunk-ccszg02q.js +5 -0
  56. package/chunk-cvn689d5.js +3 -0
  57. package/chunk-cxe6jjwj.js +3 -0
  58. package/chunk-dg6z4vdd.js +3 -0
  59. package/chunk-dgwjpbp9.js +3 -0
  60. package/chunk-dy41n60j.js +52 -0
  61. package/chunk-ek71z2fv.js +226 -0
  62. package/chunk-er1fxb7d.js +2 -0
  63. package/chunk-eyr8hrzf.js +2 -0
  64. package/chunk-fjbzk4sw.js +3 -0
  65. package/chunk-fsbsksga.js +3 -0
  66. package/chunk-h6gchare.js +3 -0
  67. package/chunk-hcb68zt7.js +85 -0
  68. package/chunk-hggap8fq.js +3 -0
  69. package/chunk-j11fyeqh.js +2 -0
  70. package/chunk-jb21jkp1.js +8 -0
  71. package/chunk-jfx9xjmr.js +18 -0
  72. package/chunk-jr0ss0mm.js +303 -0
  73. package/chunk-jrsknzjt.js +3 -0
  74. package/chunk-jv0xggh0.js +2 -0
  75. package/chunk-k17gfwq3.js +2 -0
  76. package/chunk-mh2pr7cq.js +5 -0
  77. package/chunk-mnapdp1y.js +2 -0
  78. package/chunk-mzhdrawd.js +3 -0
  79. package/chunk-n9gs6yx9.js +2 -0
  80. package/chunk-ngnymg2q.js +3 -0
  81. package/chunk-nwx5700b.js +3 -0
  82. package/chunk-pjtg3wnm.js +4 -0
  83. package/chunk-pp86v6m6.js +3 -0
  84. package/chunk-r22epxz2.js +3 -0
  85. package/chunk-rgasy862.js +5 -0
  86. package/chunk-rpwpeph5.js +3 -0
  87. package/chunk-s23gtejf.js +3 -0
  88. package/chunk-sjgqnykd.js +6 -0
  89. package/chunk-sn3x2m0m.js +6 -0
  90. package/chunk-t448rrfr.js +2 -0
  91. package/chunk-tdsk5wxa.js +451 -0
  92. package/chunk-v40fn08f.js +442 -0
  93. package/chunk-vbk1qhdz.js +3 -0
  94. package/chunk-vdkrbzh1.js +2 -0
  95. package/chunk-vgmr98cv.js +40 -0
  96. package/chunk-vsv8z729.js +6 -0
  97. package/chunk-x4f4k9pp.js +26 -0
  98. package/chunk-xt5ayg7g.js +4 -0
  99. package/chunk-ydhwv29b.js +244 -0
  100. package/chunk-zb6hc1y0.js +2 -0
  101. package/cli.js +3 -0
  102. package/launcher.cjs +97 -0
  103. package/package.json +58 -5
  104. package/pkgs/helpers/src/box.tsx +21 -0
  105. package/pkgs/helpers/src/cn.ts +32 -0
  106. package/pkgs/helpers/src/descriptors.ts +270 -0
  107. package/pkgs/helpers/src/divider.tsx +123 -0
  108. package/pkgs/helpers/src/gradient.tsx +90 -0
  109. package/pkgs/helpers/src/heading.tsx +20 -0
  110. package/pkgs/helpers/src/icon-data.ts +8009 -0
  111. package/pkgs/helpers/src/icon.tsx +53 -0
  112. package/pkgs/helpers/src/image.tsx +111 -0
  113. package/pkgs/helpers/src/index.ts +29 -0
  114. package/pkgs/helpers/src/layer.tsx +61 -0
  115. package/pkgs/helpers/src/lowering.ts +53 -0
  116. package/pkgs/helpers/src/paths.ts +47 -0
  117. package/pkgs/helpers/src/placeholder.tsx +88 -0
  118. package/pkgs/helpers/src/prose.tsx +42 -0
  119. package/pkgs/helpers/src/registry.ts +41 -0
  120. package/pkgs/helpers/src/svg.tsx +62 -0
  121. package/pkgs/helpers/src/text.tsx +16 -0
  122. package/pkgs/provider-antd/src/index.ts +78 -0
  123. package/pkgs/provider-antd/src/intro.ts +14 -0
  124. package/pkgs/provider-antd/src/manifest.ts +439 -0
  125. package/pkgs/provider-antd/src/overlays.ts +176 -0
  126. package/pkgs/provider-antd/src/registry.ts +104 -0
  127. package/pkgs/provider-antd/src/render-pass.ts +43 -0
  128. package/pkgs/provider-antd/src/tailwind-entry.css +21 -0
  129. package/pkgs/provider-antd/src/theme.ts +132 -0
  130. package/pkgs/provider-antd/src/version.ts +8 -0
  131. package/pkgs/provider-chakra/src/index.ts +80 -0
  132. package/pkgs/provider-chakra/src/intro.ts +14 -0
  133. package/pkgs/provider-chakra/src/manifest.ts +421 -0
  134. package/pkgs/provider-chakra/src/overlays.ts +246 -0
  135. package/pkgs/provider-chakra/src/registry.ts +227 -0
  136. package/pkgs/provider-chakra/src/render-pass.ts +55 -0
  137. package/pkgs/provider-chakra/src/tailwind-entry.css +21 -0
  138. package/pkgs/provider-chakra/src/theme.ts +180 -0
  139. package/pkgs/provider-chakra/src/version.ts +8 -0
  140. package/pkgs/provider-mui/src/index.ts +117 -0
  141. package/pkgs/provider-mui/src/intro.ts +12 -0
  142. package/pkgs/provider-mui/src/manifest.ts +263 -0
  143. package/pkgs/provider-mui/src/overlays.ts +124 -0
  144. package/pkgs/provider-mui/src/registry.ts +120 -0
  145. package/pkgs/provider-mui/src/render-pass.ts +36 -0
  146. package/pkgs/provider-mui/src/tailwind-entry.css +21 -0
  147. package/pkgs/provider-mui/src/theme.ts +129 -0
  148. package/pkgs/provider-mui/src/version.ts +8 -0
  149. package/pkgs/provider-none/src/components-inline.tsx +204 -0
  150. package/pkgs/provider-none/src/components.tsx +155 -0
  151. package/pkgs/provider-none/src/index.ts +57 -0
  152. package/pkgs/provider-none/src/intro.ts +18 -0
  153. package/pkgs/provider-none/src/manifest.ts +163 -0
  154. package/pkgs/provider-none/src/registry-inline.ts +36 -0
  155. package/pkgs/provider-none/src/registry.ts +39 -0
  156. package/pkgs/provider-none/src/tailwind-entry.css +57 -0
  157. package/pkgs/provider-none/src/version.ts +10 -0
  158. package/pkgs/schema/src/annotation.ts +120 -0
  159. package/pkgs/schema/src/asset.ts +66 -0
  160. package/pkgs/schema/src/board.ts +71 -0
  161. package/pkgs/schema/src/comment.ts +107 -0
  162. package/pkgs/schema/src/config.ts +185 -0
  163. package/pkgs/schema/src/css-sanitize.ts +56 -0
  164. package/pkgs/schema/src/extension.ts +105 -0
  165. package/pkgs/schema/src/fonts.ts +690 -0
  166. package/pkgs/schema/src/frame.ts +40 -0
  167. package/pkgs/schema/src/icon-name.ts +21 -0
  168. package/pkgs/schema/src/ids.ts +14 -0
  169. package/pkgs/schema/src/index.ts +169 -0
  170. package/pkgs/schema/src/migrate.ts +297 -0
  171. package/pkgs/schema/src/node.ts +229 -0
  172. package/pkgs/schema/src/paths.ts +28 -0
  173. package/pkgs/schema/src/repo.ts +134 -0
  174. package/pkgs/schema/src/screen.ts +30 -0
  175. package/pkgs/schema/src/snippet-resolve.ts +193 -0
  176. package/pkgs/schema/src/snippet.ts +104 -0
  177. package/pkgs/schema/src/svg-sanitize.ts +487 -0
  178. package/pkgs/schema/src/theme.ts +218 -0
  179. package/pkgs/schema/src/typeset.ts +693 -0
  180. package/pkgs/schema/src/validate-ids.ts +46 -0
  181. package/pkgs/schema/src/viewport.ts +8 -0
  182. package/pkgs/shadcn-snapshot/dist/manifest.json +8109 -0
  183. package/pkgs/shadcn-snapshot/src/components/canvas-portal.tsx +55 -0
  184. package/pkgs/shadcn-snapshot/src/components/ui/accordion.tsx +122 -0
  185. package/pkgs/shadcn-snapshot/src/components/ui/alert-dialog.tsx +164 -0
  186. package/pkgs/shadcn-snapshot/src/components/ui/alert.tsx +74 -0
  187. package/pkgs/shadcn-snapshot/src/components/ui/aspect-ratio.tsx +13 -0
  188. package/pkgs/shadcn-snapshot/src/components/ui/attachment.tsx +197 -0
  189. package/pkgs/shadcn-snapshot/src/components/ui/avatar.tsx +100 -0
  190. package/pkgs/shadcn-snapshot/src/components/ui/badge.tsx +50 -0
  191. package/pkgs/shadcn-snapshot/src/components/ui/breadcrumb.tsx +109 -0
  192. package/pkgs/shadcn-snapshot/src/components/ui/bubble.tsx +130 -0
  193. package/pkgs/shadcn-snapshot/src/components/ui/button-group.tsx +82 -0
  194. package/pkgs/shadcn-snapshot/src/components/ui/button.tsx +72 -0
  195. package/pkgs/shadcn-snapshot/src/components/ui/calendar.tsx +229 -0
  196. package/pkgs/shadcn-snapshot/src/components/ui/card.tsx +92 -0
  197. package/pkgs/shadcn-snapshot/src/components/ui/carousel.tsx +235 -0
  198. package/pkgs/shadcn-snapshot/src/components/ui/chart-option.ts +250 -0
  199. package/pkgs/shadcn-snapshot/src/components/ui/chart.tsx +177 -0
  200. package/pkgs/shadcn-snapshot/src/components/ui/checkbox.tsx +41 -0
  201. package/pkgs/shadcn-snapshot/src/components/ui/collapsible.tsx +32 -0
  202. package/pkgs/shadcn-snapshot/src/components/ui/combobox.tsx +196 -0
  203. package/pkgs/shadcn-snapshot/src/components/ui/context-menu.tsx +227 -0
  204. package/pkgs/shadcn-snapshot/src/components/ui/dialog.tsx +131 -0
  205. package/pkgs/shadcn-snapshot/src/components/ui/direction.tsx +24 -0
  206. package/pkgs/shadcn-snapshot/src/components/ui/drawer.tsx +112 -0
  207. package/pkgs/shadcn-snapshot/src/components/ui/dropdown-menu.tsx +205 -0
  208. package/pkgs/shadcn-snapshot/src/components/ui/empty.tsx +98 -0
  209. package/pkgs/shadcn-snapshot/src/components/ui/field.tsx +228 -0
  210. package/pkgs/shadcn-snapshot/src/components/ui/hover-card.tsx +51 -0
  211. package/pkgs/shadcn-snapshot/src/components/ui/input-group.tsx +148 -0
  212. package/pkgs/shadcn-snapshot/src/components/ui/input.tsx +43 -0
  213. package/pkgs/shadcn-snapshot/src/components/ui/item.tsx +187 -0
  214. package/pkgs/shadcn-snapshot/src/components/ui/kbd.tsx +30 -0
  215. package/pkgs/shadcn-snapshot/src/components/ui/label.tsx +25 -0
  216. package/pkgs/shadcn-snapshot/src/components/ui/marker.tsx +71 -0
  217. package/pkgs/shadcn-snapshot/src/components/ui/menubar.tsx +243 -0
  218. package/pkgs/shadcn-snapshot/src/components/ui/message.tsx +89 -0
  219. package/pkgs/shadcn-snapshot/src/components/ui/native-select.tsx +60 -0
  220. package/pkgs/shadcn-snapshot/src/components/ui/navigation-menu.tsx +165 -0
  221. package/pkgs/shadcn-snapshot/src/components/ui/pagination.tsx +117 -0
  222. package/pkgs/shadcn-snapshot/src/components/ui/popover.tsx +66 -0
  223. package/pkgs/shadcn-snapshot/src/components/ui/progress.tsx +35 -0
  224. package/pkgs/shadcn-snapshot/src/components/ui/radio-group.tsx +48 -0
  225. package/pkgs/shadcn-snapshot/src/components/ui/scroll-area.tsx +59 -0
  226. package/pkgs/shadcn-snapshot/src/components/ui/select.tsx +180 -0
  227. package/pkgs/shadcn-snapshot/src/components/ui/separator.tsx +32 -0
  228. package/pkgs/shadcn-snapshot/src/components/ui/sheet.tsx +107 -0
  229. package/pkgs/shadcn-snapshot/src/components/ui/skeleton.tsx +17 -0
  230. package/pkgs/shadcn-snapshot/src/components/ui/slider.tsx +68 -0
  231. package/pkgs/shadcn-snapshot/src/components/ui/sonner.tsx +91 -0
  232. package/pkgs/shadcn-snapshot/src/components/ui/spinner.tsx +21 -0
  233. package/pkgs/shadcn-snapshot/src/components/ui/switch.tsx +41 -0
  234. package/pkgs/shadcn-snapshot/src/components/ui/table.tsx +93 -0
  235. package/pkgs/shadcn-snapshot/src/components/ui/tabs.tsx +84 -0
  236. package/pkgs/shadcn-snapshot/src/components/ui/textarea.tsx +24 -0
  237. package/pkgs/shadcn-snapshot/src/components/ui/toggle-group.tsx +94 -0
  238. package/pkgs/shadcn-snapshot/src/components/ui/toggle.tsx +50 -0
  239. package/pkgs/shadcn-snapshot/src/components/ui/tooltip.tsx +47 -0
  240. package/pkgs/shadcn-snapshot/src/examples.ts +36 -0
  241. package/pkgs/shadcn-snapshot/src/groups.ts +87 -0
  242. package/pkgs/shadcn-snapshot/src/index.ts +43 -0
  243. package/pkgs/shadcn-snapshot/src/lib/utils.ts +4 -0
  244. package/pkgs/shadcn-snapshot/src/manifest.ts +12 -0
  245. package/pkgs/shadcn-snapshot/src/notes.ts +97 -0
  246. package/pkgs/shadcn-snapshot/src/paths.ts +47 -0
  247. package/pkgs/shadcn-snapshot/src/registry-files.ts +293 -0
  248. package/pkgs/shadcn-snapshot/src/registry.ts +631 -0
  249. package/pkgs/shadcn-snapshot/src/shadcn-tailwind.css +632 -0
  250. package/pkgs/shadcn-snapshot/src/tailwind-entry.css +159 -0
  251. package/pkgs/shadcn-snapshot/src/version.ts +8 -0
  252. package/plugins/claude/velloo/.claude-plugin/plugin.json +6 -0
  253. package/plugins/claude/velloo/agents/velloo-design-reviewer.md +33 -0
  254. package/plugins/claude/velloo/agents/velloo-designer.md +39 -0
  255. package/plugins/claude/velloo/commands/design.md +11 -0
  256. package/plugins/claude/velloo/commands/implement.md +10 -0
  257. package/plugins/claude/velloo/commands/review.md +8 -0
  258. package/plugins/gemini/GEMINI.md +31 -0
  259. package/plugins/gemini/commands/velloo/design.toml +10 -0
  260. package/plugins/gemini/commands/velloo/implement.toml +9 -0
  261. package/plugins/gemini/gemini-extension.json +9 -0
  262. package/skills/velloo-brand/SKILL.md +124 -0
  263. package/skills/velloo-design/SKILL.md +144 -0
  264. package/skills/velloo-design-system/SKILL.md +90 -0
  265. package/skills/velloo-implement/SKILL.md +101 -0
  266. package/skills/velloo-logo/SKILL.md +93 -0
  267. package/skills/velloo-setup/SKILL.md +156 -0
@@ -0,0 +1,129 @@
1
+ import { createTheme, type Theme as MuiTheme, type ThemeOptions } from "@mui/material/styles";
2
+ import {
3
+ type ColorPair,
4
+ DEFAULT_TYPESET_NAME,
5
+ resolveColors,
6
+ typesetScale,
7
+ type Theme as VellooTheme,
8
+ } from "@velloo/schema";
9
+ import { formatRgb, parse } from "culori";
10
+
11
+ /**
12
+ * MUI's color manipulator (lighten/darken in createPalette) only parses
13
+ * `#hex`, `rgb()/rgba()`, `hsl()/hsla()`, `color()` — NOT `oklch()`, which is
14
+ * exactly what velloo themes store. Convert anything outside MUI's set to
15
+ * `rgb(...)` via culori; pass MUI-native formats through untouched so a hex
16
+ * theme stays hex (and round-trips identically in codegen).
17
+ */
18
+ function muiColor(css: string): string {
19
+ const s = css.trim();
20
+ if (/^(#|rgb|hsl)/i.test(s)) return s;
21
+ return formatRgb(parse(s)) ?? s;
22
+ }
23
+
24
+ /** A color slot is a CSS string or a { DEFAULT, foreground } pair — pull the base color (MUI-safe). */
25
+ function base(slot: ColorPair | undefined, fallback: string): string {
26
+ if (typeof slot === "string") return muiColor(slot);
27
+ if (slot && typeof slot === "object" && typeof slot.DEFAULT === "string")
28
+ return muiColor(slot.DEFAULT);
29
+ return muiColor(fallback);
30
+ }
31
+
32
+ /** The `foreground` half of a pair (the on-color, MUI-safe), or a fallback. */
33
+ function fg(slot: ColorPair | undefined, fallback: string): string {
34
+ if (slot && typeof slot === "object" && typeof slot.foreground === "string")
35
+ return muiColor(slot.foreground);
36
+ return muiColor(fallback);
37
+ }
38
+
39
+ /** MUI's shape.borderRadius is a px number; coerce velloo's radius.md (number or CSS len). */
40
+ function radiusPx(theme: VellooTheme): number {
41
+ const md = (theme.radius as Record<string, unknown> | undefined)?.md;
42
+ if (typeof md === "number") return md;
43
+ if (typeof md === "string") {
44
+ const n = Number.parseFloat(md);
45
+ return Number.isFinite(n) ? (md.includes("rem") ? n * 16 : n) : 8;
46
+ }
47
+ return 8;
48
+ }
49
+
50
+ /**
51
+ * Project velloo's unified token tree onto MUI `ThemeOptions` (the input POJO
52
+ * for `createTheme`) — the adapter's `themeToNative`. This is the SINGLE source
53
+ * of the velloo→MUI mapping: `muiThemeFrom` wraps it for the canvas render
54
+ * pass, and codegen serializes the same POJO to a `createTheme(...)` artifact,
55
+ * so the preview and the emitted theme never diverge. velloo colors are
56
+ * arbitrary CSS strings (oklch/hsl/hex); MUI's palette accepts any CSS color.
57
+ */
58
+ export function muiThemeOptions(theme: VellooTheme, dark = false): ThemeOptions {
59
+ // In dark mode, overlay the theme's dark color slots — otherwise flipping
60
+ // palette.mode to "dark" would keep the light color values.
61
+ const c = resolveColors(theme, dark);
62
+ return {
63
+ palette: {
64
+ mode: dark ? "dark" : "light",
65
+ primary: { main: base(c.primary, "#4f46e5"), contrastText: fg(c.primary, "#ffffff") },
66
+ secondary: { main: base(c.secondary, "#64748b"), contrastText: fg(c.secondary, "#ffffff") },
67
+ error: { main: base(c.destructive, "#dc2626"), contrastText: fg(c.destructive, "#ffffff") },
68
+ background: { default: muiColor(c.background), paper: base(c.card, c.background) },
69
+ text: { primary: muiColor(c.foreground), secondary: base(c.muted, c.foreground) },
70
+ divider: c.border ? muiColor(c.border) : "rgba(0,0,0,0.12)",
71
+ },
72
+ shape: { borderRadius: radiusPx(theme) },
73
+ typography: muiTypography(theme),
74
+ };
75
+ }
76
+
77
+ /**
78
+ * Project the default typeset onto MUI's typography variants.
79
+ *
80
+ * MUI's theme is a serialized POJO — it ends up inside a `createTheme(...)`
81
+ * artifact where no CSS variables exist — so this reads `typesetScale`, the
82
+ * concrete-value form of the same ratio table `typesetCss` uses symbolically.
83
+ * The canvas render pass and the emitted artifact both come through here, so a
84
+ * preview cannot disagree with generated code.
85
+ */
86
+ function muiTypography(theme: VellooTheme): NonNullable<ThemeOptions["typography"]> {
87
+ const typography = theme.typography;
88
+ const typeset = typography.typesets?.[DEFAULT_TYPESET_NAME];
89
+ const scale = typesetScale(typeset, {
90
+ ...(typography.fontFamily ? { fontFamily: typography.fontFamily } : {}),
91
+ });
92
+ // The body face, falling back to the `sans` role then the system stack.
93
+ const bodyFamily =
94
+ scale.body.fontFamily ?? typography.fontFamily?.sans ?? "system-ui, -apple-system, sans-serif";
95
+
96
+ const variant = (role: keyof typeof scale) => {
97
+ const r = scale[role];
98
+ return {
99
+ // Only override the family when the typeset names a *different* face for
100
+ // this role; otherwise inherit the theme's own fontFamily.
101
+ ...(r.fontFamily && r.fontFamily !== bodyFamily ? { fontFamily: r.fontFamily } : {}),
102
+ fontSize: `${r.fontSize}px`,
103
+ lineHeight: r.lineHeight,
104
+ letterSpacing: r.letterSpacing,
105
+ fontWeight: r.fontWeight,
106
+ };
107
+ };
108
+
109
+ return {
110
+ fontFamily: bodyFamily,
111
+ fontSize: scale.body.fontSize,
112
+ h1: variant("h1"),
113
+ h2: variant("h2"),
114
+ h3: variant("h3"),
115
+ h4: variant("h4"),
116
+ h5: variant("h5"),
117
+ h6: variant("h6"),
118
+ subtitle1: variant("lead"),
119
+ subtitle2: variant("small"),
120
+ body1: variant("body"),
121
+ body2: variant("caption"),
122
+ caption: variant("caption"),
123
+ };
124
+ }
125
+
126
+ /** The MUI `Theme` for the render pass — `createTheme` over {@link muiThemeOptions}. */
127
+ export function muiThemeFrom(theme: VellooTheme, dark = false): MuiTheme {
128
+ return createTheme(muiThemeOptions(theme, dark));
129
+ }
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Lives in its own module (exported as `@velloo/provider-mui/version`) so
3
+ * version-only consumers — the CLI init wizard — don't pull the provider's
4
+ * registry (and with it all of @mui/material) into their import graph. The
5
+ * bundled CLI lazy-loads the full provider per folder config; see
6
+ * `packages/server/src/providers.ts`.
7
+ */
8
+ export const MUI_VERSION = "6" as const;
@@ -0,0 +1,204 @@
1
+ import { headingInlineStyle, textInlineStyle } from "@velloo/schema/typeset";
2
+ import * as React from "react";
3
+ import type { ButtonProps, ContainerProps, InputProps, StackProps } from "./components.tsx";
4
+
5
+ /**
6
+ * Inline-styled variants of the no-library primitives, for a `none`-CSS folder
7
+ * (`config.styling.framework === "none"`). Identical props + structural defaults
8
+ * to the Tailwind set in `components.tsx`, but every default is a plain `style`
9
+ * object instead of a Tailwind class — so they paint with the JIT off. Theme
10
+ * tokens reach them as the CSS variables `themeToCss` injects
11
+ * (`var(--color-foreground)`, `var(--radius)`, …), so a `none/none` folder still
12
+ * themes. The node's authored `style` (set via `update_props`) merges last and wins.
13
+ *
14
+ * Typography is the same story one level deeper: Heading/Text reference the
15
+ * typeset's `var(--text-*)` / `var(--leading-*)` tokens rather than hardcoded
16
+ * rem values, so a `none/none` folder's type follows its typeset — and moves
17
+ * live when one changes — exactly like every other channel.
18
+ */
19
+
20
+ /** Merge structural defaults with the node's authored inline style (author wins). */
21
+ function merge(
22
+ defaults: React.CSSProperties,
23
+ authored: React.CSSProperties | undefined,
24
+ ): React.CSSProperties {
25
+ return authored ? { ...defaults, ...authored } : defaults;
26
+ }
27
+
28
+ /** Tailwind's spacing scale is 0.25rem per step (gap-4 ⇒ 1rem). */
29
+ const space = (n: number) => `${n * 0.25}rem`;
30
+
31
+ export const Box = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(
32
+ ({ style, ...rest }, ref) => <div ref={ref} style={style} {...rest} />,
33
+ );
34
+ Box.displayName = "Box";
35
+
36
+ const alignStyle: Record<NonNullable<StackProps["align"]>, string> = {
37
+ start: "flex-start",
38
+ center: "center",
39
+ end: "flex-end",
40
+ stretch: "stretch",
41
+ };
42
+ const justifyStyle: Record<NonNullable<StackProps["justify"]>, string> = {
43
+ start: "flex-start",
44
+ center: "center",
45
+ end: "flex-end",
46
+ between: "space-between",
47
+ around: "space-around",
48
+ };
49
+
50
+ export const Stack = React.forwardRef<HTMLDivElement, StackProps>(
51
+ ({ direction = "col", gap = 4, align, justify, style, ...rest }, ref) => (
52
+ <div
53
+ ref={ref}
54
+ style={merge(
55
+ {
56
+ display: "flex",
57
+ flexDirection: direction === "row" ? "row" : "column",
58
+ gap: space(gap),
59
+ ...(align ? { alignItems: alignStyle[align] } : {}),
60
+ ...(justify ? { justifyContent: justifyStyle[justify] } : {}),
61
+ },
62
+ style,
63
+ )}
64
+ {...rest}
65
+ />
66
+ ),
67
+ );
68
+ Stack.displayName = "Stack";
69
+
70
+ const containerMaxWidth: Record<NonNullable<ContainerProps["size"]>, string> = {
71
+ sm: "640px",
72
+ md: "768px",
73
+ lg: "1024px",
74
+ xl: "1280px",
75
+ full: "100%",
76
+ };
77
+
78
+ export const Container = React.forwardRef<HTMLDivElement, ContainerProps>(
79
+ ({ size = "md", style, ...rest }, ref) => (
80
+ <div
81
+ ref={ref}
82
+ style={merge(
83
+ {
84
+ marginInline: "auto",
85
+ width: "100%",
86
+ paddingInline: "1rem",
87
+ maxWidth: containerMaxWidth[size],
88
+ },
89
+ style,
90
+ )}
91
+ {...rest}
92
+ />
93
+ ),
94
+ );
95
+ Container.displayName = "Container";
96
+
97
+ const buttonVariantStyle: Record<NonNullable<ButtonProps["variant"]>, React.CSSProperties> = {
98
+ default: { background: "var(--color-foreground)", color: "var(--color-background)" },
99
+ ghost: { background: "transparent", color: "var(--color-foreground)" },
100
+ outline: {
101
+ background: "transparent",
102
+ color: "var(--color-foreground)",
103
+ border: "1px solid var(--color-border)",
104
+ },
105
+ };
106
+
107
+ export const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
108
+ ({ variant = "default", type, style, ...rest }, ref) => (
109
+ <button
110
+ ref={ref}
111
+ type={type ?? "button"}
112
+ style={merge(
113
+ {
114
+ display: "inline-flex",
115
+ alignItems: "center",
116
+ justifyContent: "center",
117
+ gap: "0.5rem",
118
+ borderRadius: "var(--radius)",
119
+ padding: "0.5rem 1rem",
120
+ fontSize: "0.875rem",
121
+ fontWeight: 500,
122
+ cursor: "pointer",
123
+ ...buttonVariantStyle[variant],
124
+ },
125
+ style,
126
+ )}
127
+ {...rest}
128
+ />
129
+ ),
130
+ );
131
+ Button.displayName = "Button";
132
+
133
+ export const Input = React.forwardRef<HTMLInputElement, InputProps>(
134
+ ({ type = "text", value, onChange, style, ...rest }, ref) => {
135
+ const isStatic = value !== undefined && onChange === undefined;
136
+ return (
137
+ <input
138
+ ref={ref}
139
+ type={type}
140
+ value={value}
141
+ onChange={onChange}
142
+ readOnly={isStatic || rest.readOnly}
143
+ style={merge(
144
+ {
145
+ display: "block",
146
+ width: "100%",
147
+ borderRadius: "var(--radius)",
148
+ border: "1px solid var(--color-input)",
149
+ background: "var(--color-background)",
150
+ padding: "0.5rem 0.75rem",
151
+ fontSize: "0.875rem",
152
+ },
153
+ style,
154
+ )}
155
+ {...rest}
156
+ />
157
+ );
158
+ },
159
+ );
160
+ Input.displayName = "Input";
161
+
162
+ export const Card = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(
163
+ ({ style, ...rest }, ref) => (
164
+ <div
165
+ ref={ref}
166
+ style={merge(
167
+ {
168
+ borderRadius: "var(--radius)",
169
+ border: "1px solid var(--color-border)",
170
+ background: "var(--color-card)",
171
+ color: "var(--color-card-foreground)",
172
+ padding: "1.5rem",
173
+ boxShadow: "0 1px 2px 0 rgb(0 0 0 / 0.05)",
174
+ },
175
+ style,
176
+ )}
177
+ {...rest}
178
+ />
179
+ ),
180
+ );
181
+ Card.displayName = "Card";
182
+
183
+ interface HeadingProps extends React.HTMLAttributes<HTMLHeadingElement> {
184
+ level?: 1 | 2 | 3 | 4 | 5 | 6;
185
+ }
186
+
187
+ export const Heading = React.forwardRef<HTMLHeadingElement, HeadingProps>(
188
+ ({ level = 1, style, ...rest }, ref) => {
189
+ const Tag = `h${level}` as const;
190
+ return <Tag ref={ref} style={merge(headingInlineStyle(level), style)} {...rest} />;
191
+ },
192
+ );
193
+ Heading.displayName = "Heading";
194
+
195
+ interface TextProps extends React.HTMLAttributes<HTMLParagraphElement> {
196
+ variant?: "default" | "muted" | "small" | "lead";
197
+ }
198
+
199
+ export const Text = React.forwardRef<HTMLParagraphElement, TextProps>(
200
+ ({ variant = "default", style, ...rest }, ref) => (
201
+ <p ref={ref} style={merge(textInlineStyle(variant), style)} {...rest} />
202
+ ),
203
+ );
204
+ Text.displayName = "Text";
@@ -0,0 +1,155 @@
1
+ import { clsx } from "clsx";
2
+ import * as React from "react";
3
+
4
+ /**
5
+ * The no-library provider's primitives — thin wrappers over plain HTML
6
+ * elements. Anything that needs visual styling does it through Tailwind
7
+ * classes the user (or agent) supplies via the `className` prop. No
8
+ * portals, no providers, no internal state. This is intentionally the
9
+ * lowest-rope primitive set: ideal for throwaway prototypes, designs
10
+ * that haven't picked a UI library yet, and as the proof that the
11
+ * `ComponentProvider` abstraction works at the trivial end of the
12
+ * spectrum.
13
+ */
14
+
15
+ interface DivProps extends React.HTMLAttributes<HTMLDivElement> {}
16
+
17
+ export const Box = React.forwardRef<HTMLDivElement, DivProps>(({ className, ...rest }, ref) => (
18
+ <div ref={ref} className={clsx(className)} {...rest} />
19
+ ));
20
+ Box.displayName = "Box";
21
+
22
+ export interface StackProps extends DivProps {
23
+ /** Layout direction. Defaults to "col" (flex-column). */
24
+ direction?: "row" | "col";
25
+ /** Tailwind gap scale (2, 4, 6, …). Defaults to 4. */
26
+ gap?: number;
27
+ /** Cross-axis alignment. */
28
+ align?: "start" | "center" | "end" | "stretch";
29
+ /** Main-axis justification. */
30
+ justify?: "start" | "center" | "end" | "between" | "around";
31
+ }
32
+
33
+ const alignClass: Record<NonNullable<StackProps["align"]>, string> = {
34
+ start: "items-start",
35
+ center: "items-center",
36
+ end: "items-end",
37
+ stretch: "items-stretch",
38
+ };
39
+ const justifyClass: Record<NonNullable<StackProps["justify"]>, string> = {
40
+ start: "justify-start",
41
+ center: "justify-center",
42
+ end: "justify-end",
43
+ between: "justify-between",
44
+ around: "justify-around",
45
+ };
46
+
47
+ export const Stack = React.forwardRef<HTMLDivElement, StackProps>(
48
+ ({ direction = "col", gap = 4, align, justify, className, ...rest }, ref) => (
49
+ <div
50
+ ref={ref}
51
+ className={clsx(
52
+ "flex",
53
+ direction === "row" ? "flex-row" : "flex-col",
54
+ `gap-${gap}`,
55
+ align ? alignClass[align] : undefined,
56
+ justify ? justifyClass[justify] : undefined,
57
+ className,
58
+ )}
59
+ {...rest}
60
+ />
61
+ ),
62
+ );
63
+ Stack.displayName = "Stack";
64
+
65
+ export interface ContainerProps extends DivProps {
66
+ /** Max-width preset. Defaults to "md". */
67
+ size?: "sm" | "md" | "lg" | "xl" | "full";
68
+ }
69
+
70
+ const containerWidth: Record<NonNullable<ContainerProps["size"]>, string> = {
71
+ sm: "max-w-screen-sm",
72
+ md: "max-w-screen-md",
73
+ lg: "max-w-screen-lg",
74
+ xl: "max-w-screen-xl",
75
+ full: "max-w-full",
76
+ };
77
+
78
+ export const Container = React.forwardRef<HTMLDivElement, ContainerProps>(
79
+ ({ size = "md", className, ...rest }, ref) => (
80
+ <div
81
+ ref={ref}
82
+ className={clsx("mx-auto w-full px-4", containerWidth[size], className)}
83
+ {...rest}
84
+ />
85
+ ),
86
+ );
87
+ Container.displayName = "Container";
88
+
89
+ export interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
90
+ variant?: "default" | "ghost" | "outline";
91
+ }
92
+
93
+ const buttonVariant: Record<NonNullable<ButtonProps["variant"]>, string> = {
94
+ default: "bg-foreground text-background hover:bg-foreground/90",
95
+ ghost: "bg-transparent text-foreground hover:bg-muted",
96
+ outline: "bg-transparent text-foreground border border-border hover:bg-muted",
97
+ };
98
+
99
+ export const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
100
+ ({ variant = "default", className, type, ...rest }, ref) => (
101
+ <button
102
+ ref={ref}
103
+ type={type ?? "button"}
104
+ className={clsx(
105
+ "inline-flex items-center justify-center gap-2 rounded-md px-4 py-2 text-sm font-medium",
106
+ "focus-visible:outline-2 focus-visible:outline-offset-2",
107
+ buttonVariant[variant],
108
+ className,
109
+ )}
110
+ {...rest}
111
+ />
112
+ ),
113
+ );
114
+ Button.displayName = "Button";
115
+
116
+ export interface InputProps extends React.InputHTMLAttributes<HTMLInputElement> {}
117
+
118
+ export const Input = React.forwardRef<HTMLInputElement, InputProps>(
119
+ ({ className, type = "text", value, onChange, ...rest }, ref) => {
120
+ // Same canvas-safe pattern as the shadcn snapshot's Input: if a
121
+ // static `value` is supplied without `onChange`, switch to
122
+ // `readOnly` so React doesn't warn about uncontrolled→controlled.
123
+ const isStatic = value !== undefined && onChange === undefined;
124
+ return (
125
+ <input
126
+ ref={ref}
127
+ type={type}
128
+ value={value}
129
+ onChange={onChange}
130
+ readOnly={isStatic || rest.readOnly}
131
+ className={clsx(
132
+ "block w-full rounded-md border border-input bg-background px-3 py-2 text-sm",
133
+ "placeholder:text-muted-foreground focus-visible:outline-2 focus-visible:outline-offset-2",
134
+ className,
135
+ )}
136
+ {...rest}
137
+ />
138
+ );
139
+ },
140
+ );
141
+ Input.displayName = "Input";
142
+
143
+ export interface CardProps extends DivProps {}
144
+
145
+ export const Card = React.forwardRef<HTMLDivElement, CardProps>(({ className, ...rest }, ref) => (
146
+ <div
147
+ ref={ref}
148
+ className={clsx(
149
+ "rounded-lg border border-border bg-card p-6 text-card-foreground shadow-sm",
150
+ className,
151
+ )}
152
+ {...rest}
153
+ />
154
+ ));
155
+ Card.displayName = "Card";
@@ -0,0 +1,57 @@
1
+ import { dirname, join } from "node:path";
2
+ import { fileURLToPath } from "node:url";
3
+ import { type FrameworkAdapter, type Manifest, TAILWIND_CLASSNAME } from "@velloo/provider";
4
+ import { resolveProviderSrcDir } from "@velloo/provider/src-dir";
5
+ import { NONE_INLINE_INTRO, NONE_INTRO } from "./intro.ts";
6
+ import { NONE_MANIFEST } from "./manifest.ts";
7
+ import { registry } from "./registry.ts";
8
+ import { inlineRegistry } from "./registry-inline.ts";
9
+
10
+ export { Box, Button, Card, Container, Input, Stack } from "./components.tsx";
11
+ export { NONE_MANIFEST } from "./manifest.ts";
12
+ export { registry } from "./registry.ts";
13
+
14
+ export { noLibVersion } from "./version.ts";
15
+
16
+ import { noLibVersion } from "./version.ts";
17
+
18
+ const here = dirname(fileURLToPath(import.meta.url));
19
+
20
+ /** Component sources + Tailwind entry CSS. Resolves from source and from the
21
+ * bundled CLI (build.ts copies them to `<dist>/pkgs/provider-none/src`). */
22
+ const srcDir = resolveProviderSrcDir(here, "provider-none", process.env.VELLOO_NOLIB_SRC);
23
+
24
+ /** Absolute path to the Tailwind entry CSS shipped with the no-library provider. */
25
+ export const entryCssPath: string = join(srcDir, "tailwind-entry.css");
26
+
27
+ /** Absolute path to the no-library provider's component sources for JIT scanning. */
28
+ export const componentsDir: string = srcDir;
29
+
30
+ export async function loadManifest(): Promise<Manifest> {
31
+ return NONE_MANIFEST;
32
+ }
33
+
34
+ /**
35
+ * Build the no-library `ComponentProvider`. Identical interface shape
36
+ * to the shadcn provider — the renderer / JIT / codegen / canvas don't
37
+ * know which one is active; they just consume the contract.
38
+ */
39
+ export function createProvider(): FrameworkAdapter {
40
+ return {
41
+ id: "none",
42
+ version: noLibVersion,
43
+ componentsDir,
44
+ styleEntryPath: entryCssPath,
45
+ registry,
46
+ loadManifest,
47
+ label: `none ${noLibVersion}`,
48
+ // Default to Tailwind (existing folders); a folder whose `config.styling`
49
+ // is `none` resolves to the inline-`style` channel instead.
50
+ styleChannel: TAILWIND_CLASSNAME,
51
+ styleChannels: ["tailwind-classname", "style"],
52
+ mcpIntro: (channel) => [...(channel === "style" ? NONE_INLINE_INTRO : NONE_INTRO)],
53
+ // Inline-styled primitives for the `style` channel; Tailwind-classed for
54
+ // every other channel. Lets a `none/none` folder paint with the JIT off.
55
+ registryForChannel: (kind) => (kind === "style" ? inlineRegistry : registry),
56
+ };
57
+ }
@@ -0,0 +1,18 @@
1
+ /**
2
+ * MCP instruction framing for a no-framework folder
3
+ * (`FrameworkAdapter.mcpIntro`), one variant per style channel.
4
+ *
5
+ * The server's base brief is framework-neutral, so these state the (small)
6
+ * vocabulary positively rather than correcting a shadcn claim.
7
+ */
8
+ export const NONE_INTRO: readonly string[] = [
9
+ "**This folder has no component library** — only bare primitives wrapping plain HTML: `Box`/`Stack`/`Container` for layout, `Card`, `Button`, `Input`, plus the velloo helpers (`Heading`/`Text`, `Image`, `Gradient`, `Layer`, `SVG`, `Divider`, `Placeholder`, `Icon`). There is no `Badge`/`Avatar`/`Tabs`/`Dialog` — build those from primitives or define snippets. Call `list_components` for the exact set. Styling is **Tailwind classes**.",
10
+ "",
11
+ ];
12
+
13
+ export const NONE_INLINE_INTRO: readonly string[] = [
14
+ "**This folder has no component library and no CSS framework** — bare primitives wrapping plain HTML (`Box`/`Stack`/`Container`, `Card`, `Button`, `Input`) plus the velloo helpers (`Heading`/`Text`, `Image`, `Icon`, `SVG`, `Divider`, `Gradient`, `Layer`, `Placeholder`). There is no `Badge`/`Avatar`/`Tabs`/`Dialog` — build those from primitives or snippets. Call `list_components` for the exact set.",
15
+ "",
16
+ '**Style through inline `style` objects.** `update_props { style: { display: "flex", gap: "16px", padding: "24px", borderRadius: "8px", color: "var(--color-foreground)" } }` — a plain React style object (merges shallowly; an inner `null` drops a key, `style: null` clears). Reference theme tokens as CSS variables (`var(--color-primary)`, `var(--radius)`) from `get_theme` so the design stays themable. `emit_code` emits `style={{…}}` on plain elements — no imports, no Tailwind. Tailwind utility diagnostics do not apply.',
17
+ "",
18
+ ];