velloo 0.4.1 → 0.6.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/README.md +29 -7
- package/canvas/assets/index-CnyI3aig.js +29 -0
- package/canvas/assets/index-GNLd0pCG.css +2 -0
- package/canvas/assets/lucide-all-CH8LmVh0.js +1 -0
- package/canvas/index.html +2 -2
- package/{chunk-91pajfnm.js → chunk-08mjtg1e.js} +1 -1
- package/{chunk-m1wp8cpt.js → chunk-1gkeepkm.js} +1 -1
- package/{chunk-2dm4x17z.js → chunk-1td6z6ey.js} +1 -1
- package/{chunk-ykdx12na.js → chunk-2ba6edh8.js} +1 -1
- package/chunk-2q561dec.js +2 -0
- package/chunk-2web93qz.js +2 -0
- package/{chunk-py6sjyzk.js → chunk-3trkmgfr.js} +1 -1
- package/chunk-52m26hh4.js +3 -0
- package/{chunk-7xffbj5h.js → chunk-56vfy0db.js} +1 -1
- package/{chunk-8t5phg0s.js → chunk-56z5xd5b.js} +1 -1
- package/{chunk-xbhxzdat.js → chunk-63y5gdzw.js} +1 -1
- package/{chunk-t9ygewjx.js → chunk-6813v926.js} +257 -3
- package/{chunk-cejmmx3r.js → chunk-69qb8p8s.js} +2 -2
- package/chunk-6k05kqnc.js +3 -0
- package/chunk-74yxy75r.js +3 -0
- package/{chunk-7a45tn73.js → chunk-8cj4swpr.js} +5 -5
- package/chunk-8grzf8q1.js +2 -0
- package/chunk-8vam2893.js +3 -0
- package/{chunk-dj1pp4e3.js → chunk-8vgpffn7.js} +1 -1
- package/{chunk-j5axqyan.js → chunk-96qhpth5.js} +1 -1
- package/chunk-ab8fga32.js +22 -0
- package/chunk-azeqkms7.js +6 -0
- package/{chunk-2y9nnzpr.js → chunk-bc7pkjcn.js} +1 -1
- package/{chunk-7gtvstne.js → chunk-c4spp880.js} +1 -1
- package/{chunk-a9mgvspm.js → chunk-chtv0yj6.js} +211 -110
- package/{chunk-r9ekd92e.js → chunk-dar6wbf2.js} +1 -1
- package/{chunk-aa3str7g.js → chunk-e2btp1wd.js} +1 -1
- package/{chunk-hsrg23gd.js → chunk-eqjtq673.js} +1 -1
- package/chunk-esb7n55g.js +244 -0
- package/chunk-ey65err5.js +5 -0
- package/{chunk-r03aywsb.js → chunk-ff0jfn0v.js} +1 -1
- package/chunk-ff2vt7cz.js +12 -0
- package/chunk-g185gx8a.js +2 -0
- package/{chunk-km3z2czq.js → chunk-h85hv05d.js} +1 -1
- package/{chunk-db7mf114.js → chunk-hf4adxe0.js} +9 -7
- package/{chunk-6zr596r2.js → chunk-hjc5eg5c.js} +1 -1
- package/{chunk-b4jy4hcd.js → chunk-hsfpbjpc.js} +1 -1
- package/{chunk-ph94nrc8.js → chunk-jsvkqae2.js} +1 -1
- package/{chunk-rfrbnw8r.js → chunk-k423dkjz.js} +1 -1
- package/chunk-mfch0b0t.js +3 -0
- package/chunk-nbbnb5e9.js +3 -0
- package/{chunk-tr49kraa.js → chunk-nx09zqgs.js} +1 -1
- package/chunk-p93x4pn2.js +3 -0
- package/{chunk-k3dpwjx4.js → chunk-pxaxgkaq.js} +1 -1
- package/chunk-qwccndcd.js +5 -0
- package/{chunk-vjrn10xr.js → chunk-rjjc9vam.js} +2 -2
- package/{chunk-npsg7btt.js → chunk-rk238m15.js} +1 -1
- package/chunk-t2x3mztc.js +2 -0
- package/chunk-t6qr2ay9.js +3 -0
- package/chunk-ta84ehgg.js +2 -0
- package/chunk-tac2wvc7.js +2 -0
- package/chunk-tbd6wn3q.js +6 -0
- package/chunk-v6c3h9ft.js +3 -0
- package/chunk-w2naqxqt.js +2 -0
- package/chunk-wfhv9jg4.js +2 -0
- package/chunk-wnj432fw.js +3 -0
- package/chunk-x02z2ccm.js +2 -0
- package/{chunk-b58pnj20.js → chunk-xtwx2p9g.js} +1 -1
- package/chunk-yfvc8d2g.js +716 -0
- package/chunk-z73q4dq9.js +2 -0
- package/{chunk-yfttm20w.js → chunk-ztsckexy.js} +2 -2
- package/cli.js +1 -1
- package/package.json +3 -1
- package/pkgs/helpers/src/descriptors.ts +1 -0
- package/pkgs/helpers/src/index.ts +7 -4
- package/pkgs/helpers/src/lowering.ts +0 -24
- package/pkgs/helpers/src/primitive-classes.tsx +43 -0
- package/pkgs/provider-antd/src/intro.ts +3 -3
- package/pkgs/provider-antd/src/manifest.ts +478 -57
- package/pkgs/provider-antd/src/registry.ts +8 -5
- package/pkgs/provider-antd/src/render-pass.ts +10 -4
- package/pkgs/provider-antd/src/reset-css.d.ts +5 -0
- package/pkgs/provider-antd/src/theme.ts +54 -11
- package/pkgs/provider-chakra/src/manifest.ts +5 -1
- package/pkgs/provider-html/src/index.ts +68 -0
- package/pkgs/provider-html/src/registry.ts +121 -0
- package/pkgs/provider-html/src/version.ts +1 -0
- package/pkgs/provider-mui/src/index.ts +4 -2
- package/pkgs/provider-mui/src/manifest.ts +10 -1
- package/pkgs/provider-mui/src/render-pass.ts +15 -1
- package/pkgs/provider-mui/src/theme.ts +10 -4
- package/pkgs/provider-none/src/components-inline.tsx +12 -3
- package/pkgs/provider-none/src/components.tsx +26 -53
- package/pkgs/provider-none/src/manifest.ts +2 -0
- package/pkgs/schema/src/annotation.ts +6 -3
- package/pkgs/schema/src/comment.ts +10 -1
- package/pkgs/schema/src/config.ts +33 -1
- package/pkgs/schema/src/css-declarations.ts +41 -0
- package/pkgs/schema/src/index.ts +16 -1
- package/pkgs/schema/src/node-identity.ts +92 -0
- package/pkgs/schema/src/node.ts +13 -4
- package/pkgs/schema/src/theme.ts +46 -1
- package/pkgs/schema/src/typeset.ts +24 -17
- package/pkgs/shadcn-snapshot/dist/manifest.json +1 -0
- package/pkgs/shadcn-snapshot/src/components/ui/alert.tsx +2 -4
- package/pkgs/shadcn-snapshot/src/components/ui/aspect-ratio.tsx +2 -3
- package/pkgs/shadcn-snapshot/src/components/ui/attachment.tsx +3 -4
- package/pkgs/shadcn-snapshot/src/components/ui/avatar.tsx +2 -4
- package/pkgs/shadcn-snapshot/src/components/ui/badge.tsx +2 -4
- package/pkgs/shadcn-snapshot/src/components/ui/breadcrumb.tsx +2 -4
- package/pkgs/shadcn-snapshot/src/components/ui/bubble.tsx +2 -4
- package/pkgs/shadcn-snapshot/src/components/ui/button-group.tsx +3 -4
- package/pkgs/shadcn-snapshot/src/components/ui/button.tsx +2 -4
- package/pkgs/shadcn-snapshot/src/components/ui/card.tsx +2 -4
- package/pkgs/shadcn-snapshot/src/components/ui/carousel.tsx +3 -4
- package/pkgs/shadcn-snapshot/src/components/ui/chart.tsx +1 -1
- package/pkgs/shadcn-snapshot/src/components/ui/direction.tsx +2 -3
- package/pkgs/shadcn-snapshot/src/components/ui/empty.tsx +2 -4
- package/pkgs/shadcn-snapshot/src/components/ui/field.tsx +3 -4
- package/pkgs/shadcn-snapshot/src/components/ui/input-group.tsx +3 -4
- package/pkgs/shadcn-snapshot/src/components/ui/item.tsx +3 -4
- package/pkgs/shadcn-snapshot/src/components/ui/kbd.tsx +2 -3
- package/pkgs/shadcn-snapshot/src/components/ui/label.tsx +2 -4
- package/pkgs/shadcn-snapshot/src/components/ui/marker.tsx +2 -4
- package/pkgs/shadcn-snapshot/src/components/ui/message.tsx +2 -4
- package/pkgs/shadcn-snapshot/src/components/ui/native-select.tsx +2 -4
- package/pkgs/shadcn-snapshot/src/components/ui/navigation-menu.tsx +2 -4
- package/pkgs/shadcn-snapshot/src/components/ui/pagination.tsx +3 -4
- package/pkgs/shadcn-snapshot/src/components/ui/progress.tsx +2 -4
- package/pkgs/shadcn-snapshot/src/components/ui/radio-group.tsx +2 -4
- package/pkgs/shadcn-snapshot/src/components/ui/scroll-area.tsx +2 -4
- package/pkgs/shadcn-snapshot/src/components/ui/separator.tsx +2 -4
- package/pkgs/shadcn-snapshot/src/components/ui/skeleton.tsx +2 -3
- package/pkgs/shadcn-snapshot/src/components/ui/spinner.tsx +2 -3
- package/pkgs/shadcn-snapshot/src/components/ui/table.tsx +2 -4
- package/pkgs/shadcn-snapshot/src/components/ui/tabs.tsx +2 -4
- package/pkgs/shadcn-snapshot/src/components/ui/toggle.tsx +2 -4
- package/pkgs/shadcn-snapshot/src/shadcn-tailwind.css +1 -1
- package/pkgs/shadcn-snapshot/src/tailwind-entry.css +1 -1
- package/plugins/claude/velloo/agents/velloo-design-reviewer.md +56 -13
- package/plugins/claude/velloo/agents/velloo-designer.md +4 -1
- package/skills/velloo-setup/SKILL.md +19 -55
- package/canvas/assets/index-B1OD0Yz5.css +0 -2
- package/canvas/assets/index-BWYFx2Rr.js +0 -29
- package/canvas/assets/lucide-all-Bcm80WFX.js +0 -1
- package/chunk-00t0bz7x.js +0 -244
- package/chunk-0446t32z.js +0 -2
- package/chunk-0zen7bzb.js +0 -3
- package/chunk-2h24va0j.js +0 -2
- package/chunk-2jbhv7vh.js +0 -3
- package/chunk-5ywkk7d6.js +0 -2
- package/chunk-b7famda5.js +0 -3
- package/chunk-cvn689d5.js +0 -3
- package/chunk-e6nhc3ay.js +0 -6
- package/chunk-f5g45xed.js +0 -2
- package/chunk-fjbzk4sw.js +0 -3
- package/chunk-hv52a6hf.js +0 -2
- package/chunk-jep31ffe.js +0 -2
- package/chunk-jwzhhhzn.js +0 -3
- package/chunk-mcymwefw.js +0 -5
- package/chunk-n0kx20s2.js +0 -2
- package/chunk-nwf2kn41.js +0 -26
- package/chunk-phz993p3.js +0 -2
- package/chunk-qan5dnjt.js +0 -688
- package/chunk-r5d0jsnd.js +0 -5
- package/chunk-shac6bat.js +0 -6
- package/chunk-t4zvcece.js +0 -10
- package/chunk-tarws372.js +0 -2
- package/chunk-yghypth2.js +0 -2
- package/chunk-zqtz23xk.js +0 -3
|
@@ -14,7 +14,9 @@ const PRIMITIVE_DESCRIPTORS: ComponentDescriptor[] = [
|
|
|
14
14
|
id: "Box",
|
|
15
15
|
category: "ui",
|
|
16
16
|
source: "velloo",
|
|
17
|
+
plainElement: true,
|
|
17
18
|
props: [
|
|
19
|
+
{ name: "as", type: "string", optional: true, control: "string" },
|
|
18
20
|
{
|
|
19
21
|
name: "className",
|
|
20
22
|
type: "string | undefined",
|
|
@@ -100,11 +100,14 @@ export const CanvasNoteSchema = z
|
|
|
100
100
|
*/
|
|
101
101
|
x: z.number().optional(),
|
|
102
102
|
y: z.number().optional(),
|
|
103
|
+
/** User-resizable width. */
|
|
104
|
+
width: z.number().positive(),
|
|
103
105
|
/**
|
|
104
|
-
*
|
|
105
|
-
*
|
|
106
|
+
* The height the author drew or resized the note to. Absent, the note is
|
|
107
|
+
* exactly as tall as its text; set, it is this tall, and text that runs
|
|
108
|
+
* past it scrolls inside the note.
|
|
106
109
|
*/
|
|
107
|
-
|
|
110
|
+
height: z.number().positive().optional(),
|
|
108
111
|
/** Markdown body. */
|
|
109
112
|
body: z.string(),
|
|
110
113
|
/** Present when the note is about a specific node rather than the board. */
|
|
@@ -116,4 +116,13 @@ export type CommentAnchorState =
|
|
|
116
116
|
| { status: "attached"; resolvedPath: number[] }
|
|
117
117
|
| { status: "stale" };
|
|
118
118
|
|
|
119
|
-
export type CommentThreadView = CommentThread & {
|
|
119
|
+
export type CommentThreadView = CommentThread & {
|
|
120
|
+
anchorState: CommentAnchorState;
|
|
121
|
+
/**
|
|
122
|
+
* False when the viewer can read the thread but not resolve or delete it — a
|
|
123
|
+
* cloud thread on a link they no longer manage. Absent means they can.
|
|
124
|
+
*/
|
|
125
|
+
manage?: false;
|
|
126
|
+
/** The git branch a cloud thread's link was last published from, where known. */
|
|
127
|
+
branch?: string;
|
|
128
|
+
};
|
|
@@ -28,7 +28,7 @@ export const LibrarySchema = z.object({
|
|
|
28
28
|
* Component provider id. The server's provider loader maps ids to
|
|
29
29
|
* factories; `"shadcn-upstream"` is the default for new folders.
|
|
30
30
|
*/
|
|
31
|
-
id: z.enum(["shadcn-upstream", "none", "mui", "antd", "chakra"]),
|
|
31
|
+
id: z.enum(["shadcn-upstream", "none", "html", "mui", "antd", "chakra"]),
|
|
32
32
|
version: z.string().min(1),
|
|
33
33
|
source: z.enum(["binary", "cache", "in-repo"]),
|
|
34
34
|
/** Where the components live, relative to the design folder root. */
|
|
@@ -50,6 +50,19 @@ const CodegenConfigSchema = z.object({
|
|
|
50
50
|
|
|
51
51
|
export type CodegenConfig = z.infer<typeof CodegenConfigSchema>;
|
|
52
52
|
|
|
53
|
+
/**
|
|
54
|
+
* A path inside the host app, relative to its root. The config is committed
|
|
55
|
+
* with the repo and the agents are told to open what it names, so a cloned
|
|
56
|
+
* repo must not be able to aim it anywhere else: absolute paths and `..`
|
|
57
|
+
* segments make the file invalid rather than being resolved.
|
|
58
|
+
*/
|
|
59
|
+
const AppRelativePathSchema = z
|
|
60
|
+
.string()
|
|
61
|
+
.min(1)
|
|
62
|
+
.refine((path) => !/^(?:[\\/~]|[A-Za-z]:)/.test(path) && !path.split(/[\\/]/).includes(".."), {
|
|
63
|
+
message: "must be relative to the app root, with no absolute path or `..` segment",
|
|
64
|
+
});
|
|
65
|
+
|
|
53
66
|
/**
|
|
54
67
|
* Where the host app lives, used by the live-island bundler to resolve
|
|
55
68
|
* a `render:"live"` extension's `importPath` (and its dependencies, e.g.
|
|
@@ -73,6 +86,11 @@ export const HostAppSchema = z.object({
|
|
|
73
86
|
* built-in framework recipe, then no wrapper.
|
|
74
87
|
*/
|
|
75
88
|
preview: z.string().min(1).optional(),
|
|
89
|
+
/**
|
|
90
|
+
* The app's stylesheets an HTML design is styled by, in cascade order. The
|
|
91
|
+
* design keeps copies of them under `assets/host/` (`store_host_files`).
|
|
92
|
+
*/
|
|
93
|
+
stylesheets: z.array(z.string().regex(/^(?:\/(?!\/)|https:\/\/)/)).optional(),
|
|
76
94
|
/**
|
|
77
95
|
* Bounds repository-component discovery beyond what the app's entries and
|
|
78
96
|
* routes import: `include` adds component roots (files or directories,
|
|
@@ -171,6 +189,20 @@ export const ConfigSchema = z
|
|
|
171
189
|
styling: z.object({ framework: z.enum(["tailwind", "none"]) }).optional(),
|
|
172
190
|
/** Host app location for the live-island bundler. See `HostAppSchema`. */
|
|
173
191
|
hostApp: HostAppSchema.optional(),
|
|
192
|
+
/**
|
|
193
|
+
* A design-system document this folder follows — normally the repo's
|
|
194
|
+
* `DESIGN.md`.
|
|
195
|
+
*
|
|
196
|
+
* A path, never a copy. The file belongs to the repo and goes on being
|
|
197
|
+
* edited there; a copy inside the design folder would drift away from the
|
|
198
|
+
* rules it was supposed to state, which is the one thing a design system
|
|
199
|
+
* must not do. Relative to the host app root, so the usual value is
|
|
200
|
+
* `DESIGN.md`.
|
|
201
|
+
*
|
|
202
|
+
* Optional because the folder also finds one by convention — this records
|
|
203
|
+
* a file somewhere unconventional, or pins the choice when several exist.
|
|
204
|
+
*/
|
|
205
|
+
designSystem: z.object({ path: AppRelativePathSchema }).optional(),
|
|
174
206
|
/**
|
|
175
207
|
* Named host apps for monorepos — the multi-app twin of `hostApp`, keyed
|
|
176
208
|
* by a short app name (`"web"`, `"admin"`; `init`'s multi-app scan uses
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
const CSS_PROPERTY = /^(--[\w-]+|-?[a-z][a-z-]*)$/;
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* CSS declaration text as a React style object (`background-size` ⇒
|
|
5
|
+
* `backgroundSize`, custom properties kept), or null when the text is not a
|
|
6
|
+
* declaration list — a class string, say. Semicolons inside `url(…)` or quotes
|
|
7
|
+
* do not split.
|
|
8
|
+
*/
|
|
9
|
+
export function styleObjectFromCss(text: string): Record<string, string> | null {
|
|
10
|
+
const declarations: string[] = [];
|
|
11
|
+
let depth = 0;
|
|
12
|
+
let quote: string | null = null;
|
|
13
|
+
let start = 0;
|
|
14
|
+
for (let i = 0; i < text.length; i++) {
|
|
15
|
+
const char = text[i];
|
|
16
|
+
if (quote) {
|
|
17
|
+
if (char === quote) quote = null;
|
|
18
|
+
} else if (char === '"' || char === "'") quote = char;
|
|
19
|
+
else if (char === "(") depth++;
|
|
20
|
+
else if (char === ")") depth = Math.max(0, depth - 1);
|
|
21
|
+
else if (char === ";" && depth === 0) {
|
|
22
|
+
declarations.push(text.slice(start, i));
|
|
23
|
+
start = i + 1;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
declarations.push(text.slice(start));
|
|
27
|
+
const style: Record<string, string> = {};
|
|
28
|
+
for (const declaration of declarations) {
|
|
29
|
+
if (declaration.trim() === "") continue;
|
|
30
|
+
const colon = declaration.indexOf(":");
|
|
31
|
+
if (colon < 0) return null;
|
|
32
|
+
const property = declaration.slice(0, colon).trim().toLowerCase();
|
|
33
|
+
const value = declaration.slice(colon + 1).trim();
|
|
34
|
+
if (!CSS_PROPERTY.test(property) || value === "") return null;
|
|
35
|
+
const key = property.startsWith("--")
|
|
36
|
+
? property
|
|
37
|
+
: property.replace(/^-(ms)-/, "$1-").replace(/-([a-z])/g, (_, c: string) => c.toUpperCase());
|
|
38
|
+
style[key] = value;
|
|
39
|
+
}
|
|
40
|
+
return Object.keys(style).length > 0 ? style : null;
|
|
41
|
+
}
|
package/pkgs/schema/src/index.ts
CHANGED
|
@@ -56,6 +56,7 @@ export {
|
|
|
56
56
|
type ViewportPreset,
|
|
57
57
|
ViewportPresetSchema,
|
|
58
58
|
} from "./config.ts";
|
|
59
|
+
export { styleObjectFromCss } from "./css-declarations.ts";
|
|
59
60
|
export {
|
|
60
61
|
isCssIdent,
|
|
61
62
|
neutralizeCssText,
|
|
@@ -93,6 +94,7 @@ export {
|
|
|
93
94
|
} from "./migrate.ts";
|
|
94
95
|
export {
|
|
95
96
|
type ComponentNode,
|
|
97
|
+
type EmitAsRef,
|
|
96
98
|
isComponentNode,
|
|
97
99
|
isParamRef,
|
|
98
100
|
isRepoNode,
|
|
@@ -109,6 +111,17 @@ export {
|
|
|
109
111
|
repoKey,
|
|
110
112
|
type SnippetInstance,
|
|
111
113
|
} from "./node.ts";
|
|
114
|
+
export {
|
|
115
|
+
type EmitAsNode,
|
|
116
|
+
isNode,
|
|
117
|
+
isSyntheticRef,
|
|
118
|
+
type NodeShape,
|
|
119
|
+
nodeShape,
|
|
120
|
+
PARAM_TAG_REF,
|
|
121
|
+
type RepoNode,
|
|
122
|
+
STATIC_REF,
|
|
123
|
+
type SyntheticRef,
|
|
124
|
+
} from "./node-identity.ts";
|
|
112
125
|
export {
|
|
113
126
|
DesignNameSchema,
|
|
114
127
|
designNameIssue,
|
|
@@ -139,6 +152,8 @@ export {
|
|
|
139
152
|
ColorsSchema,
|
|
140
153
|
type LooseTokenGroup,
|
|
141
154
|
resolveColors,
|
|
155
|
+
spacingCssTokens,
|
|
156
|
+
TAILWIND_SIZE_NAMES,
|
|
142
157
|
type Theme,
|
|
143
158
|
ThemeSchema,
|
|
144
159
|
TypographySchema,
|
|
@@ -173,7 +188,7 @@ export {
|
|
|
173
188
|
typesetSizePx,
|
|
174
189
|
typesetThemeTokens,
|
|
175
190
|
typesetUtilityClasses,
|
|
176
|
-
|
|
191
|
+
typesetV3Theme,
|
|
177
192
|
typesetVars,
|
|
178
193
|
} from "./typeset.ts";
|
|
179
194
|
export { type DuplicateId, findDuplicateIds } from "./validate-ids.ts";
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import {
|
|
2
|
+
type ComponentNode,
|
|
3
|
+
type EmitAsRef,
|
|
4
|
+
isComponentNode,
|
|
5
|
+
isParamRef,
|
|
6
|
+
isSnippetInstance,
|
|
7
|
+
type Node,
|
|
8
|
+
type ParamRef,
|
|
9
|
+
type RepoComponentRef,
|
|
10
|
+
type SnippetInstance,
|
|
11
|
+
} from "./node.ts";
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* A `$ref` the renderer resolves itself rather than through any registry.
|
|
15
|
+
* Synthetic refs are never persisted — a preview synthesizes them — and every
|
|
16
|
+
* provider has to be able to draw them, so they can't be library components
|
|
17
|
+
* (a `none` folder has no `Badge` to draw a param slot with).
|
|
18
|
+
*/
|
|
19
|
+
export const PARAM_TAG_REF = "velloo:param-tag";
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* The ref a node serializes to when the canvas bundle has no browser source
|
|
23
|
+
* for it and the client must drop in its server render instead.
|
|
24
|
+
*/
|
|
25
|
+
export const STATIC_REF = "velloo:static";
|
|
26
|
+
|
|
27
|
+
export type SyntheticRef = typeof PARAM_TAG_REF | typeof STATIC_REF;
|
|
28
|
+
|
|
29
|
+
const SYNTHETIC_REFS: readonly SyntheticRef[] = [PARAM_TAG_REF, STATIC_REF];
|
|
30
|
+
|
|
31
|
+
export function isSyntheticRef(ref: string): ref is SyntheticRef {
|
|
32
|
+
return (SYNTHETIC_REFS as readonly string[]).includes(ref);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/** A component node carrying a repository identity (see {@link ComponentNode.$repo}). */
|
|
36
|
+
export type RepoNode = ComponentNode & { $repo: RepoComponentRef };
|
|
37
|
+
|
|
38
|
+
/** A component node carrying an emit-time host facade (see {@link ComponentNode.$emitAs}). */
|
|
39
|
+
export type EmitAsNode = ComponentNode & { $emitAs: EmitAsRef };
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* What a node's own fields say it is. Purely structural: no registry, no
|
|
43
|
+
* catalog, no I/O — a `named` shape is as far as the node alone can go, and
|
|
44
|
+
* `resolveNodeIdentity` in `@velloo/provider` takes it from there.
|
|
45
|
+
*
|
|
46
|
+
* The order of the `$`-keys is the contract, stated here once and nowhere
|
|
47
|
+
* else: `$snippet`, then `$param`, then a component — where an identity
|
|
48
|
+
* (`$repo`) beats an emit-time facade (`$emitAs`) beats a synthetic ref beats
|
|
49
|
+
* a plain name. A malformed value carrying both `$snippet` and `$ref` is a
|
|
50
|
+
* snippet instance, as every walker has always read it.
|
|
51
|
+
*/
|
|
52
|
+
export type NodeShape =
|
|
53
|
+
| { kind: "repo"; node: RepoNode; ref: string; repo: RepoComponentRef }
|
|
54
|
+
| { kind: "emit-as"; node: EmitAsNode; ref: string; emitAs: EmitAsRef }
|
|
55
|
+
| { kind: "synthetic"; node: ComponentNode; ref: SyntheticRef }
|
|
56
|
+
| { kind: "named"; node: ComponentNode; ref: string }
|
|
57
|
+
| { kind: "snippet"; node: SnippetInstance }
|
|
58
|
+
| { kind: "param"; node: ParamRef }
|
|
59
|
+
/** Not a node at all — a raw scalar or object sitting in a node position. */
|
|
60
|
+
| { kind: "invalid"; value: unknown };
|
|
61
|
+
|
|
62
|
+
/** Discriminate a value by its own fields. Accepts `unknown`: node positions are a trust boundary. */
|
|
63
|
+
export function nodeShape(value: unknown): NodeShape {
|
|
64
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) {
|
|
65
|
+
return { kind: "invalid", value };
|
|
66
|
+
}
|
|
67
|
+
const node = value as Node;
|
|
68
|
+
if (isSnippetInstance(node)) return { kind: "snippet", node };
|
|
69
|
+
if (isParamRef(node)) return { kind: "param", node };
|
|
70
|
+
if (isComponentNode(node)) {
|
|
71
|
+
if (node.$repo !== undefined) {
|
|
72
|
+
return { kind: "repo", node: node as RepoNode, ref: node.$ref, repo: node.$repo };
|
|
73
|
+
}
|
|
74
|
+
if (node.$emitAs !== undefined) {
|
|
75
|
+
return { kind: "emit-as", node: node as EmitAsNode, ref: node.$ref, emitAs: node.$emitAs };
|
|
76
|
+
}
|
|
77
|
+
if (isSyntheticRef(node.$ref)) {
|
|
78
|
+
return { kind: "synthetic", node, ref: node.$ref };
|
|
79
|
+
}
|
|
80
|
+
return { kind: "named", node, ref: node.$ref };
|
|
81
|
+
}
|
|
82
|
+
return { kind: "invalid", value };
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Whether a raw JSON value is itself a node. The check every walker needs when
|
|
87
|
+
* it meets a *prop* value — a `children` prop carrying inline rich text, a slot
|
|
88
|
+
* prop holding an icon — where a node and a plain value are both legal.
|
|
89
|
+
*/
|
|
90
|
+
export function isNode(value: unknown): value is Node {
|
|
91
|
+
return nodeShape(value).kind !== "invalid";
|
|
92
|
+
}
|
package/pkgs/schema/src/node.ts
CHANGED
|
@@ -46,18 +46,27 @@ export type ComponentNode = {
|
|
|
46
46
|
* subtree — preserving the app's real component identity through
|
|
47
47
|
* capture → design → emit. Absent ⇒ the node emits as itself.
|
|
48
48
|
*/
|
|
49
|
-
$emitAs?:
|
|
49
|
+
$emitAs?: EmitAsRef | undefined;
|
|
50
50
|
/**
|
|
51
51
|
* Repository component identity: this node IS a component the host app
|
|
52
52
|
* imports (a package export such as Mantine's `Tabs`, or the app's own
|
|
53
53
|
* `StatCard`), not a library component. `$ref` stays the JSX name codegen
|
|
54
|
-
* prints; the identity decides rendering and imports.
|
|
55
|
-
*
|
|
56
|
-
* explicit on the node rather than a registry-order accident.
|
|
54
|
+
* prints; the identity decides rendering and imports. Where it sits against
|
|
55
|
+
* the node's other keys is `nodeShape`'s to say (`./node-identity.ts`).
|
|
57
56
|
*/
|
|
58
57
|
$repo?: RepoComponentRef | undefined;
|
|
59
58
|
};
|
|
60
59
|
|
|
60
|
+
/**
|
|
61
|
+
* A host component a node emits *as*, in place of its own subtree. Superseded
|
|
62
|
+
* in practice by {@link RepoComponentRef}, which renders for real; kept because
|
|
63
|
+
* design folders carry it.
|
|
64
|
+
*/
|
|
65
|
+
export type EmitAsRef = {
|
|
66
|
+
name: string;
|
|
67
|
+
importPath: string;
|
|
68
|
+
};
|
|
69
|
+
|
|
61
70
|
/**
|
|
62
71
|
* Where a repository component comes from. The import form is kept exactly as
|
|
63
72
|
* code generation must print it; the resolved file is runtime cache data and
|
package/pkgs/schema/src/theme.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
+
import { isCssIdent } from "./css-sanitize.ts";
|
|
2
3
|
|
|
3
4
|
const NumOrCssLen = z.union([z.number(), z.string().min(1)]);
|
|
4
5
|
|
|
@@ -56,6 +57,45 @@ export type Colors = z.infer<typeof ColorsSchema>;
|
|
|
56
57
|
*/
|
|
57
58
|
export type ColorsOverride = { [K in keyof Colors]?: Colors[K] | undefined };
|
|
58
59
|
|
|
60
|
+
/**
|
|
61
|
+
* Spacing names Tailwind v4 already reads as a size scale. Its `max-w-*`,
|
|
62
|
+
* `w-*` and `min-w-*` utilities resolve a `--spacing-<name>` ahead of
|
|
63
|
+
* `--container-<name>`, so a design system's t-shirt spacing (`xl: 1.5rem`)
|
|
64
|
+
* emitted under one of these names turns every `max-w-xl` into 24px and a
|
|
65
|
+
* paragraph into one word per line.
|
|
66
|
+
*/
|
|
67
|
+
export const TAILWIND_SIZE_NAMES: ReadonlySet<string> = new Set([
|
|
68
|
+
"3xs",
|
|
69
|
+
"2xs",
|
|
70
|
+
"xs",
|
|
71
|
+
"sm",
|
|
72
|
+
"md",
|
|
73
|
+
"lg",
|
|
74
|
+
"xl",
|
|
75
|
+
"2xl",
|
|
76
|
+
"3xl",
|
|
77
|
+
"4xl",
|
|
78
|
+
"5xl",
|
|
79
|
+
"6xl",
|
|
80
|
+
"7xl",
|
|
81
|
+
"prose",
|
|
82
|
+
]);
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* The named spacing tokens that become `--spacing-<name>` in CSS. Numeric
|
|
86
|
+
* steps are Tailwind's built-in scale and names Tailwind reads as sizes stay
|
|
87
|
+
* in the theme only; the canvas stylesheet and the emitted globals.css both
|
|
88
|
+
* come from this list, so they cannot disagree.
|
|
89
|
+
*/
|
|
90
|
+
export function spacingCssTokens(spacing: Theme["spacing"]): Array<[string, string | number]> {
|
|
91
|
+
const out: Array<[string, string | number]> = [];
|
|
92
|
+
for (const [name, value] of Object.entries(spacing ?? {})) {
|
|
93
|
+
if (!Number.isNaN(Number(name)) || !isCssIdent(name) || TAILWIND_SIZE_NAMES.has(name)) continue;
|
|
94
|
+
if (typeof value === "string" || typeof value === "number") out.push([name, value]);
|
|
95
|
+
}
|
|
96
|
+
return out;
|
|
97
|
+
}
|
|
98
|
+
|
|
59
99
|
/**
|
|
60
100
|
* The effective colors for a mode: `colors`, with `colorsDark` layered on when
|
|
61
101
|
* rendering dark.
|
|
@@ -91,7 +131,12 @@ export function resolveColors(theme: Theme, dark = false): Colors {
|
|
|
91
131
|
* CSS-safe ident so they can't inject into the emitted stylesheet.
|
|
92
132
|
*/
|
|
93
133
|
const PaletteSchema = z.record(
|
|
94
|
-
z
|
|
134
|
+
z
|
|
135
|
+
.string()
|
|
136
|
+
.regex(
|
|
137
|
+
/^[a-z][a-z0-9]*(?:-[a-z0-9]+)*$/,
|
|
138
|
+
'palette keys are lowercase kebab-case, letter first — "primary-soft", "success-500", "border-primary-300"',
|
|
139
|
+
),
|
|
95
140
|
z.string().min(1),
|
|
96
141
|
);
|
|
97
142
|
|
|
@@ -287,24 +287,31 @@ export function typesetUtilityClasses(): string[] {
|
|
|
287
287
|
}
|
|
288
288
|
|
|
289
289
|
/**
|
|
290
|
-
* The scale as
|
|
291
|
-
* paired leading and tracking
|
|
292
|
-
*
|
|
293
|
-
*
|
|
290
|
+
* The scale as Tailwind v3 `theme.extend` maps. `fontSize` carries each role's
|
|
291
|
+
* paired leading and tracking (so `text-h1` alone sets all three), and
|
|
292
|
+
* `lineHeight` / `letterSpacing` make the standalone `leading-<role>` /
|
|
293
|
+
* `tracking-<role>` utilities exist — v3 derives no utility from a fontSize
|
|
294
|
+
* tuple's extras, and `TYPESET_CLASSES` spells all three. Every value is a
|
|
295
|
+
* `var()` into the typeset sheet, so a v3 app re-derives inside a
|
|
296
|
+
* `.typeset-<preset>` region exactly like a v4 one.
|
|
294
297
|
*/
|
|
295
|
-
export function
|
|
296
|
-
string,
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
298
|
+
export function typesetV3Theme(): {
|
|
299
|
+
fontSize: Record<string, [string, { lineHeight: string; letterSpacing: string }]>;
|
|
300
|
+
lineHeight: Record<string, string>;
|
|
301
|
+
letterSpacing: Record<string, string>;
|
|
302
|
+
} {
|
|
303
|
+
const fontSize: Record<string, [string, { lineHeight: string; letterSpacing: string }]> = {};
|
|
304
|
+
const lineHeight: Record<string, string> = {};
|
|
305
|
+
const letterSpacing: Record<string, string> = {};
|
|
306
|
+
for (const role of TYPESET_SCALE_NAMES) {
|
|
307
|
+
fontSize[role] = [
|
|
308
|
+
`var(--text-${role})`,
|
|
309
|
+
{ lineHeight: `var(--leading-${role})`, letterSpacing: `var(--tracking-${role})` },
|
|
310
|
+
];
|
|
311
|
+
lineHeight[role] = `var(--leading-${role})`;
|
|
312
|
+
letterSpacing[role] = `var(--tracking-${role})`;
|
|
313
|
+
}
|
|
314
|
+
return { fontSize, lineHeight, letterSpacing };
|
|
308
315
|
}
|
|
309
316
|
|
|
310
317
|
/**
|
|
@@ -1,11 +1,9 @@
|
|
|
1
1
|
// Vendored from shadcn-ui (https://ui.shadcn.com/docs/components/radix/alert).
|
|
2
|
-
//
|
|
3
|
-
// Regenerate with `bun run vendor` —
|
|
4
|
-
// canvas adaptation, in which case add the id to vendor.ts's ADAPTED set.
|
|
2
|
+
// Design-mode fork for the Velloo canvas — not the shadcn the IDE chrome renders.
|
|
3
|
+
// Regenerate with `bun run vendor` — the pipeline is scripts/vendor-shadcn/.
|
|
5
4
|
|
|
6
5
|
import { cva, type VariantProps } from "class-variance-authority";
|
|
7
6
|
import type * as React from "react";
|
|
8
|
-
|
|
9
7
|
import { cn } from "../../lib/utils.ts";
|
|
10
8
|
|
|
11
9
|
const alertVariants = cva(
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
// Vendored from shadcn-ui (https://ui.shadcn.com/docs/components/radix/aspect-ratio).
|
|
2
|
-
//
|
|
3
|
-
// Regenerate with `bun run vendor` —
|
|
4
|
-
// canvas adaptation, in which case add the id to vendor.ts's ADAPTED set.
|
|
2
|
+
// Design-mode fork for the Velloo canvas — not the shadcn the IDE chrome renders.
|
|
3
|
+
// Regenerate with `bun run vendor` — the pipeline is scripts/vendor-shadcn/.
|
|
5
4
|
"use client";
|
|
6
5
|
|
|
7
6
|
import { AspectRatio as AspectRatioPrimitive } from "radix-ui";
|
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
// Vendored from shadcn-ui (https://ui.shadcn.com/docs/components/radix/attachment).
|
|
2
|
-
//
|
|
3
|
-
// Regenerate with `bun run vendor` —
|
|
4
|
-
// canvas adaptation, in which case add the id to vendor.ts's ADAPTED set.
|
|
2
|
+
// Design-mode fork for the Velloo canvas — not the shadcn the IDE chrome renders.
|
|
3
|
+
// Regenerate with `bun run vendor` — the pipeline is scripts/vendor-shadcn/.
|
|
5
4
|
|
|
6
5
|
import { cva, type VariantProps } from "class-variance-authority";
|
|
7
6
|
import { Slot } from "radix-ui";
|
|
8
7
|
import type * as React from "react";
|
|
9
|
-
|
|
10
8
|
import { cn } from "../../lib/utils.ts";
|
|
9
|
+
|
|
11
10
|
import { Button } from "./button.tsx";
|
|
12
11
|
|
|
13
12
|
const attachmentVariants = cva(
|
|
@@ -1,12 +1,10 @@
|
|
|
1
1
|
// Vendored from shadcn-ui (https://ui.shadcn.com/docs/components/radix/avatar).
|
|
2
|
-
//
|
|
3
|
-
// Regenerate with `bun run vendor` —
|
|
4
|
-
// canvas adaptation, in which case add the id to vendor.ts's ADAPTED set.
|
|
2
|
+
// Design-mode fork for the Velloo canvas — not the shadcn the IDE chrome renders.
|
|
3
|
+
// Regenerate with `bun run vendor` — the pipeline is scripts/vendor-shadcn/.
|
|
5
4
|
"use client";
|
|
6
5
|
|
|
7
6
|
import { Avatar as AvatarPrimitive } from "radix-ui";
|
|
8
7
|
import type * as React from "react";
|
|
9
|
-
|
|
10
8
|
import { cn } from "../../lib/utils.ts";
|
|
11
9
|
|
|
12
10
|
function Avatar({
|
|
@@ -1,12 +1,10 @@
|
|
|
1
1
|
// Vendored from shadcn-ui (https://ui.shadcn.com/docs/components/radix/badge).
|
|
2
|
-
//
|
|
3
|
-
// Regenerate with `bun run vendor` —
|
|
4
|
-
// canvas adaptation, in which case add the id to vendor.ts's ADAPTED set.
|
|
2
|
+
// Design-mode fork for the Velloo canvas — not the shadcn the IDE chrome renders.
|
|
3
|
+
// Regenerate with `bun run vendor` — the pipeline is scripts/vendor-shadcn/.
|
|
5
4
|
|
|
6
5
|
import { cva, type VariantProps } from "class-variance-authority";
|
|
7
6
|
import { Slot } from "radix-ui";
|
|
8
7
|
import type * as React from "react";
|
|
9
|
-
|
|
10
8
|
import { cn } from "../../lib/utils.ts";
|
|
11
9
|
|
|
12
10
|
const badgeVariants = cva(
|
|
@@ -1,12 +1,10 @@
|
|
|
1
1
|
// Vendored from shadcn-ui (https://ui.shadcn.com/docs/components/radix/breadcrumb).
|
|
2
|
-
//
|
|
3
|
-
// Regenerate with `bun run vendor` —
|
|
4
|
-
// canvas adaptation, in which case add the id to vendor.ts's ADAPTED set.
|
|
2
|
+
// Design-mode fork for the Velloo canvas — not the shadcn the IDE chrome renders.
|
|
3
|
+
// Regenerate with `bun run vendor` — the pipeline is scripts/vendor-shadcn/.
|
|
5
4
|
|
|
6
5
|
import { ChevronRightIcon, MoreHorizontalIcon } from "lucide-react";
|
|
7
6
|
import { Slot } from "radix-ui";
|
|
8
7
|
import type * as React from "react";
|
|
9
|
-
|
|
10
8
|
import { cn } from "../../lib/utils.ts";
|
|
11
9
|
|
|
12
10
|
function Breadcrumb({ className, ...props }: React.ComponentProps<"nav">) {
|
|
@@ -1,12 +1,10 @@
|
|
|
1
1
|
// Vendored from shadcn-ui (https://ui.shadcn.com/docs/components/radix/bubble).
|
|
2
|
-
//
|
|
3
|
-
// Regenerate with `bun run vendor` —
|
|
4
|
-
// canvas adaptation, in which case add the id to vendor.ts's ADAPTED set.
|
|
2
|
+
// Design-mode fork for the Velloo canvas — not the shadcn the IDE chrome renders.
|
|
3
|
+
// Regenerate with `bun run vendor` — the pipeline is scripts/vendor-shadcn/.
|
|
5
4
|
|
|
6
5
|
import { cva, type VariantProps } from "class-variance-authority";
|
|
7
6
|
import { Slot } from "radix-ui";
|
|
8
7
|
import type * as React from "react";
|
|
9
|
-
|
|
10
8
|
import { cn } from "../../lib/utils.ts";
|
|
11
9
|
|
|
12
10
|
function BubbleGroup({ className, ...props }: React.ComponentProps<"div">) {
|
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
// Vendored from shadcn-ui (https://ui.shadcn.com/docs/components/radix/button-group).
|
|
2
|
-
//
|
|
3
|
-
// Regenerate with `bun run vendor` —
|
|
4
|
-
// canvas adaptation, in which case add the id to vendor.ts's ADAPTED set.
|
|
2
|
+
// Design-mode fork for the Velloo canvas — not the shadcn the IDE chrome renders.
|
|
3
|
+
// Regenerate with `bun run vendor` — the pipeline is scripts/vendor-shadcn/.
|
|
5
4
|
import { cva, type VariantProps } from "class-variance-authority";
|
|
6
5
|
import { Slot } from "radix-ui";
|
|
7
|
-
|
|
8
6
|
import { cn } from "../../lib/utils.ts";
|
|
7
|
+
|
|
9
8
|
import { Separator } from "./separator.tsx";
|
|
10
9
|
|
|
11
10
|
const buttonGroupVariants = cva(
|
|
@@ -1,12 +1,10 @@
|
|
|
1
1
|
// Vendored from shadcn-ui (https://ui.shadcn.com/docs/components/radix/button).
|
|
2
|
-
//
|
|
3
|
-
// Regenerate with `bun run vendor` —
|
|
4
|
-
// canvas adaptation, in which case add the id to vendor.ts's ADAPTED set.
|
|
2
|
+
// Design-mode fork for the Velloo canvas — not the shadcn the IDE chrome renders.
|
|
3
|
+
// Regenerate with `bun run vendor` — the pipeline is scripts/vendor-shadcn/.
|
|
5
4
|
|
|
6
5
|
import { cva, type VariantProps } from "class-variance-authority";
|
|
7
6
|
import { Slot } from "radix-ui";
|
|
8
7
|
import type * as React from "react";
|
|
9
|
-
|
|
10
8
|
import { cn } from "../../lib/utils.ts";
|
|
11
9
|
|
|
12
10
|
const buttonVariants = cva(
|
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
// Vendored from shadcn-ui (https://ui.shadcn.com/docs/components/radix/card).
|
|
2
|
-
//
|
|
3
|
-
// Regenerate with `bun run vendor` —
|
|
4
|
-
// canvas adaptation, in which case add the id to vendor.ts's ADAPTED set.
|
|
2
|
+
// Design-mode fork for the Velloo canvas — not the shadcn the IDE chrome renders.
|
|
3
|
+
// Regenerate with `bun run vendor` — the pipeline is scripts/vendor-shadcn/.
|
|
5
4
|
import type * as React from "react";
|
|
6
|
-
|
|
7
5
|
import { cn } from "../../lib/utils.ts";
|
|
8
6
|
|
|
9
7
|
function Card({
|
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
// Vendored from shadcn-ui (https://ui.shadcn.com/docs/components/radix/carousel).
|
|
2
|
-
//
|
|
3
|
-
// Regenerate with `bun run vendor` —
|
|
4
|
-
// canvas adaptation, in which case add the id to vendor.ts's ADAPTED set.
|
|
2
|
+
// Design-mode fork for the Velloo canvas — not the shadcn the IDE chrome renders.
|
|
3
|
+
// Regenerate with `bun run vendor` — the pipeline is scripts/vendor-shadcn/.
|
|
5
4
|
"use client";
|
|
6
5
|
|
|
7
6
|
import useEmblaCarousel, { type UseEmblaCarouselType } from "embla-carousel-react";
|
|
8
7
|
import { ChevronLeftIcon, ChevronRightIcon } from "lucide-react";
|
|
9
8
|
import * as React from "react";
|
|
10
|
-
|
|
11
9
|
import { cn } from "../../lib/utils.ts";
|
|
10
|
+
|
|
12
11
|
import { Button } from "./button.tsx";
|
|
13
12
|
|
|
14
13
|
type CarouselApi = UseEmblaCarouselType[1];
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// Velloo-flavored Chart. shadcn's `chart` is a recharts wrapper that needs a
|
|
1
|
+
// Canvas-safe: Velloo-flavored Chart. shadcn's `chart` is a recharts wrapper that needs a
|
|
2
2
|
// measured DOM (ResponsiveContainer), so it renders nothing under the
|
|
3
3
|
// renderer's static SSR. We render a realistic preview server-side via
|
|
4
4
|
// echarts' headless SSR-to-SVG mode (see chart-option.ts) — bar/line/area/
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
// Vendored from shadcn-ui (https://ui.shadcn.com/docs/components/radix/direction).
|
|
2
|
-
//
|
|
3
|
-
// Regenerate with `bun run vendor` —
|
|
4
|
-
// canvas adaptation, in which case add the id to vendor.ts's ADAPTED set.
|
|
2
|
+
// Design-mode fork for the Velloo canvas — not the shadcn the IDE chrome renders.
|
|
3
|
+
// Regenerate with `bun run vendor` — the pipeline is scripts/vendor-shadcn/.
|
|
5
4
|
"use client";
|
|
6
5
|
|
|
7
6
|
import { Direction } from "radix-ui";
|