velloo 0.6.0 → 0.8.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 +121 -225
- package/THIRD-PARTY-NOTICES.md +3 -3
- package/canvas/assets/index-CcPwhD7W.js +31 -0
- package/canvas/assets/index-CkVteRZ9.css +2 -0
- package/canvas/assets/lucide-all-Cezxn40A.js +1 -0
- package/canvas/index.html +2 -2
- package/{chunk-rjjc9vam.js → chunk-07fxzrx2.js} +2 -2
- package/{chunk-ff0jfn0v.js → chunk-32cq4wpr.js} +1 -1
- package/{chunk-nx09zqgs.js → chunk-3612470d.js} +1 -1
- package/{chunk-hf4adxe0.js → chunk-45wv1fs5.js} +8 -8
- package/chunk-4g4c9h7k.js +2 -0
- package/{chunk-8vgpffn7.js → chunk-6w42sr61.js} +1 -1
- package/{chunk-esb7n55g.js → chunk-8n07n0cr.js} +3 -3
- package/{chunk-96qhpth5.js → chunk-8qf0ne1p.js} +1 -1
- package/{chunk-56z5xd5b.js → chunk-8ztgcajz.js} +1 -1
- package/chunk-9g45c5md.js +815 -0
- package/{chunk-w2naqxqt.js → chunk-aefn23tr.js} +1 -1
- package/{chunk-jsvkqae2.js → chunk-asqpx5v7.js} +1 -1
- package/chunk-b4hny6hw.js +3 -0
- package/chunk-bntsn3wj.js +2 -0
- package/{chunk-bc7pkjcn.js → chunk-c4164x55.js} +1 -1
- package/{chunk-mfch0b0t.js → chunk-cg0sjdqt.js} +1 -1
- package/{chunk-3trkmgfr.js → chunk-cq2q36d1.js} +1 -1
- package/chunk-d19ttv1a.js +4 -0
- package/{chunk-8grzf8q1.js → chunk-djwvt6jx.js} +1 -1
- package/chunk-dqqpbmxt.js +22 -0
- package/{chunk-1td6z6ey.js → chunk-dy7qwj3t.js} +1 -1
- package/{chunk-dar6wbf2.js → chunk-ejpccmcj.js} +1 -1
- package/{chunk-pxaxgkaq.js → chunk-emty5315.js} +1 -1
- package/chunk-esg0x95a.js +5 -0
- package/{chunk-k423dkjz.js → chunk-ez720ked.js} +1 -1
- package/{chunk-h85hv05d.js → chunk-ffm2jpxp.js} +1 -1
- package/{chunk-6813v926.js → chunk-g3k8k6fq.js} +3 -3
- package/{chunk-63y5gdzw.js → chunk-h3ser37q.js} +1 -1
- package/{chunk-74yxy75r.js → chunk-hsk91jms.js} +1 -1
- package/chunk-jxgwdz2r.js +5 -0
- package/chunk-kvq7pcph.js +2 -0
- package/chunk-m0v3d581.js +2 -0
- package/chunk-majd3gx9.js +3 -0
- package/{chunk-t2x3mztc.js → chunk-mqtnj8ws.js} +1 -1
- package/{chunk-xtwx2p9g.js → chunk-mqx96m2g.js} +1 -1
- package/{chunk-c4spp880.js → chunk-nrxqr4v5.js} +1 -1
- package/{chunk-g185gx8a.js → chunk-nx0ex7qw.js} +1 -1
- package/{chunk-qwccndcd.js → chunk-q7wwqn03.js} +1 -1
- package/chunk-qgbat4fv.js +6 -0
- package/{chunk-08mjtg1e.js → chunk-qqagacne.js} +1 -1
- package/{chunk-69qb8p8s.js → chunk-qx83fdv2.js} +1 -1
- package/{chunk-ff2vt7cz.js → chunk-r5y1sh4f.js} +1 -1
- package/{chunk-2ba6edh8.js → chunk-rg86bhtb.js} +2 -2
- package/{chunk-x02z2ccm.js → chunk-rhfzy9c0.js} +1 -1
- package/{chunk-t6qr2ay9.js → chunk-rrrn1mkq.js} +1 -1
- package/{chunk-56vfy0db.js → chunk-s1cwck4c.js} +1 -1
- package/{chunk-tac2wvc7.js → chunk-sjxp2bx3.js} +1 -1
- package/chunk-skk6yvnw.js +3 -0
- package/{chunk-52m26hh4.js → chunk-t08391mh.js} +1 -1
- package/{chunk-2q561dec.js → chunk-t61vyqpd.js} +1 -1
- package/{chunk-ta84ehgg.js → chunk-v6ks5v53.js} +1 -1
- package/{chunk-hjc5eg5c.js → chunk-w30zfv3m.js} +1 -1
- package/{chunk-tbd6wn3q.js → chunk-x84qrz4q.js} +1 -1
- package/{chunk-chtv0yj6.js → chunk-xg49s85z.js} +147 -30
- package/{chunk-8cj4swpr.js → chunk-xxw67jpk.js} +3 -3
- package/{chunk-eqjtq673.js → chunk-yjwtdm71.js} +1 -1
- package/{chunk-8vam2893.js → chunk-z6r6wxm6.js} +1 -1
- package/{chunk-hsfpbjpc.js → chunk-zgwvkgsz.js} +1 -1
- package/cli.js +1 -1
- package/launcher.cjs +3 -1
- package/package.json +1 -1
- package/pkgs/helpers/src/box.tsx +12 -6
- package/pkgs/helpers/src/descriptors.ts +6 -0
- package/pkgs/helpers/src/icon.tsx +5 -3
- package/pkgs/helpers/src/index.ts +2 -2
- package/pkgs/helpers/src/text.tsx +29 -5
- package/pkgs/provider-antd/src/index.ts +1 -0
- package/pkgs/provider-antd/src/manifest.ts +1 -0
- package/pkgs/provider-chakra/src/manifest.ts +1 -0
- package/pkgs/provider-html/src/index.ts +1 -0
- package/pkgs/provider-mui/src/index.ts +10 -0
- package/pkgs/provider-mui/src/manifest.ts +1 -0
- package/pkgs/provider-none/src/components-inline.tsx +20 -14
- package/pkgs/provider-none/src/components.tsx +2 -4
- package/pkgs/provider-none/src/index.ts +1 -0
- package/pkgs/schema/src/board.ts +13 -1
- package/pkgs/schema/src/config.ts +38 -1
- package/pkgs/schema/src/flow.ts +230 -0
- package/pkgs/schema/src/frame.ts +7 -0
- package/pkgs/schema/src/index.ts +24 -0
- package/pkgs/schema/src/node-identity.ts +54 -1
- package/pkgs/schema/src/node.ts +114 -26
- package/pkgs/schema/src/snippet-resolve.ts +18 -12
- package/pkgs/schema/src/svg-sanitize.ts +3 -0
- package/pkgs/schema/src/theme.ts +56 -0
- package/pkgs/schema/src/typeset.ts +21 -4
- package/pkgs/shadcn-snapshot/dist/manifest.json +6 -0
- package/plugins/claude/velloo/agents/velloo-designer.md +7 -4
- package/plugins/claude/velloo/commands/setup.md +13 -0
- package/plugins/gemini/GEMINI.md +9 -5
- package/plugins/gemini/commands/velloo/setup.toml +11 -0
- package/skills/velloo-design/SKILL.md +11 -6
- package/skills/velloo-setup/SKILL.md +179 -36
- package/canvas/assets/index-CnyI3aig.js +0 -29
- package/canvas/assets/index-GNLd0pCG.css +0 -2
- package/canvas/assets/lucide-all-CH8LmVh0.js +0 -1
- package/chunk-1gkeepkm.js +0 -2
- package/chunk-2web93qz.js +0 -2
- package/chunk-ab8fga32.js +0 -22
- package/chunk-azeqkms7.js +0 -6
- package/chunk-e2btp1wd.js +0 -3
- package/chunk-ey65err5.js +0 -5
- package/chunk-rk238m15.js +0 -4
- package/chunk-wfhv9jg4.js +0 -2
- package/chunk-wnj432fw.js +0 -3
- package/chunk-yfvc8d2g.js +0 -716
- package/chunk-z73q4dq9.js +0 -2
- package/chunk-ztsckexy.js +0 -5
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
import{fail}from"./chunk-s23gtejf.js";import"./chunk-
|
|
2
|
+
import{fail}from"./chunk-s23gtejf.js";import"./chunk-32cq4wpr.js";import{SHELLS,completionScript,commandSpecs,detectShell,installCompletions}from"./chunk-asqpx5v7.js";import{require_picocolors}from"./chunk-jrsknzjt.js";import{__toESM,defineCommand}from"./chunk-2smsg2ct.js";var import_picocolors=__toESM(require_picocolors(),1);var completions_default=defineCommand({meta:{name:"completions",description:"Shell TAB completions \u2014 print the script, or install it with --install"},args:{shell:{type:"positional",required:!1,description:`Shell: ${SHELLS.join(" | ")} (default: detected from $SHELL)`},install:{type:"boolean",default:!1,description:"Write the script + wire it into your shell (idempotent)"}},async run({args}){let shell=args.shell??detectShell();if(!shell||!SHELLS.includes(shell))fail("completions",`unsupported or undetected shell${args.shell?` "${args.shell}"`:""} \u2014 pass one of: ${SHELLS.join(", ")}.`);if(!args.install){console.log(completionScript(shell,await commandSpecs()));return}let r=await installCompletions(shell);if(console.log(""),console.log(import_picocolors.default.green(`\u2713 ${shell} completions installed.`)),console.log(` script ${import_picocolors.default.cyan(r.scriptPath)}`),r.rcPath)console.log(r.rcUpdated?` rc ${import_picocolors.default.cyan(r.rcPath)} ${import_picocolors.default.dim("(source line appended)")}`:` rc ${import_picocolors.default.cyan(r.rcPath)} ${import_picocolors.default.dim("(already wired)")}`);console.log(""),console.log(import_picocolors.default.dim(shell==="fish"?" New fish sessions pick it up automatically.":` Restart your shell (or \`source ${r.rcPath}\`) to activate TAB completion.`))}});export{completions_default as default};
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
import{CURRENT_SCHEMA_VERSION}from"./chunk-
|
|
2
|
+
import{CURRENT_SCHEMA_VERSION}from"./chunk-xxw67jpk.js";import{snapshotVersion2}from"./chunk-p93x4pn2.js";import{TOOL_VERSION}from"./chunk-rrrn1mkq.js";function buildDefaultConfig(opts={}){return{schemaVersion:CURRENT_SCHEMA_VERSION,toolVersion:TOOL_VERSION,name:opts.name??"design",folderId:crypto.randomUUID(),libraries:{default:opts.library??{id:"shadcn-upstream",version:snapshotVersion2,source:"binary",componentsPath:"binary"}},defaultLibrary:"default",viewportPresets:[{name:"Mobile",w:390,h:844},{name:"Tablet",w:768,h:1024},{name:"Desktop",w:1440,h:900}],...opts.defaultScreen?{defaultScreen:opts.defaultScreen}:{},...opts.defaultBoard?{defaultBoard:opts.defaultBoard}:{},...opts.hostApp?{hostApp:opts.hostApp}:{},...opts.hostApps?{hostApps:opts.hostApps}:{},...opts.feedback?{feedback:opts.feedback}:{},...opts.styling?{styling:opts.styling}:{},...opts.codegen?{codegen:opts.codegen}:{},...opts.designSystem?{designSystem:opts.designSystem}:{},...opts.themeSource?{themeSource:opts.themeSource}:{}}}
|
|
3
3
|
export{buildDefaultConfig};
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
import"./chunk-
|
|
2
|
+
import"./chunk-bntsn3wj.js";import"./chunk-xxw67jpk.js";import{normalizeCloudUrl,loadCredential,listCredentials,deleteCredential,clearCredentials,revokeCredential}from"./chunk-rg86bhtb.js";import{defaultCloudUrl}from"./chunk-w30zfv3m.js";import{defineCommand}from"./chunk-2smsg2ct.js";var logout_default=defineCommand({meta:{name:"logout",description:"Log out of velloo-cloud (signs the CLI token out and removes it)"},args:{url:{type:"string",description:"velloo-cloud base URL (default: $VELLOO_CLOUD_URL or the built-in default)"},all:{type:"boolean",default:!1,description:"Remove saved credentials for every cloud"}},async run({args}){if(args.all){await Promise.all(Object.entries(await listCredentials()).map(([cloudUrl,credential])=>revokeCredential(cloudUrl,credential.token)));let count=await clearCredentials();console.log(count>0?`velloo logout: removed credentials for ${count} cloud${count===1?"":"s"}`:"velloo logout: no saved credentials");return}let cloudUrl=args.url?normalizeCloudUrl(args.url):defaultCloudUrl(),existing=await loadCredential(cloudUrl);if(existing)await revokeCredential(cloudUrl,existing.token);if(await deleteCredential(cloudUrl))console.log(`velloo logout: logged out of ${cloudUrl}${existing?.email?` (${existing.email})`:""}`);else console.log(`velloo logout: not logged in to ${cloudUrl}`)}});export{logout_default as default};
|
package/cli.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
#!/usr/bin/env bun
|
|
2
2
|
// @bun
|
|
3
|
-
import"./chunk-s23gtejf.js";import{COMMANDS}from"./chunk-
|
|
3
|
+
import"./chunk-s23gtejf.js";import{COMMANDS}from"./chunk-32cq4wpr.js";import{TOOL_VERSION}from"./chunk-rrrn1mkq.js";import{maybeNotifyAboutUpdate}from"./chunk-d19ttv1a.js";import{defineCommand,runMain}from"./chunk-2smsg2ct.js";var main=defineCommand({meta:{name:"velloo",version:TOOL_VERSION,description:"Open-source, local-first canvas for agent-driven design."},subCommands:COMMANDS});await runMain(main);var command=process.argv[2];if(!["mcp","__daemon","__update_check","run","upgrade"].includes(command??""))await maybeNotifyAboutUpdate();
|
package/launcher.cjs
CHANGED
|
@@ -80,7 +80,9 @@ const runtime = join(runtimeRoot, "bin", process.platform === "win32" ? "bun.exe
|
|
|
80
80
|
if (!existsSync(runtime)) die(`the Bun runtime package ${runtimeName} is incomplete`);
|
|
81
81
|
|
|
82
82
|
const app = join(__dirname, "cli.js");
|
|
83
|
-
|
|
83
|
+
// `--no-install`: Bun must never answer an import from its global cache or
|
|
84
|
+
// fetch a package to do it — see BUN_RUNTIME_FLAGS in src/bun-runtime.ts.
|
|
85
|
+
const child = spawnSync(runtime, ["--no-install", app, ...process.argv.slice(2)], {
|
|
84
86
|
stdio: "inherit",
|
|
85
87
|
env: {
|
|
86
88
|
...process.env,
|
package/package.json
CHANGED
package/pkgs/helpers/src/box.tsx
CHANGED
|
@@ -9,13 +9,19 @@ import type * as React from "react";
|
|
|
9
9
|
import { createElement } from "react";
|
|
10
10
|
import { cn } from "./cn.ts";
|
|
11
11
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
12
|
+
/**
|
|
13
|
+
* An element name: an HTML tag, or one of SVG's camelCase ones
|
|
14
|
+
* (`linearGradient`, `clipPath`). Shared by everything that has to agree on
|
|
15
|
+
* what `as` may hold — compose's lowering, each `Box`, and codegen — because a
|
|
16
|
+
* tag one of them accepts and another doesn't renders as a `div`.
|
|
17
|
+
*/
|
|
18
|
+
export const ELEMENT_TAG = /^[a-z][a-zA-Z0-9]*$/;
|
|
17
19
|
|
|
20
|
+
// Restrict `as` to an element name. Anything else (a component reference, an
|
|
21
|
+
// injection attempt) falls back to div. Rendering the real tag means inline
|
|
22
|
+
// elements (span/strong/a/…) get their natural inline display from the UA
|
|
23
|
+
// stylesheet, instead of a div's block stacking inline runs.
|
|
18
24
|
export function Box({ as, className, ...props }: React.ComponentProps<"div"> & { as?: string }) {
|
|
19
|
-
const tag = typeof as === "string" &&
|
|
25
|
+
const tag = typeof as === "string" && ELEMENT_TAG.test(as) ? as : "div";
|
|
20
26
|
return createElement(tag, { "data-slot": "box", className: cn(className), ...props });
|
|
21
27
|
}
|
|
@@ -233,6 +233,12 @@ export const HELPER_DESCRIPTORS: readonly ComponentDescriptor[] = [
|
|
|
233
233
|
props: [
|
|
234
234
|
{ name: "content", type: "string | undefined", optional: true, control: "string" },
|
|
235
235
|
{ name: "viewBox", type: "string | undefined", optional: true, control: "string" },
|
|
236
|
+
{
|
|
237
|
+
name: "preserveAspectRatio",
|
|
238
|
+
type: "string | undefined",
|
|
239
|
+
optional: true,
|
|
240
|
+
control: "string",
|
|
241
|
+
},
|
|
236
242
|
{ name: "color", type: "string | undefined", optional: true, control: "color" },
|
|
237
243
|
],
|
|
238
244
|
example: {
|
|
@@ -27,11 +27,13 @@ function lookup(name: string): IconNode | undefined {
|
|
|
27
27
|
return viaPascal === undefined ? undefined : ICON_NODES[viaPascal];
|
|
28
28
|
}
|
|
29
29
|
|
|
30
|
-
const FALLBACK = lookup("HelpCircle");
|
|
31
|
-
|
|
32
30
|
export function Icon({ name, className, size = 16, strokeWidth = 2, ...props }: IconProps) {
|
|
33
31
|
const hit = lookup(name);
|
|
34
|
-
|
|
32
|
+
// Looked up here, not once at module level: a call at the top of this file
|
|
33
|
+
// is a side effect to a bundler, which then keeps the module — and the 0.6 MB
|
|
34
|
+
// of icon data behind it — in every bundle that imports anything at all from
|
|
35
|
+
// the helpers index, `Icon` on the screen or not.
|
|
36
|
+
const node = hit ?? lookup("HelpCircle");
|
|
35
37
|
if (!node) return null;
|
|
36
38
|
const tint = hit ? className : cn("text-[var(--color-fg-muted)]", className);
|
|
37
39
|
return (
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { Box } from "./box.tsx";
|
|
1
|
+
export { Box, ELEMENT_TAG } from "./box.tsx";
|
|
2
2
|
export { cn, mergeTailwind } from "./cn.ts";
|
|
3
3
|
export { HELPER_DESCRIPTORS, helperDescriptors } from "./descriptors.ts";
|
|
4
4
|
export { Divider, type DividerProps } from "./divider.tsx";
|
|
@@ -29,4 +29,4 @@ export {
|
|
|
29
29
|
export { Prose, type ProseProps } from "./prose.tsx";
|
|
30
30
|
export { helpersRegistry } from "./registry.ts";
|
|
31
31
|
export { SVG, type SVGProps } from "./svg.tsx";
|
|
32
|
-
export { Text, type TextProps } from "./text.tsx";
|
|
32
|
+
export { Text, type TextProps, TextRunContext, textTag } from "./text.tsx";
|
|
@@ -3,14 +3,38 @@ import { textClasses } from "@velloo/schema/typeset";
|
|
|
3
3
|
import * as React from "react";
|
|
4
4
|
import { cn } from "./cn.ts";
|
|
5
5
|
|
|
6
|
-
export interface TextProps extends React.HTMLAttributes<
|
|
6
|
+
export interface TextProps extends React.HTMLAttributes<HTMLElement> {
|
|
7
7
|
/** Visual weight. Selects a rung of the theme's type ladder plus a tone. */
|
|
8
8
|
variant?: "default" | "muted" | "small" | "lead";
|
|
9
9
|
}
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
11
|
+
/**
|
|
12
|
+
* True beneath a `Text`. A paragraph cannot hold a paragraph: an HTML parser
|
|
13
|
+
* ends the outer `<p>` where the inner one starts, so markup that is rendered
|
|
14
|
+
* on the server and parsed again (a screenshot, a comparison) lays the inner
|
|
15
|
+
* text out as a sibling, while the same tree mounted on the client keeps it
|
|
16
|
+
* nested. A `Text` inside a `Text` is a run of that paragraph, so it renders
|
|
17
|
+
* the element a run is — and every path draws the same line.
|
|
18
|
+
*/
|
|
19
|
+
export const TextRunContext = React.createContext(false);
|
|
20
|
+
|
|
21
|
+
/** The element a `Text` renders: a paragraph, or a run inside one. */
|
|
22
|
+
export function textTag(run: boolean): "p" | "span" {
|
|
23
|
+
return run ? "span" : "p";
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export const Text = React.forwardRef<HTMLElement, TextProps>(
|
|
27
|
+
({ variant, className, ...props }, ref) => {
|
|
28
|
+
const run = React.useContext(TextRunContext);
|
|
29
|
+
return (
|
|
30
|
+
<TextRunContext.Provider value={true}>
|
|
31
|
+
{React.createElement(textTag(run), {
|
|
32
|
+
ref,
|
|
33
|
+
className: cn(textClasses(variant, run), className) || undefined,
|
|
34
|
+
...props,
|
|
35
|
+
})}
|
|
36
|
+
</TextRunContext.Provider>
|
|
37
|
+
);
|
|
38
|
+
},
|
|
15
39
|
);
|
|
16
40
|
Text.displayName = "Text";
|
|
@@ -54,6 +54,7 @@ export function createProvider(): FrameworkAdapter {
|
|
|
54
54
|
),
|
|
55
55
|
styleChannel: STYLE_PROP,
|
|
56
56
|
styleChannels: ["style"],
|
|
57
|
+
themeRoles: ["background", "foreground", "primary", "destructive", "card"],
|
|
57
58
|
mcpIntro: () => [...ANTD_INTRO],
|
|
58
59
|
renderPass: (theme, dark) => makeRenderPass(theme, dark ?? false),
|
|
59
60
|
codegenModule: "antd",
|
|
@@ -838,6 +838,7 @@ export const ANTD_MANIFEST: Manifest = [
|
|
|
838
838
|
[
|
|
839
839
|
{ name: "content", type: "string", optional: false, control: "string" },
|
|
840
840
|
{ name: "viewBox", type: "string", optional: false, control: "string" },
|
|
841
|
+
{ name: "preserveAspectRatio", type: "string", optional: true, control: "string" },
|
|
841
842
|
],
|
|
842
843
|
"Raw inline SVG markup.",
|
|
843
844
|
),
|
|
@@ -403,6 +403,7 @@ export const CHAKRA_MANIFEST: Manifest = [
|
|
|
403
403
|
[
|
|
404
404
|
{ name: "content", type: "string", optional: false, control: "string" },
|
|
405
405
|
{ name: "viewBox", type: "string", optional: false, control: "string" },
|
|
406
|
+
{ name: "preserveAspectRatio", type: "string", optional: true, control: "string" },
|
|
406
407
|
],
|
|
407
408
|
"Raw inline SVG markup.",
|
|
408
409
|
),
|
|
@@ -59,6 +59,7 @@ export function createProvider(): FrameworkAdapter {
|
|
|
59
59
|
loadManifest: async () => HTML_MANIFEST,
|
|
60
60
|
styleChannel: STYLE_PROP,
|
|
61
61
|
styleChannels: ["style"],
|
|
62
|
+
themeRoles: ["background", "foreground", "card", "muted", "border", "input"],
|
|
62
63
|
registryForChannel: () => registry,
|
|
63
64
|
mcpIntro: () => HTML_INTRO,
|
|
64
65
|
hostStylesheets: true,
|
|
@@ -57,6 +57,16 @@ export function createProvider(): FrameworkAdapter {
|
|
|
57
57
|
),
|
|
58
58
|
styleChannel: SX_PROP,
|
|
59
59
|
styleChannels: ["sx"],
|
|
60
|
+
themeRoles: [
|
|
61
|
+
"background",
|
|
62
|
+
"foreground",
|
|
63
|
+
"primary",
|
|
64
|
+
"secondary",
|
|
65
|
+
"destructive",
|
|
66
|
+
"card",
|
|
67
|
+
"muted",
|
|
68
|
+
"border",
|
|
69
|
+
],
|
|
60
70
|
mcpIntro: () => [...MUI_INTRO],
|
|
61
71
|
renderPass: (theme, dark) => makeRenderPass(theme, dark ?? false),
|
|
62
72
|
codegenModule: "@mui/material",
|
|
@@ -250,6 +250,7 @@ export const MUI_MANIFEST: Manifest = [
|
|
|
250
250
|
[
|
|
251
251
|
{ name: "content", type: "string", optional: false, control: "string" },
|
|
252
252
|
{ name: "viewBox", type: "string", optional: false, control: "string" },
|
|
253
|
+
{ name: "preserveAspectRatio", type: "string", optional: true, control: "string" },
|
|
253
254
|
],
|
|
254
255
|
"Raw inline SVG markup.",
|
|
255
256
|
),
|
|
@@ -1,12 +1,7 @@
|
|
|
1
|
+
import { ELEMENT_TAG, TextRunContext, textTag } from "@velloo/helpers";
|
|
1
2
|
import { headingInlineStyle, textInlineStyle } from "@velloo/schema/typeset";
|
|
2
3
|
import * as React from "react";
|
|
3
|
-
import {
|
|
4
|
-
BOX_TAG,
|
|
5
|
-
type ButtonProps,
|
|
6
|
-
type ContainerProps,
|
|
7
|
-
type InputProps,
|
|
8
|
-
type StackProps,
|
|
9
|
-
} from "./components.tsx";
|
|
4
|
+
import type { ButtonProps, ContainerProps, InputProps, StackProps } from "./components.tsx";
|
|
10
5
|
|
|
11
6
|
/**
|
|
12
7
|
* Inline-styled variants of the no-library primitives, for a `none`-CSS folder
|
|
@@ -38,7 +33,10 @@ export const Box = React.forwardRef<
|
|
|
38
33
|
HTMLDivElement,
|
|
39
34
|
React.HTMLAttributes<HTMLDivElement> & { as?: string }
|
|
40
35
|
>(({ as, ...rest }, ref) =>
|
|
41
|
-
React.createElement(typeof as === "string" &&
|
|
36
|
+
React.createElement(typeof as === "string" && ELEMENT_TAG.test(as) ? as : "div", {
|
|
37
|
+
ref,
|
|
38
|
+
...rest,
|
|
39
|
+
}),
|
|
42
40
|
);
|
|
43
41
|
Box.displayName = "Box";
|
|
44
42
|
|
|
@@ -201,13 +199,21 @@ export const Heading = React.forwardRef<HTMLHeadingElement, HeadingProps>(
|
|
|
201
199
|
);
|
|
202
200
|
Heading.displayName = "Heading";
|
|
203
201
|
|
|
204
|
-
interface TextProps extends React.HTMLAttributes<
|
|
202
|
+
interface TextProps extends React.HTMLAttributes<HTMLElement> {
|
|
205
203
|
variant?: "default" | "muted" | "small" | "lead";
|
|
206
204
|
}
|
|
207
205
|
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
206
|
+
// A `Text` inside a `Text` is a run of it — see `TextRunContext`.
|
|
207
|
+
export const Text = React.forwardRef<HTMLElement, TextProps>(({ variant, style, ...rest }, ref) => {
|
|
208
|
+
const run = React.useContext(TextRunContext);
|
|
209
|
+
return (
|
|
210
|
+
<TextRunContext.Provider value={true}>
|
|
211
|
+
{React.createElement(textTag(run), {
|
|
212
|
+
ref,
|
|
213
|
+
style: merge(textInlineStyle(variant, run), style),
|
|
214
|
+
...rest,
|
|
215
|
+
})}
|
|
216
|
+
</TextRunContext.Provider>
|
|
217
|
+
);
|
|
218
|
+
});
|
|
213
219
|
Text.displayName = "Text";
|
|
@@ -3,6 +3,7 @@ import {
|
|
|
3
3
|
BUTTON_VARIANT_CLASS,
|
|
4
4
|
CARD_CLASS,
|
|
5
5
|
CONTAINER_WIDTH_CLASS,
|
|
6
|
+
ELEMENT_TAG,
|
|
6
7
|
INPUT_CLASS,
|
|
7
8
|
STACK_ALIGN_CLASS,
|
|
8
9
|
STACK_JUSTIFY_CLASS,
|
|
@@ -23,12 +24,9 @@ import * as React from "react";
|
|
|
23
24
|
|
|
24
25
|
interface DivProps extends React.HTMLAttributes<HTMLDivElement> {}
|
|
25
26
|
|
|
26
|
-
/** `as` takes a lowercase HTML tag only — anything else renders the div. */
|
|
27
|
-
export const BOX_TAG = /^[a-z][a-z0-9]*$/;
|
|
28
|
-
|
|
29
27
|
export const Box = React.forwardRef<HTMLDivElement, DivProps & { as?: string }>(
|
|
30
28
|
({ as, className, ...rest }, ref) =>
|
|
31
|
-
React.createElement(typeof as === "string" &&
|
|
29
|
+
React.createElement(typeof as === "string" && ELEMENT_TAG.test(as) ? as : "div", {
|
|
32
30
|
ref,
|
|
33
31
|
className: clsx(className),
|
|
34
32
|
...rest,
|
|
@@ -59,6 +59,7 @@ export function createProvider(): FrameworkAdapter {
|
|
|
59
59
|
// is `none` resolves to the inline-`style` channel instead.
|
|
60
60
|
styleChannel: TAILWIND_CLASSNAME,
|
|
61
61
|
styleChannels: ["tailwind-classname", "style"],
|
|
62
|
+
themeRoles: ["background", "foreground", "card", "muted", "border", "input"],
|
|
62
63
|
mcpIntro: (channel) => [...(channel === "style" ? NONE_INLINE_INTRO : NONE_INTRO)],
|
|
63
64
|
// Inline-styled primitives for the `style` channel; Tailwind-classed for
|
|
64
65
|
// every other channel. Lets a `none/none` folder paint with the JIT off.
|
package/pkgs/schema/src/board.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
+
import { FlowEdgeSchema } from "./flow.ts";
|
|
2
3
|
import { FrameSchema } from "./frame.ts";
|
|
3
4
|
import { ResourceIdSchema } from "./ids.ts";
|
|
4
5
|
|
|
@@ -12,7 +13,11 @@ import { ResourceIdSchema } from "./ids.ts";
|
|
|
12
13
|
export const BoardGroupSchema = z.object({
|
|
13
14
|
id: ResourceIdSchema,
|
|
14
15
|
name: z.string().min(1),
|
|
15
|
-
/**
|
|
16
|
+
/**
|
|
17
|
+
* CSS color value. The sidebar uses a board group's for its chip and rail;
|
|
18
|
+
* a frame group may carry one, but the canvas draws nothing for frame
|
|
19
|
+
* groups yet.
|
|
20
|
+
*/
|
|
16
21
|
color: z.string().optional(),
|
|
17
22
|
});
|
|
18
23
|
|
|
@@ -61,6 +66,13 @@ export const BoardSchema = z.object({
|
|
|
61
66
|
frames: z.array(FrameSchema).default([]),
|
|
62
67
|
/** Frame regions within this board (see {@link BoardGroupSchema}). */
|
|
63
68
|
groups: z.array(BoardGroupSchema).default([]),
|
|
69
|
+
/**
|
|
70
|
+
* Arrows between this board's frames (see {@link FlowEdgeSchema}). Absent ⇒
|
|
71
|
+
* a board of unconnected frames, which is every existing one — and the field
|
|
72
|
+
* is dropped again when the last arrow goes, so such a board's file never
|
|
73
|
+
* changes shape.
|
|
74
|
+
*/
|
|
75
|
+
edges: z.array(FlowEdgeSchema).optional(),
|
|
64
76
|
});
|
|
65
77
|
|
|
66
78
|
export type Board = z.infer<typeof BoardSchema>;
|
|
@@ -106,6 +106,38 @@ export const HostAppSchema = z.object({
|
|
|
106
106
|
|
|
107
107
|
export type HostApp = z.infer<typeof HostAppSchema>;
|
|
108
108
|
|
|
109
|
+
/**
|
|
110
|
+
* Where the design's theme came from in the app: what `velloo init` read (or
|
|
111
|
+
* left alone), and what an `import_theme` from a stylesheet into the default
|
|
112
|
+
* theme records again. Agents are told by it what checking the theme against
|
|
113
|
+
* the app means — a theme read from a JavaScript theme object (`mantine`,
|
|
114
|
+
* `mui`) is compared with that module, since no stylesheet holds it.
|
|
115
|
+
*
|
|
116
|
+
* "stylesheet" — the app's stylesheet, and what it brings with it.
|
|
117
|
+
* "design-md" — a DESIGN.md, layered on the stylesheet.
|
|
118
|
+
* "mantine" / "mui" — the theme object the app hands that library.
|
|
119
|
+
* "library-defaults" — the app uses `library` and sets no theme of its own,
|
|
120
|
+
* so the design is on that library's.
|
|
121
|
+
* "preset" — nothing of the app's: a built-in preset.
|
|
122
|
+
*/
|
|
123
|
+
export const ThemeSourceSchema = z.object({
|
|
124
|
+
kind: z.enum(["stylesheet", "design-md", "mantine", "mui", "library-defaults", "preset"]),
|
|
125
|
+
/**
|
|
126
|
+
* The app's files it was read from, relative to the app root, the one
|
|
127
|
+
* `kind` names first: a stylesheet is followed by the sheets it imports,
|
|
128
|
+
* the tailwind.config it merged and the modules whose font loader calls
|
|
129
|
+
* set a face. Absent when nothing was read from a file in the app.
|
|
130
|
+
*/
|
|
131
|
+
files: z.array(AppRelativePathSchema).min(1).optional(),
|
|
132
|
+
/** The library whose own theme it is — for `"library-defaults"`. */
|
|
133
|
+
library: z.string().min(1).optional(),
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
export type ThemeSource = z.infer<typeof ThemeSourceSchema>;
|
|
137
|
+
|
|
138
|
+
/** The CSS framework a folder styles with. See `ConfigSchema.styling`. */
|
|
139
|
+
export const StylingSchema = z.object({ framework: z.enum(["tailwind", "none"]) });
|
|
140
|
+
|
|
109
141
|
/**
|
|
110
142
|
* Folder config. Multi-library: a folder registers N libraries by id
|
|
111
143
|
* and pins one as the default; each screen optionally declares which
|
|
@@ -186,7 +218,7 @@ export const ConfigSchema = z
|
|
|
186
218
|
* server rejects a folder whose CSS framework no registered library
|
|
187
219
|
* supports (e.g. shadcn + none).
|
|
188
220
|
*/
|
|
189
|
-
styling:
|
|
221
|
+
styling: StylingSchema.optional(),
|
|
190
222
|
/** Host app location for the live-island bundler. See `HostAppSchema`. */
|
|
191
223
|
hostApp: HostAppSchema.optional(),
|
|
192
224
|
/**
|
|
@@ -203,6 +235,11 @@ export const ConfigSchema = z
|
|
|
203
235
|
* a file somewhere unconventional, or pins the choice when several exist.
|
|
204
236
|
*/
|
|
205
237
|
designSystem: z.object({ path: AppRelativePathSchema }).optional(),
|
|
238
|
+
/**
|
|
239
|
+
* Where the default theme was read from in the app. See `ThemeSourceSchema`.
|
|
240
|
+
* Absent for a design made before it was recorded: nothing is assumed.
|
|
241
|
+
*/
|
|
242
|
+
themeSource: ThemeSourceSchema.optional(),
|
|
206
243
|
/**
|
|
207
244
|
* Named host apps for monorepos — the multi-app twin of `hostApp`, keyed
|
|
208
245
|
* by a short app name (`"web"`, `"admin"`; `init`'s multi-app scan uses
|