@synopackageland/ui 0.6.0 → 0.7.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 +1 -1
- package/dist/cli.js +122 -113
- package/dist/index.js +8 -8
- package/dist/json/catalog.d.ts +1 -1
- package/dist/json-ai-prompt.md +6 -3
- package/dist/json-preview/preview.js +3 -3
- package/dist/json.js +19 -19
- package/dist/reka-runtime.json +1 -1
- package/docs/json-ui.md +9 -6
- package/package.json +4 -1
package/README.md
CHANGED
|
@@ -7,7 +7,7 @@ Import the components you need into your Vue application.
|
|
|
7
7
|
|
|
8
8
|
For DSM window / full-page Portal / phone layouts, see
|
|
9
9
|
[Responsive DSM application layout](docs/adaptive-layout.md). To generate UI
|
|
10
|
-
as JSON (including with an AI and the `syno-ui` validate/render CLI), see
|
|
10
|
+
as JSON (including with an AI and the `syno-pkg-land-ui` validate/render CLI), see
|
|
11
11
|
[Declarative DSM UI](docs/json-ui.md).
|
|
12
12
|
|
|
13
13
|
Synology Package Land UI provides Vue components for Synology package applications,
|
package/dist/cli.js
CHANGED
|
@@ -1,83 +1,90 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { readFile as
|
|
2
|
+
import { readFile as S, mkdtemp as E, mkdir as M, writeFile as D, rm as R } from "node:fs/promises";
|
|
3
3
|
import { createServer as F } from "node:http";
|
|
4
4
|
import { tmpdir as H } from "node:os";
|
|
5
|
-
import { join as
|
|
5
|
+
import { join as g, win32 as U, posix as j } from "node:path";
|
|
6
6
|
import { spawn as I } from "node:child_process";
|
|
7
|
-
import { existsSync as
|
|
7
|
+
import { existsSync as f } from "node:fs";
|
|
8
8
|
import { setTimeout as L } from "node:timers/promises";
|
|
9
9
|
import { synoJsonAiPrompt as T, synoJsonSchema as W, describeSynoJsonComponent as _, closestSynoJsonComponent as V, listSynoJsonComponents as B, validateSynoJsonSpec as G } from "./json.js";
|
|
10
10
|
const K = [
|
|
11
11
|
"/Applications/Google Chrome.app/Contents/MacOS/Google Chrome",
|
|
12
12
|
"/Applications/Chromium.app/Contents/MacOS/Chromium"
|
|
13
13
|
], X = ["google-chrome", "google-chrome-stable", "chromium", "chromium-browser"], z = ["ProgramFiles", "ProgramFiles(x86)", "LOCALAPPDATA"];
|
|
14
|
-
function Q(e = process.env, t = process.platform, n =
|
|
15
|
-
return e.CHROME ? e.CHROME : (t === "darwin" ? K : t === "win32" ? z.flatMap((
|
|
14
|
+
function Q(e = process.env, t = process.platform, n = f) {
|
|
15
|
+
return e.CHROME ? e.CHROME : (t === "darwin" ? K : t === "win32" ? z.flatMap((r) => e[r] ? [U.join(e[r], "Google", "Chrome", "Application", "chrome.exe")] : []) : (e.PATH ?? "").split(j.delimiter).filter(Boolean).flatMap((r) => X.map((o) => j.join(r, o)))).find(n);
|
|
16
16
|
}
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
if (!t) throw new Error("Chrome or Chromium was not found; set CHROME to its executable path.");
|
|
20
|
-
const n = I(t, [
|
|
17
|
+
function Y(e, t = process.env) {
|
|
18
|
+
return [
|
|
21
19
|
"--headless=new",
|
|
22
20
|
"--disable-gpu",
|
|
23
21
|
"--hide-scrollbars",
|
|
24
22
|
"--no-first-run",
|
|
23
|
+
// Repaint whole tiles: partial raster redraws only the invalidated rect, and
|
|
24
|
+
// the anti-aliased edges it touches can come out one colour level apart, so
|
|
25
|
+
// the same page could otherwise screenshot differently from run to run.
|
|
26
|
+
"--disable-partial-raster",
|
|
25
27
|
// GitHub's Ubuntu AppArmor policy blocks the unprivileged Chromium sandbox.
|
|
26
28
|
// Match Playwright's CI launch defaults for these repository-only fixtures.
|
|
27
|
-
...
|
|
29
|
+
...t.CI ? ["--no-sandbox", "--disable-dev-shm-usage"] : [],
|
|
28
30
|
"--remote-debugging-port=0",
|
|
29
31
|
`--user-data-dir=${e}`,
|
|
30
32
|
"about:blank"
|
|
31
|
-
]
|
|
32
|
-
|
|
33
|
+
];
|
|
34
|
+
}
|
|
35
|
+
async function Z(e) {
|
|
36
|
+
const t = Q();
|
|
37
|
+
if (!t) throw new Error("Chrome or Chromium was not found; set CHROME to its executable path.");
|
|
38
|
+
const n = I(t, Y(e), { stdio: ["ignore", "ignore", "pipe"] });
|
|
39
|
+
let s, r = "";
|
|
33
40
|
n.once("error", (a) => {
|
|
34
41
|
s = a;
|
|
35
42
|
}), n.stderr.on("data", (a) => {
|
|
36
|
-
|
|
43
|
+
r = (r + a).slice(-4e3);
|
|
37
44
|
});
|
|
38
|
-
const
|
|
39
|
-
for (let a = 0; a < 100 && !
|
|
40
|
-
if (!
|
|
41
|
-
throw n.kill(), new Error(`Chrome failed to start: ${s?.message ?? (
|
|
42
|
-
const [i] = (await
|
|
45
|
+
const o = g(e, "DevToolsActivePort");
|
|
46
|
+
for (let a = 0; a < 100 && !f(o) && !s && n.exitCode === null; a++) await L(100);
|
|
47
|
+
if (!f(o))
|
|
48
|
+
throw n.kill(), new Error(`Chrome failed to start: ${s?.message ?? (r || "no debugging port within 10 seconds")}`);
|
|
49
|
+
const [i] = (await S(o, "utf8")).split(`
|
|
43
50
|
`), c = await (await fetch(`http://127.0.0.1:${i}/json/new?about:blank`, { method: "PUT" })).json(), d = new WebSocket(c.webSocketDebuggerUrl);
|
|
44
|
-
await new Promise((a,
|
|
45
|
-
d.onopen = a, d.onerror =
|
|
51
|
+
await new Promise((a, u) => {
|
|
52
|
+
d.onopen = a, d.onerror = u;
|
|
46
53
|
});
|
|
47
54
|
let l = 1;
|
|
48
|
-
const
|
|
55
|
+
const m = /* @__PURE__ */ new Map();
|
|
49
56
|
d.onmessage = (a) => {
|
|
50
|
-
const
|
|
51
|
-
|
|
57
|
+
const u = JSON.parse(String(a.data));
|
|
58
|
+
m.get(u.id)?.(u), m.delete(u.id);
|
|
52
59
|
};
|
|
53
|
-
const b = (a,
|
|
60
|
+
const b = (a, u = {}) => new Promise((A, P) => {
|
|
54
61
|
const O = l++;
|
|
55
|
-
|
|
62
|
+
m.set(O, (w) => w.error ? P(new Error(w.error.message)) : A(w.result)), d.send(JSON.stringify({ id: O, method: a, params: u }));
|
|
56
63
|
});
|
|
57
64
|
await b("Emulation.setDeviceMetricsOverride", { width: 1100, height: 720, deviceScaleFactor: 1, mobile: !1 });
|
|
58
|
-
const
|
|
59
|
-
return { send: b, close: () => (d.close(), n.kill(),
|
|
65
|
+
const N = new Promise((a) => n.once("exit", a));
|
|
66
|
+
return { send: b, close: () => (d.close(), n.kill(), N) };
|
|
60
67
|
}
|
|
61
|
-
const
|
|
68
|
+
const q = `<!doctype html>
|
|
62
69
|
<html><head><meta charset="utf-8"><link rel="stylesheet" href="/theme.css">
|
|
63
70
|
<style>html, body, #app { margin: 0; height: 100%; }</style></head>
|
|
64
71
|
<body><div id="app"></div><script type="module" src="/preview.js"><\/script></body></html>`;
|
|
65
|
-
function
|
|
72
|
+
function ee(e, t) {
|
|
66
73
|
const n = {
|
|
67
74
|
"/theme.css": [new URL("theme.css", e), "text/css"],
|
|
68
75
|
"/preview.js": [new URL("json-preview/preview.js", e), "text/javascript"]
|
|
69
|
-
}, s = F(async (
|
|
70
|
-
const i = new URL(
|
|
76
|
+
}, s = F(async (r, o) => {
|
|
77
|
+
const i = new URL(r.url ?? "/", "http://localhost").pathname;
|
|
71
78
|
try {
|
|
72
|
-
const [c, d] = i === "/" ? [
|
|
73
|
-
|
|
79
|
+
const [c, d] = i === "/" ? [q, "text/html"] : i === "/config.json" ? [t, "application/json"] : [await S(n[i][0]), n[i][1]];
|
|
80
|
+
o.writeHead(200, { "content-type": d }).end(c);
|
|
74
81
|
} catch {
|
|
75
|
-
|
|
82
|
+
o.writeHead(404).end();
|
|
76
83
|
}
|
|
77
84
|
});
|
|
78
|
-
return new Promise((
|
|
85
|
+
return new Promise((r) => s.listen(0, "127.0.0.1", () => r(s)));
|
|
79
86
|
}
|
|
80
|
-
async function
|
|
87
|
+
async function te(e, t) {
|
|
81
88
|
await e.send("Page.navigate", { url: t });
|
|
82
89
|
const { result: n, exceptionDetails: s } = await e.send(
|
|
83
90
|
"Runtime.evaluate",
|
|
@@ -96,25 +103,25 @@ async function ee(e, t) {
|
|
|
96
103
|
if (s) throw new Error(`Rendering failed: ${s.exception?.description ?? "unknown error"}`);
|
|
97
104
|
return n.value;
|
|
98
105
|
}
|
|
99
|
-
function
|
|
106
|
+
function ne(e) {
|
|
100
107
|
return async (t) => {
|
|
101
|
-
const n = await
|
|
102
|
-
let
|
|
108
|
+
const n = await ee(e, JSON.stringify({ spec: t.spec, state: t.state, messages: t.messages })), s = `http://127.0.0.1:${n.address().port}/`, r = await E(g(H(), "syno-pkg-land-ui-render-"));
|
|
109
|
+
let o;
|
|
103
110
|
try {
|
|
104
|
-
|
|
111
|
+
o = await Z(r), await M(t.out, { recursive: !0 });
|
|
105
112
|
const i = [];
|
|
106
113
|
for (const c of t.widths) {
|
|
107
|
-
await
|
|
108
|
-
const d = await
|
|
109
|
-
await D(
|
|
114
|
+
await o.send("Emulation.setDeviceMetricsOverride", { width: c, height: t.height, deviceScaleFactor: 1, mobile: !1 });
|
|
115
|
+
const d = await te(o, `${s}?width=${c}`), { data: l } = await o.send("Page.captureScreenshot", { format: "png" }), m = g(t.out, `${t.name}-${c}.png`);
|
|
116
|
+
await D(m, Buffer.from(l, "base64")), i.push({ width: c, screenshot: m, issues: d });
|
|
110
117
|
}
|
|
111
118
|
return i;
|
|
112
119
|
} finally {
|
|
113
|
-
await
|
|
120
|
+
await o?.close(), n.close(), await R(r, { recursive: !0, force: !0, maxRetries: 12, retryDelay: 250 });
|
|
114
121
|
}
|
|
115
122
|
};
|
|
116
123
|
}
|
|
117
|
-
const
|
|
124
|
+
const p = `Usage: syno-pkg-land-ui <command> [options]
|
|
118
125
|
|
|
119
126
|
Commands:
|
|
120
127
|
catalog [--json] List the JSON UI components
|
|
@@ -129,139 +136,141 @@ Commands:
|
|
|
129
136
|
--state <file.json> Host-provided state
|
|
130
137
|
--messages <file.json> Message catalog (enables i18n checks)
|
|
131
138
|
render <file> [options] Validate, screenshot and report layout overflow (needs Chrome, Node 22+)
|
|
132
|
-
--out <dir> Screenshot directory (default syno-ui-render)
|
|
139
|
+
--out <dir> Screenshot directory (default syno-pkg-land-ui-render)
|
|
133
140
|
--widths 390,640,960,1350 Viewport widths: phone, narrow window, DSM window, wide
|
|
134
141
|
--height <px> Viewport height (default 800)
|
|
135
142
|
--state, --messages As for validate; messages also back $computed t()
|
|
136
|
-
`,
|
|
137
|
-
function
|
|
143
|
+
`, se = /* @__PURE__ */ new Set(["actions", "functions", "state", "messages", "out", "widths", "height", "wide"]);
|
|
144
|
+
function re(e) {
|
|
138
145
|
const t = [], n = {};
|
|
139
146
|
for (let s = 0; s < e.length; s++) {
|
|
140
|
-
const
|
|
141
|
-
if (!
|
|
142
|
-
t.push(
|
|
147
|
+
const r = e[s];
|
|
148
|
+
if (!r.startsWith("--")) {
|
|
149
|
+
t.push(r);
|
|
143
150
|
continue;
|
|
144
151
|
}
|
|
145
|
-
const [
|
|
146
|
-
n[
|
|
152
|
+
const [o, i] = r.slice(2).split("=", 2);
|
|
153
|
+
n[o] = i ?? (se.has(o) && e[s + 1] !== void 0 ? e[++s] : !0);
|
|
147
154
|
}
|
|
148
155
|
return { positional: t, flags: n };
|
|
149
156
|
}
|
|
150
|
-
const
|
|
157
|
+
const y = (e) => typeof e == "string" ? e.split(",").map((t) => t.trim()).filter(Boolean) : void 0;
|
|
151
158
|
function oe(e) {
|
|
152
159
|
return ` ${e.severity} ${e.code} ${e.path || "/"}: ${e.message}${e.hint ? `
|
|
153
160
|
hint: ${e.hint}` : ""}
|
|
154
161
|
`;
|
|
155
162
|
}
|
|
156
|
-
class
|
|
163
|
+
class h extends Error {
|
|
157
164
|
}
|
|
158
165
|
async function C(e, t) {
|
|
159
166
|
try {
|
|
160
167
|
return await e.readFile(t);
|
|
161
168
|
} catch (n) {
|
|
162
|
-
throw new
|
|
169
|
+
throw new h(`Cannot read ${t}: ${n instanceof Error ? n.message : String(n)}`);
|
|
163
170
|
}
|
|
164
171
|
}
|
|
165
|
-
async function
|
|
172
|
+
async function $(e, t) {
|
|
166
173
|
const n = await C(e, t);
|
|
167
174
|
try {
|
|
168
175
|
return JSON.parse(n);
|
|
169
176
|
} catch (s) {
|
|
170
|
-
throw new
|
|
177
|
+
throw new h(`${t} is not valid JSON: ${s instanceof Error ? s.message : String(s)}`);
|
|
171
178
|
}
|
|
172
179
|
}
|
|
173
|
-
async function
|
|
180
|
+
async function k(e, t, n) {
|
|
174
181
|
const s = await C(e, t);
|
|
175
|
-
let
|
|
182
|
+
let r;
|
|
176
183
|
try {
|
|
177
|
-
|
|
178
|
-
} catch (
|
|
179
|
-
return { valid: !1, errors: [{ severity: "error", code: "invalid_json", path: "", message:
|
|
184
|
+
r = JSON.parse(s);
|
|
185
|
+
} catch (o) {
|
|
186
|
+
return { valid: !1, errors: [{ severity: "error", code: "invalid_json", path: "", message: o instanceof Error ? o.message : String(o), hint: "Return a single JSON object without comments or trailing commas." }], warnings: [] };
|
|
180
187
|
}
|
|
181
|
-
return G(
|
|
188
|
+
return G(r, n);
|
|
182
189
|
}
|
|
183
|
-
async function
|
|
190
|
+
async function x(e, t) {
|
|
184
191
|
return {
|
|
185
|
-
actions:
|
|
186
|
-
functions:
|
|
187
|
-
state: typeof t.state == "string" ? await
|
|
188
|
-
messages: typeof t.messages == "string" ? await
|
|
192
|
+
actions: y(t.actions),
|
|
193
|
+
functions: y(t.functions),
|
|
194
|
+
state: typeof t.state == "string" ? await $(e, t.state) : void 0,
|
|
195
|
+
messages: typeof t.messages == "string" ? await $(e, t.messages) : void 0
|
|
189
196
|
};
|
|
190
197
|
}
|
|
191
|
-
const
|
|
192
|
-
function
|
|
198
|
+
const J = (e, t) => e.errors.length > 0 || !!t.strict && e.warnings.length > 0;
|
|
199
|
+
function v(e) {
|
|
193
200
|
return e.errors.length || e.warnings.length ? `${e.file}: ${e.errors.length} error(s), ${e.warnings.length} warning(s)
|
|
194
201
|
${[...e.errors, ...e.warnings].map(oe).join("")}` : `${e.file}: OK
|
|
195
202
|
`;
|
|
196
203
|
}
|
|
197
|
-
async function
|
|
204
|
+
async function ie(e, { positional: t, flags: n }) {
|
|
198
205
|
if (!t.length)
|
|
199
|
-
return e.stderr(
|
|
200
|
-
const s = await
|
|
201
|
-
for (const
|
|
202
|
-
return e.stdout(n.json ? JSON.stringify(
|
|
203
|
-
` :
|
|
206
|
+
return e.stderr(p), 2;
|
|
207
|
+
const s = await x(e, n), r = [];
|
|
208
|
+
for (const o of t) r.push({ file: o, ...await k(e, o, s) });
|
|
209
|
+
return e.stdout(n.json ? JSON.stringify(r, null, 2) + `
|
|
210
|
+
` : r.map(v).join("")), r.some((o) => J(o, n)) ? 1 : 0;
|
|
204
211
|
}
|
|
205
|
-
const
|
|
206
|
-
async function
|
|
212
|
+
const ae = [390, 640, 960, 1350];
|
|
213
|
+
async function ce(e, { positional: [t], flags: n }) {
|
|
207
214
|
if (!t)
|
|
208
|
-
return e.stderr(
|
|
215
|
+
return e.stderr(p), 2;
|
|
209
216
|
if (!e.render)
|
|
210
217
|
return e.stderr(`render needs a local Chrome or Chromium (set CHROME to its path) and Node 22 or newer.
|
|
211
218
|
`), 2;
|
|
212
|
-
const s = await
|
|
213
|
-
if (
|
|
214
|
-
return e.stdout(n.json ? JSON.stringify({ file: t, validation:
|
|
215
|
-
` :
|
|
216
|
-
const
|
|
217
|
-
spec: await
|
|
219
|
+
const s = await x(e, n), r = { file: t, ...await k(e, t, s) };
|
|
220
|
+
if (J(r, n))
|
|
221
|
+
return e.stdout(n.json ? JSON.stringify({ file: t, validation: r, renders: [] }, null, 2) + `
|
|
222
|
+
` : v(r)), 1;
|
|
223
|
+
const o = await e.render({
|
|
224
|
+
spec: await $(e, t),
|
|
218
225
|
state: s.state,
|
|
219
226
|
messages: s.messages,
|
|
220
|
-
widths:
|
|
227
|
+
widths: y(n.widths)?.map(Number) ?? ae,
|
|
221
228
|
height: typeof n.height == "string" ? Number(n.height) : 800,
|
|
222
|
-
out: typeof n.out == "string" ? n.out : "syno-ui-render",
|
|
229
|
+
out: typeof n.out == "string" ? n.out : "syno-pkg-land-ui-render",
|
|
223
230
|
name: t.split(/[\\/]/).pop().replace(/\.json$/i, "")
|
|
224
231
|
}).catch((i) => {
|
|
225
|
-
throw new
|
|
232
|
+
throw new h(`render failed: ${i instanceof Error ? i.message : String(i)}`);
|
|
226
233
|
});
|
|
227
|
-
if (n.json) e.stdout(JSON.stringify({ file: t, validation:
|
|
234
|
+
if (n.json) e.stdout(JSON.stringify({ file: t, validation: r, renders: o }, null, 2) + `
|
|
228
235
|
`);
|
|
229
236
|
else {
|
|
230
|
-
e.stdout(
|
|
231
|
-
for (const { width: i, screenshot: c, issues: d } of
|
|
237
|
+
e.stdout(r.warnings.length ? v(r) : "");
|
|
238
|
+
for (const { width: i, screenshot: c, issues: d } of o)
|
|
232
239
|
e.stdout(`${t} @${i}px: ${d.length ? `${d.length} layout issue(s)` : "OK"} ${c}
|
|
233
240
|
` + d.map((l) => ` ${l.kind} ${l.key ?? "(outside the spec)"}: ${l.detail}
|
|
234
241
|
`).join(""));
|
|
235
242
|
}
|
|
236
|
-
return
|
|
243
|
+
return o.some((i) => i.issues.length) ? 1 : 0;
|
|
237
244
|
}
|
|
238
|
-
async function
|
|
245
|
+
async function de(e, t) {
|
|
239
246
|
try {
|
|
240
|
-
return await
|
|
247
|
+
return await le(re(e), t);
|
|
241
248
|
} catch (n) {
|
|
242
|
-
if (!(n instanceof
|
|
249
|
+
if (!(n instanceof h)) throw n;
|
|
243
250
|
return t.stderr(`${n.message}
|
|
244
251
|
`), 2;
|
|
245
252
|
}
|
|
246
253
|
}
|
|
247
|
-
async function
|
|
248
|
-
|
|
254
|
+
async function le(e, t) {
|
|
255
|
+
if (e.flags.help === !0)
|
|
256
|
+
return t.stdout(p), 0;
|
|
257
|
+
const [n, ...s] = e.positional, r = e.flags.json === !0;
|
|
249
258
|
switch (n) {
|
|
250
259
|
case "catalog": {
|
|
251
|
-
const
|
|
252
|
-
return t.stdout(
|
|
253
|
-
` :
|
|
260
|
+
const o = B();
|
|
261
|
+
return t.stdout(r ? JSON.stringify({ components: o }, null, 2) + `
|
|
262
|
+
` : o.map((i) => `${i.name}${i.required.length ? ` (${i.required.join(", ")})` : ""}: ${i.description}
|
|
254
263
|
`).join("")), 0;
|
|
255
264
|
}
|
|
256
265
|
case "describe": {
|
|
257
|
-
const
|
|
266
|
+
const o = s[0] ?? "", i = _(o);
|
|
258
267
|
if (!i) {
|
|
259
|
-
const c = V(
|
|
260
|
-
return t.stderr(`Unknown component ${JSON.stringify(
|
|
268
|
+
const c = V(o);
|
|
269
|
+
return t.stderr(`Unknown component ${JSON.stringify(o)}.${c ? ` Did you mean "${c}"?` : ""} Run "syno-pkg-land-ui catalog".
|
|
261
270
|
`), 2;
|
|
262
271
|
}
|
|
263
|
-
return t.stdout(
|
|
264
|
-
` :
|
|
272
|
+
return t.stdout(r ? JSON.stringify(i, null, 2) + `
|
|
273
|
+
` : ue(i)), 0;
|
|
265
274
|
}
|
|
266
275
|
case "schema":
|
|
267
276
|
return t.stdout(JSON.stringify(W(), null, 2) + `
|
|
@@ -269,14 +278,14 @@ async function de(e, t) {
|
|
|
269
278
|
case "prompt":
|
|
270
279
|
return t.stdout(T()), 0;
|
|
271
280
|
case "validate":
|
|
272
|
-
return
|
|
281
|
+
return ie(t, { positional: s, flags: e.flags });
|
|
273
282
|
case "render":
|
|
274
|
-
return
|
|
283
|
+
return ce(t, { positional: s, flags: e.flags });
|
|
275
284
|
default:
|
|
276
|
-
return t.stderr(
|
|
285
|
+
return t.stderr(p), 2;
|
|
277
286
|
}
|
|
278
287
|
}
|
|
279
|
-
function
|
|
288
|
+
function ue(e) {
|
|
280
289
|
const t = Object.entries(e.props).map(([n, s]) => ` ${n}${s.required ? "" : "?"}: ${JSON.stringify(s.schema)}
|
|
281
290
|
`).join("");
|
|
282
291
|
return `${e.name}: ${e.description}
|
|
@@ -287,10 +296,10 @@ events: ${e.events.join(", ") || "(none)"}
|
|
|
287
296
|
example: ${JSON.stringify(e.example)}
|
|
288
297
|
`;
|
|
289
298
|
}
|
|
290
|
-
process.exitCode = await
|
|
299
|
+
process.exitCode = await de(process.argv.slice(2), {
|
|
291
300
|
stdout: (e) => process.stdout.write(e),
|
|
292
301
|
stderr: (e) => process.stderr.write(e),
|
|
293
|
-
readFile: (e) =>
|
|
302
|
+
readFile: (e) => S(e, "utf8"),
|
|
294
303
|
// The DevTools connection uses the WebSocket global of Node 22 and newer.
|
|
295
|
-
render: typeof WebSocket == "function" ?
|
|
304
|
+
render: typeof WebSocket == "function" ? ne(import.meta.url) : void 0
|
|
296
305
|
});
|
package/dist/index.js
CHANGED
|
@@ -2,7 +2,7 @@ import * as _l from "vue";
|
|
|
2
2
|
import { inject as et, computed as h, defineComponent as E, openBlock as f, createElementBlock as _, normalizeStyle as $e, unref as l, createElementVNode as K, normalizeClass as le, createBlock as q, createCommentVNode as N, renderSlot as k, useAttrs as Kr, provide as Qe, watch as ve, watchEffect as lt, onBeforeUpdate as Ju, onBeforeUnmount as Ge, mergeProps as ee, shallowRef as ar, shallowReadonly as Zt, toValue as Xe, getCurrentScope as wi, onScopeDispose as vn, customRef as Qu, effectScope as Ci, getCurrentInstance as gt, isRef as zt, reactive as ct, toRefs as Fe, ref as T, nextTick as Ae, onMounted as Te, Fragment as fe, toHandlerKey as ed, camelize as ki, onUpdated as Si, triggerRef as td, toRef as ad, onUnmounted as pt, h as wt, Comment as rd, cloneVNode as od, withCtx as x, createVNode as O, withKeys as je, withDirectives as xt, vShow as ca, withModifiers as Se, Teleport as Wr, normalizeProps as Ee, guardReactiveProps as De, markRaw as nd, renderList as ke, watchSyncEffect as ld, withMemo as mn, watchPostEffect as $i, mergeDefaults as qi, resolveDynamicComponent as Ke, toHandlers as Pi, createTextVNode as ye, toDisplayString as Y, toRaw as id, useId as Ct, useTemplateRef as Ue, vModelText as Ai, resolveComponent as hn, vModelSelect as _o, useSlots as ea, createSlots as sd, shallowReactive as ud } from "vue";
|
|
3
3
|
import { Minus as zo, ChevronDown as ft, Plus as No, Check as Lt, X as St, ChevronRight as dt, CalendarDays as dd, ChevronLeft as yn, CircleAlert as gn, TriangleAlert as bn, CircleCheck as Ei, Info as Hr, Ellipsis as xl, ChevronsLeft as cd, ChevronsRight as fd, RefreshCw as Er, Filter as pd, Search as vd, Trash2 as md, ChevronUp as Ti, GripVertical as wl, FolderOpen as Di, Folder as hd, File as yd, UploadCloud as gd, FileText as bd, Scissors as _d, Copy as xd, Pencil as wd, CircleHelp as Cd, Lightbulb as kd, ChevronsUpDown as Sd, Package as $d, ExternalLink as qd, Menu as Pd, Download as Ad, ArrowUpRight as Ed } from "@lucide/vue";
|
|
4
4
|
import { DateFormatter as Ft, createCalendar as Td, toCalendar as Cl, CalendarDateTime as Bi, CalendarDate as Oi, getLocalTimeZone as _n, ZonedDateTime as Dd, getDayOfWeek as xn, startOfMonth as Bd, endOfMonth as kl, today as Od, isEqualMonth as Sl, isSameMonth as Ii, isSameDay as Pa, isEqualDay as Ua, isToday as Id, parseDate as Rd } from "@internationalized/date";
|
|
5
|
-
const Ri = /* @__PURE__ */ Symbol("syno-ui:locale");
|
|
5
|
+
const Ri = /* @__PURE__ */ Symbol("syno-pkg-land-ui:locale");
|
|
6
6
|
function rr(e) {
|
|
7
7
|
const a = et(Ri, null);
|
|
8
8
|
return h(() => e() ?? a?.value ?? "en");
|
|
@@ -1313,7 +1313,7 @@ const Ld = ["type", "disabled", "data-disabled"], nt = /* @__PURE__ */ E({
|
|
|
1313
1313
|
k(r.$slots, "default")
|
|
1314
1314
|
], 10, zd));
|
|
1315
1315
|
}
|
|
1316
|
-
}), Mi = /* @__PURE__ */ Symbol("syno-ui:form"), Cn = /* @__PURE__ */ Symbol("syno-ui:form-field");
|
|
1316
|
+
}), Mi = /* @__PURE__ */ Symbol("syno-pkg-land-ui:form"), Cn = /* @__PURE__ */ Symbol("syno-pkg-land-ui:form-field");
|
|
1317
1317
|
function Nd() {
|
|
1318
1318
|
return et(Mi, null);
|
|
1319
1319
|
}
|
|
@@ -20644,7 +20644,7 @@ const m0 = ["disabled", "readonly", "placeholder", "onKeydown"], h0 = ["disabled
|
|
|
20644
20644
|
], 8, T0)) : N("", !0)
|
|
20645
20645
|
], 16));
|
|
20646
20646
|
}
|
|
20647
|
-
}), ku = /* @__PURE__ */ Symbol("syno-ui-toast-controller");
|
|
20647
|
+
}), ku = /* @__PURE__ */ Symbol("syno-pkg-land-ui-toast-controller");
|
|
20648
20648
|
function _A() {
|
|
20649
20649
|
const e = et(ku);
|
|
20650
20650
|
if (!e)
|
|
@@ -25859,7 +25859,7 @@ const rS = { class: "mb-3 flex flex-wrap items-start justify-between gap-3" }, o
|
|
|
25859
25859
|
])
|
|
25860
25860
|
], 40, kS));
|
|
25861
25861
|
}
|
|
25862
|
-
}), Iu = /* @__PURE__ */ Symbol("syno-ui-notification-controller");
|
|
25862
|
+
}), Iu = /* @__PURE__ */ Symbol("syno-pkg-land-ui-notification-controller");
|
|
25863
25863
|
function OS() {
|
|
25864
25864
|
const e = et(Iu);
|
|
25865
25865
|
if (!e)
|
|
@@ -27157,7 +27157,7 @@ const b$ = ["aria-rowcount", "aria-colcount"], _$ = { role: "row" }, x$ = ["aria
|
|
|
27157
27157
|
_: 1
|
|
27158
27158
|
}, 8, ["open", "title", "description", "width"]));
|
|
27159
27159
|
}
|
|
27160
|
-
}), Ru = /* @__PURE__ */ Symbol("syno-ui-message-box");
|
|
27160
|
+
}), Ru = /* @__PURE__ */ Symbol("syno-pkg-land-ui-message-box");
|
|
27161
27161
|
function H$(e = (a, t) => wn("en", a, t)) {
|
|
27162
27162
|
const a = T([]), t = /* @__PURE__ */ new Map();
|
|
27163
27163
|
let r = 1;
|
|
@@ -27244,7 +27244,7 @@ const EE = /* @__PURE__ */ E({
|
|
|
27244
27244
|
}, null, 8, ["kind", "title", "message", "phrase", "progress", "options", "onSettle"]))), 128))
|
|
27245
27245
|
], 64));
|
|
27246
27246
|
}
|
|
27247
|
-
}), Mu = /* @__PURE__ */ Symbol("syno-ui-wizard");
|
|
27247
|
+
}), Mu = /* @__PURE__ */ Symbol("syno-pkg-land-ui-wizard");
|
|
27248
27248
|
function G$() {
|
|
27249
27249
|
return et(Mu, null);
|
|
27250
27250
|
}
|
|
@@ -28216,7 +28216,7 @@ const Y$ = ["aria-label"], X$ = {
|
|
|
28216
28216
|
])) : N("", !0)
|
|
28217
28217
|
], 64));
|
|
28218
28218
|
}
|
|
28219
|
-
}), Vu = /* @__PURE__ */ Symbol("syno-ui:config-manager"), cl = /* @__PURE__ */ Symbol("syno-ui:config-provider");
|
|
28219
|
+
}), Vu = /* @__PURE__ */ Symbol("syno-pkg-land-ui:config-manager"), cl = /* @__PURE__ */ Symbol("syno-pkg-land-ui:config-provider");
|
|
28220
28220
|
function Da(e) {
|
|
28221
28221
|
if (typeof e != "object" || e === null || Array.isArray(e)) return !1;
|
|
28222
28222
|
const a = Object.getPrototypeOf(e);
|
|
@@ -28947,7 +28947,7 @@ const ZE = /* @__PURE__ */ E({
|
|
|
28947
28947
|
ve(
|
|
28948
28948
|
() => a.alignItem,
|
|
28949
28949
|
(r) => {
|
|
28950
|
-
r && console.warn("[syno-ui] Space: `alignItem` is deprecated, use `alignItems` instead.");
|
|
28950
|
+
r && console.warn("[syno-pkg-land-ui] Space: `alignItem` is deprecated, use `alignItems` instead.");
|
|
28951
28951
|
},
|
|
28952
28952
|
{ immediate: !0 }
|
|
28953
28953
|
);
|
package/dist/json/catalog.d.ts
CHANGED
|
@@ -905,6 +905,6 @@ export declare const synoJsonCatalog: import('@json-render/core').Catalog<{
|
|
|
905
905
|
}>;
|
|
906
906
|
export declare const synoJsonAiRules: string[];
|
|
907
907
|
/** The self-check loop an AI follows after generating a spec. */
|
|
908
|
-
export declare const synoJsonAiWorkflow = "## Self-check workflow\n\n1. List components with `npx syno-ui catalog`; read props with `npx syno-ui describe <Component>`.\n2. Write the spec as JSON: {\"root\", \"elements\", \"state\"}. Seed every state path you bind or read.\n3. Run `npx syno-ui validate ui.json --json` (add --actions, --functions, --state, --messages for host-provided names).\n Fix every error at its JSON Pointer `path` using its `hint`, then validate again until it passes.\n4. Run `npx syno-ui render ui.json --out shots` to screenshot phone, DSM window and wide widths and to\n report layout overflow; fix reported elements and repeat.\n5. Hand over the spec only when validate and render both exit 0.";
|
|
908
|
+
export declare const synoJsonAiWorkflow = "## Self-check workflow\n\nInstall `@synopackageland/ui` first. Without a local install, use\n`npx -y -p @synopackageland/ui syno-pkg-land-ui <command>` (pin the package version for reproducibility).\n\n1. List components with `npx --no syno-pkg-land-ui catalog`; read props with `npx --no syno-pkg-land-ui describe <Component>`.\n2. Write the spec as JSON: {\"root\", \"elements\", \"state\"}. Seed every state path you bind or read.\n3. Run `npx --no syno-pkg-land-ui validate ui.json --json` (add --actions, --functions, --state, --messages for host-provided names).\n Fix every error at its JSON Pointer `path` using its `hint`, then validate again until it passes.\n4. Run `npx --no syno-pkg-land-ui render ui.json --out shots` to screenshot phone, DSM window and wide widths and to\n report layout overflow; fix reported elements and repeat.\n5. Hand over the spec only when validate and render both exit 0.";
|
|
909
909
|
/** The complete AI system prompt: catalog, rules and the self-check workflow. */
|
|
910
910
|
export declare function synoJsonAiPrompt(): string;
|
package/dist/json-ai-prompt.md
CHANGED
|
@@ -175,10 +175,13 @@ RULES:
|
|
|
175
175
|
|
|
176
176
|
## Self-check workflow
|
|
177
177
|
|
|
178
|
-
|
|
178
|
+
Install `@synopackageland/ui` first. Without a local install, use
|
|
179
|
+
`npx -y -p @synopackageland/ui syno-pkg-land-ui <command>` (pin the package version for reproducibility).
|
|
180
|
+
|
|
181
|
+
1. List components with `npx --no syno-pkg-land-ui catalog`; read props with `npx --no syno-pkg-land-ui describe <Component>`.
|
|
179
182
|
2. Write the spec as JSON: {"root", "elements", "state"}. Seed every state path you bind or read.
|
|
180
|
-
3. Run `npx syno-ui validate ui.json --json` (add --actions, --functions, --state, --messages for host-provided names).
|
|
183
|
+
3. Run `npx --no syno-pkg-land-ui validate ui.json --json` (add --actions, --functions, --state, --messages for host-provided names).
|
|
181
184
|
Fix every error at its JSON Pointer `path` using its `hint`, then validate again until it passes.
|
|
182
|
-
4. Run `npx syno-ui render ui.json --out shots` to screenshot phone, DSM window and wide widths and to
|
|
185
|
+
4. Run `npx --no syno-pkg-land-ui render ui.json --out shots` to screenshot phone, DSM window and wide widths and to
|
|
183
186
|
report layout overflow; fix reported elements and repeat.
|
|
184
187
|
5. Hand over the spec only when validate and render both exit 0.
|
|
@@ -11364,7 +11364,7 @@ function jS(e, t) {
|
|
|
11364
11364
|
f ? await f[1](l, u, c) : console.warn(`Unknown action: ${a}`);
|
|
11365
11365
|
} };
|
|
11366
11366
|
}
|
|
11367
|
-
const LS = /* @__PURE__ */ Symbol("syno-ui:locale");
|
|
11367
|
+
const LS = /* @__PURE__ */ Symbol("syno-pkg-land-ui:locale");
|
|
11368
11368
|
function qS(e) {
|
|
11369
11369
|
const t = Le(LS, null);
|
|
11370
11370
|
return $(() => e() ?? t?.value ?? "en");
|
|
@@ -12644,7 +12644,7 @@ const KS = ["type", "disabled", "data-disabled"], HS = /* @__PURE__ */ V({
|
|
|
12644
12644
|
B(r.$slots, "default")
|
|
12645
12645
|
], 10, KS));
|
|
12646
12646
|
}
|
|
12647
|
-
}), Cp = /* @__PURE__ */ Symbol("syno-ui:form"), vl = /* @__PURE__ */ Symbol("syno-ui:form-field");
|
|
12647
|
+
}), Cp = /* @__PURE__ */ Symbol("syno-pkg-land-ui:form"), vl = /* @__PURE__ */ Symbol("syno-pkg-land-ui:form-field");
|
|
12648
12648
|
function JS() {
|
|
12649
12649
|
return Le(Cp, null);
|
|
12650
12650
|
}
|
|
@@ -20522,7 +20522,7 @@ const ys = /* @__PURE__ */ Symbol("syno-app-presentation"), X$ = ["data-ui-data-
|
|
|
20522
20522
|
])) : Q("", !0)
|
|
20523
20523
|
], 64));
|
|
20524
20524
|
}
|
|
20525
|
-
}), QE = /* @__PURE__ */ Symbol("syno-ui:config-manager"), eP = /* @__PURE__ */ Symbol("syno-ui:config-provider");
|
|
20525
|
+
}), QE = /* @__PURE__ */ Symbol("syno-pkg-land-ui:config-manager"), eP = /* @__PURE__ */ Symbol("syno-pkg-land-ui:config-provider");
|
|
20526
20526
|
function Pi(e) {
|
|
20527
20527
|
if (typeof e != "object" || e === null || Array.isArray(e)) return !1;
|
|
20528
20528
|
const t = Object.getPrototypeOf(e);
|
package/dist/json.js
CHANGED
|
@@ -3,7 +3,7 @@ import { z as gt } from "zod";
|
|
|
3
3
|
import { defineCatalog as z } from "@json-render/core";
|
|
4
4
|
import { createStateStore as yt, defineCatalog as wt } from "@json-render/core";
|
|
5
5
|
import { defineRegistry as B, useBoundProp as b, JSONUIProvider as M, Renderer as W } from "@json-render/vue";
|
|
6
|
-
import { ActionProvider as $t, JSONUIProvider as St, Renderer as jt, StateProvider as Ot, ValidationProvider as xt, VisibilityProvider as At, defineRegistry as Pt, useActions as
|
|
6
|
+
import { ActionProvider as $t, JSONUIProvider as St, Renderer as jt, StateProvider as Ot, ValidationProvider as xt, VisibilityProvider as At, defineRegistry as Pt, useActions as kt, useBoundProp as Ct, useStateStore as Rt } from "@json-render/vue";
|
|
7
7
|
import { schema as H } from "@json-render/vue/schema";
|
|
8
8
|
import { schema as It } from "@json-render/vue/schema";
|
|
9
9
|
import { h as d, defineComponent as G, openBlock as X, createBlock as Y, unref as j, withCtx as Q, createVNode as Z } from "vue";
|
|
@@ -16,11 +16,11 @@ const V = o.lazy(() => o.object({
|
|
|
16
16
|
disabled: o.boolean().optional(),
|
|
17
17
|
selectable: o.boolean().optional(),
|
|
18
18
|
children: o.array(V).optional()
|
|
19
|
-
})),
|
|
19
|
+
})), k = o.object({
|
|
20
20
|
label: o.string(),
|
|
21
21
|
value: o.string(),
|
|
22
22
|
disabled: o.boolean().optional()
|
|
23
|
-
}), Pe =
|
|
23
|
+
}), Pe = k.extend({
|
|
24
24
|
description: o.string().optional()
|
|
25
25
|
}), U = o.object({
|
|
26
26
|
key: o.string(),
|
|
@@ -88,7 +88,7 @@ const V = o.lazy(() => o.object({
|
|
|
88
88
|
Tabs: {
|
|
89
89
|
props: o.object({
|
|
90
90
|
value: o.string(),
|
|
91
|
-
items: o.array(
|
|
91
|
+
items: o.array(k),
|
|
92
92
|
ariaLabel: o.string().optional()
|
|
93
93
|
}),
|
|
94
94
|
events: ["change"],
|
|
@@ -141,7 +141,7 @@ const V = o.lazy(() => o.object({
|
|
|
141
141
|
Select: {
|
|
142
142
|
props: o.object({
|
|
143
143
|
value: o.string().optional(),
|
|
144
|
-
options: o.array(
|
|
144
|
+
options: o.array(k),
|
|
145
145
|
placeholder: o.string().optional(),
|
|
146
146
|
disabled: o.boolean().optional(),
|
|
147
147
|
search: o.boolean().optional()
|
|
@@ -318,7 +318,7 @@ const V = o.lazy(() => o.object({
|
|
|
318
318
|
}, A = z(H, {
|
|
319
319
|
components: _,
|
|
320
320
|
actions: {}
|
|
321
|
-
}),
|
|
321
|
+
}), ke = [
|
|
322
322
|
"Prefer AppRoot > AppShell > Page as the normal DSM application hierarchy.",
|
|
323
323
|
"Prefer SettingsSection and SettingsField for settings; prefer ResourceList/DataTable for ordinary scalar resource collections.",
|
|
324
324
|
"Keep state in the spec and use $bindState/$bindItem for editable controls; do not invent JavaScript in props.",
|
|
@@ -327,11 +327,11 @@ const V = o.lazy(() => o.object({
|
|
|
327
327
|
"AppShell adapts to its actual DSM window width: phone (<=600px), desktop window (601–1199px), and wide web/Portal (>=1200px). Never assume browser viewport width.",
|
|
328
328
|
"For a phone-unfriendly custom view, use ResponsiveView slots: mobile alternative and default full view. Keep essential actions accessible on mobile.",
|
|
329
329
|
"Use low-level Stack/Text only when a semantic component does not already express the layout."
|
|
330
|
-
],
|
|
330
|
+
], Ce = '## Self-check workflow\n\nInstall `@synopackageland/ui` first. Without a local install, use\n`npx -y -p @synopackageland/ui syno-pkg-land-ui <command>` (pin the package version for reproducibility).\n\n1. List components with `npx --no syno-pkg-land-ui catalog`; read props with `npx --no syno-pkg-land-ui describe <Component>`.\n2. Write the spec as JSON: {"root", "elements", "state"}. Seed every state path you bind or read.\n3. Run `npx --no syno-pkg-land-ui validate ui.json --json` (add --actions, --functions, --state, --messages for host-provided names).\n Fix every error at its JSON Pointer `path` using its `hint`, then validate again until it passes.\n4. Run `npx --no syno-pkg-land-ui render ui.json --out shots` to screenshot phone, DSM window and wide widths and to\n report layout overflow; fix reported elements and repeat.\n5. Hand over the spec only when validate and render both exit 0.';
|
|
331
331
|
function rt() {
|
|
332
|
-
return `${A.prompt({ customRules:
|
|
332
|
+
return `${A.prompt({ customRules: ke })}
|
|
333
333
|
|
|
334
|
-
${
|
|
334
|
+
${Ce}
|
|
335
335
|
`;
|
|
336
336
|
}
|
|
337
337
|
const Re = {
|
|
@@ -344,13 +344,13 @@ const Re = {
|
|
|
344
344
|
function Ue(e) {
|
|
345
345
|
return { default: () => e };
|
|
346
346
|
}
|
|
347
|
-
function
|
|
347
|
+
function C(e) {
|
|
348
348
|
return e ? Ae(e) : void 0;
|
|
349
349
|
}
|
|
350
350
|
function T(e) {
|
|
351
351
|
return {
|
|
352
352
|
...e,
|
|
353
|
-
icon:
|
|
353
|
+
icon: C(e.icon),
|
|
354
354
|
children: e.children?.map(T)
|
|
355
355
|
};
|
|
356
356
|
}
|
|
@@ -409,7 +409,7 @@ const Le = {
|
|
|
409
409
|
return d(t === "heading" ? "h2" : t === "mono" ? "code" : "span", { class: t === "muted" ? "text-[13px] text-[var(--ui-text-muted)]" : t === "caption" ? "text-[12px] text-[var(--ui-text-muted)]" : t === "heading" ? "text-[16px] font-semibold text-[var(--ui-text)]" : t === "mono" ? "font-mono text-[12px] text-[var(--ui-text)]" : "text-[13px] text-[var(--ui-text)]", "data-syno-ui": "" }, e.text);
|
|
410
410
|
},
|
|
411
411
|
Button: ({ props: e, emit: t }) => {
|
|
412
|
-
const n =
|
|
412
|
+
const n = C(e.icon);
|
|
413
413
|
return d(be, {
|
|
414
414
|
variant: e.variant,
|
|
415
415
|
size: e.size,
|
|
@@ -538,7 +538,7 @@ const Le = {
|
|
|
538
538
|
EmptyState: ({ props: e, slots: t }) => d(ie, {
|
|
539
539
|
title: e.title,
|
|
540
540
|
description: e.description,
|
|
541
|
-
icon:
|
|
541
|
+
icon: C(e.icon)
|
|
542
542
|
}, t),
|
|
543
543
|
Progress: ({ props: e }) => d(ne, e),
|
|
544
544
|
Badge: ({ props: e }) => d(oe, { tone: e.tone }, Ue(e.text)),
|
|
@@ -669,7 +669,7 @@ function ct(e, t = {}) {
|
|
|
669
669
|
path: w("type"),
|
|
670
670
|
elementKey: p,
|
|
671
671
|
message: `Unknown component type ${JSON.stringify(h)}.`,
|
|
672
|
-
hint: g ? `Did you mean "${g}"? Run "syno-ui catalog" for every component.` : 'Run "syno-ui catalog" for every component, or register a host extension component.'
|
|
672
|
+
hint: g ? `Did you mean "${g}"? Run "syno-pkg-land-ui catalog" for every component.` : 'Run "syno-pkg-land-ui catalog" for every component, or register a host extension component.'
|
|
673
673
|
});
|
|
674
674
|
continue;
|
|
675
675
|
}
|
|
@@ -708,7 +708,7 @@ function qe(e, t, n, s, i) {
|
|
|
708
708
|
path: a(l),
|
|
709
709
|
elementKey: t,
|
|
710
710
|
message: `${n} has no prop "${l}".`,
|
|
711
|
-
hint: h ? `Did you mean "${h}"? Run "syno-ui describe ${n}".` : v(`${n} props`, c)
|
|
711
|
+
hint: h ? `Did you mean "${h}"? Run "syno-pkg-land-ui describe ${n}".` : v(`${n} props`, c)
|
|
712
712
|
});
|
|
713
713
|
continue;
|
|
714
714
|
}
|
|
@@ -725,7 +725,7 @@ function qe(e, t, n, s, i) {
|
|
|
725
725
|
});
|
|
726
726
|
}
|
|
727
727
|
for (const l of c)
|
|
728
|
-
!Object.hasOwn(i, l) && !K(r[l]) && e.error({ code: "missing_prop", path: a(l), elementKey: t, message: `${n} requires prop "${l}".`, hint: `Run "syno-ui describe ${n}" for its type.` });
|
|
728
|
+
!Object.hasOwn(i, l) && !K(r[l]) && e.error({ code: "missing_prop", path: a(l), elementKey: t, message: `${n} requires prop "${l}".`, hint: `Run "syno-pkg-land-ui describe ${n}" for its type.` });
|
|
729
729
|
}
|
|
730
730
|
function F(e, t) {
|
|
731
731
|
const n = [];
|
|
@@ -1103,14 +1103,14 @@ export {
|
|
|
1103
1103
|
It as jsonRenderVueSchema,
|
|
1104
1104
|
dt as listSynoJsonComponents,
|
|
1105
1105
|
rt as synoJsonAiPrompt,
|
|
1106
|
-
|
|
1106
|
+
ke as synoJsonAiRules,
|
|
1107
1107
|
A as synoJsonCatalog,
|
|
1108
1108
|
_ as synoJsonComponentDefinitions,
|
|
1109
1109
|
D as synoJsonRegistry,
|
|
1110
1110
|
Le as synoJsonRenderers,
|
|
1111
1111
|
mt as synoJsonSchema,
|
|
1112
|
-
|
|
1113
|
-
|
|
1112
|
+
kt as useActions,
|
|
1113
|
+
Ct as useBoundProp,
|
|
1114
1114
|
Rt as useStateStore,
|
|
1115
1115
|
ct as validateSynoJsonSpec,
|
|
1116
1116
|
gt as z
|
package/dist/reka-runtime.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"version": "2.10.5",
|
|
4
4
|
"delivery": "bundled-patched-esm",
|
|
5
5
|
"patchManifestSha256": "14f10159b60d48ac7a0686f58faf7a30e99898dc267b3c032cf2bdd6052dc52b",
|
|
6
|
-
"bundleSha256": "
|
|
6
|
+
"bundleSha256": "f91918f6eb4061e040da4ccc839184535e347f7eee4472622fbb2fc0a37f6849",
|
|
7
7
|
"sourceHashes": {
|
|
8
8
|
"shared/useBodyScrollLock.js": "657592f283cb6fd25454abd284a0024af21936cb56e05b762ff0d22b6a979d32",
|
|
9
9
|
"DismissableLayer/DismissableLayer.js": "da05ca544d9822a8e2b71057e78c0e1ef59423aa3893534338fb58e1ecbd1a8d",
|
package/docs/json-ui.md
CHANGED
|
@@ -107,8 +107,11 @@ state machines stay application-owned extensions.
|
|
|
107
107
|
|
|
108
108
|
## AI tools
|
|
109
109
|
|
|
110
|
-
The package ships a `syno-ui` command
|
|
111
|
-
|
|
110
|
+
The package ships a `syno-pkg-land-ui` command and the same functions from the JSON
|
|
111
|
+
entry. After `npm install @synopackageland/ui`, run
|
|
112
|
+
`npx --no syno-pkg-land-ui <command>`. To run it without installing locally, use
|
|
113
|
+
`npx -y -p @synopackageland/ui syno-pkg-land-ui <command>`; pin the package version
|
|
114
|
+
for reproducible automation. Since 0.7.0 the old `syno-ui` bin is removed.
|
|
112
115
|
|
|
113
116
|
| Command | Purpose | Function |
|
|
114
117
|
| --- | --- | --- |
|
|
@@ -125,7 +128,7 @@ references and cycles, state pointers, `$item` outside `repeat`, actions,
|
|
|
125
128
|
`$computed` functions and i18n keys. Tell it what the host provides:
|
|
126
129
|
|
|
127
130
|
```bash
|
|
128
|
-
syno-ui validate ui.json --json --actions save,refresh --functions formatBytes \
|
|
131
|
+
syno-pkg-land-ui validate ui.json --json --actions save,refresh --functions formatBytes \
|
|
129
132
|
--state host-state.json --messages messages/en.json
|
|
130
133
|
```
|
|
131
134
|
|
|
@@ -138,12 +141,12 @@ key and warns about literal user-facing text.
|
|
|
138
141
|
|
|
139
142
|
### Workflow for an AI
|
|
140
143
|
|
|
141
|
-
1. Read `syno-ui prompt` once, then `syno-ui catalog` and `syno-ui describe` for
|
|
144
|
+
1. Read `syno-pkg-land-ui prompt` once, then `syno-pkg-land-ui catalog` and `syno-pkg-land-ui describe` for
|
|
142
145
|
the components you plan to use.
|
|
143
146
|
2. Write `{ "root", "elements", "state" }`, seeding every state path you bind.
|
|
144
|
-
3. Run `syno-ui validate ui.json --json` with the host's actions, functions,
|
|
147
|
+
3. Run `syno-pkg-land-ui validate ui.json --json` with the host's actions, functions,
|
|
145
148
|
state and messages. Fix each error at its `path` using its `hint`; repeat.
|
|
146
|
-
4. Run `syno-ui render ui.json --out shots`, look at the screenshots, and fix
|
|
149
|
+
4. Run `syno-pkg-land-ui render ui.json --out shots`, look at the screenshots, and fix
|
|
147
150
|
every element named in an `outside_viewport` or `clipped_content` issue.
|
|
148
151
|
5. Hand over the spec only when `validate` and `render` both exit 0.
|
|
149
152
|
|
package/package.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "0.
|
|
2
|
+
"version": "0.7.0",
|
|
3
3
|
"description": "Shared Vue 3 UI component library with a DSM 7 inspired application theme",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"type": "module",
|
|
@@ -16,6 +16,9 @@
|
|
|
16
16
|
"docs/component-defaults-0.5.7.md",
|
|
17
17
|
"docs/json-ui.md"
|
|
18
18
|
],
|
|
19
|
+
"bin": {
|
|
20
|
+
"syno-pkg-land-ui": "./dist/cli.js"
|
|
21
|
+
},
|
|
19
22
|
"main": "./dist/index.js",
|
|
20
23
|
"module": "./dist/index.js",
|
|
21
24
|
"types": "./dist/index.d.ts",
|