@synopackageland/ui 0.6.1 → 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 +57 -55
- 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 +2 -2
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,17 +1,17 @@
|
|
|
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 =
|
|
14
|
+
function Q(e = process.env, t = process.platform, n = f) {
|
|
15
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
17
|
function Y(e, t = process.env) {
|
|
@@ -42,28 +42,28 @@ async function Z(e) {
|
|
|
42
42
|
}), n.stderr.on("data", (a) => {
|
|
43
43
|
r = (r + a).slice(-4e3);
|
|
44
44
|
});
|
|
45
|
-
const o =
|
|
46
|
-
for (let a = 0; a < 100 && !
|
|
47
|
-
if (!
|
|
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
48
|
throw n.kill(), new Error(`Chrome failed to start: ${s?.message ?? (r || "no debugging port within 10 seconds")}`);
|
|
49
|
-
const [i] = (await
|
|
49
|
+
const [i] = (await S(o, "utf8")).split(`
|
|
50
50
|
`), c = await (await fetch(`http://127.0.0.1:${i}/json/new?about:blank`, { method: "PUT" })).json(), d = new WebSocket(c.webSocketDebuggerUrl);
|
|
51
|
-
await new Promise((a,
|
|
52
|
-
d.onopen = a, d.onerror =
|
|
51
|
+
await new Promise((a, u) => {
|
|
52
|
+
d.onopen = a, d.onerror = u;
|
|
53
53
|
});
|
|
54
54
|
let l = 1;
|
|
55
|
-
const
|
|
55
|
+
const m = /* @__PURE__ */ new Map();
|
|
56
56
|
d.onmessage = (a) => {
|
|
57
|
-
const
|
|
58
|
-
|
|
57
|
+
const u = JSON.parse(String(a.data));
|
|
58
|
+
m.get(u.id)?.(u), m.delete(u.id);
|
|
59
59
|
};
|
|
60
|
-
const b = (a,
|
|
60
|
+
const b = (a, u = {}) => new Promise((A, P) => {
|
|
61
61
|
const O = l++;
|
|
62
|
-
|
|
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 }));
|
|
63
63
|
});
|
|
64
64
|
await b("Emulation.setDeviceMetricsOverride", { width: 1100, height: 720, deviceScaleFactor: 1, mobile: !1 });
|
|
65
|
-
const
|
|
66
|
-
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) };
|
|
67
67
|
}
|
|
68
68
|
const q = `<!doctype html>
|
|
69
69
|
<html><head><meta charset="utf-8"><link rel="stylesheet" href="/theme.css">
|
|
@@ -76,7 +76,7 @@ function ee(e, t) {
|
|
|
76
76
|
}, s = F(async (r, o) => {
|
|
77
77
|
const i = new URL(r.url ?? "/", "http://localhost").pathname;
|
|
78
78
|
try {
|
|
79
|
-
const [c, d] = i === "/" ? [q, "text/html"] : i === "/config.json" ? [t, "application/json"] : [await
|
|
79
|
+
const [c, d] = i === "/" ? [q, "text/html"] : i === "/config.json" ? [t, "application/json"] : [await S(n[i][0]), n[i][1]];
|
|
80
80
|
o.writeHead(200, { "content-type": d }).end(c);
|
|
81
81
|
} catch {
|
|
82
82
|
o.writeHead(404).end();
|
|
@@ -105,15 +105,15 @@ async function te(e, t) {
|
|
|
105
105
|
}
|
|
106
106
|
function ne(e) {
|
|
107
107
|
return async (t) => {
|
|
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(
|
|
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
109
|
let o;
|
|
110
110
|
try {
|
|
111
111
|
o = await Z(r), await M(t.out, { recursive: !0 });
|
|
112
112
|
const i = [];
|
|
113
113
|
for (const c of t.widths) {
|
|
114
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" }),
|
|
116
|
-
await D(
|
|
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 });
|
|
117
117
|
}
|
|
118
118
|
return i;
|
|
119
119
|
} finally {
|
|
@@ -121,7 +121,7 @@ function ne(e) {
|
|
|
121
121
|
}
|
|
122
122
|
};
|
|
123
123
|
}
|
|
124
|
-
const
|
|
124
|
+
const p = `Usage: syno-pkg-land-ui <command> [options]
|
|
125
125
|
|
|
126
126
|
Commands:
|
|
127
127
|
catalog [--json] List the JSON UI components
|
|
@@ -136,7 +136,7 @@ Commands:
|
|
|
136
136
|
--state <file.json> Host-provided state
|
|
137
137
|
--messages <file.json> Message catalog (enables i18n checks)
|
|
138
138
|
render <file> [options] Validate, screenshot and report layout overflow (needs Chrome, Node 22+)
|
|
139
|
-
--out <dir> Screenshot directory (default syno-ui-render)
|
|
139
|
+
--out <dir> Screenshot directory (default syno-pkg-land-ui-render)
|
|
140
140
|
--widths 390,640,960,1350 Viewport widths: phone, narrow window, DSM window, wide
|
|
141
141
|
--height <px> Viewport height (default 800)
|
|
142
142
|
--state, --messages As for validate; messages also back $computed t()
|
|
@@ -154,30 +154,30 @@ function re(e) {
|
|
|
154
154
|
}
|
|
155
155
|
return { positional: t, flags: n };
|
|
156
156
|
}
|
|
157
|
-
const
|
|
157
|
+
const y = (e) => typeof e == "string" ? e.split(",").map((t) => t.trim()).filter(Boolean) : void 0;
|
|
158
158
|
function oe(e) {
|
|
159
159
|
return ` ${e.severity} ${e.code} ${e.path || "/"}: ${e.message}${e.hint ? `
|
|
160
160
|
hint: ${e.hint}` : ""}
|
|
161
161
|
`;
|
|
162
162
|
}
|
|
163
|
-
class
|
|
163
|
+
class h extends Error {
|
|
164
164
|
}
|
|
165
165
|
async function C(e, t) {
|
|
166
166
|
try {
|
|
167
167
|
return await e.readFile(t);
|
|
168
168
|
} catch (n) {
|
|
169
|
-
throw new
|
|
169
|
+
throw new h(`Cannot read ${t}: ${n instanceof Error ? n.message : String(n)}`);
|
|
170
170
|
}
|
|
171
171
|
}
|
|
172
|
-
async function
|
|
172
|
+
async function $(e, t) {
|
|
173
173
|
const n = await C(e, t);
|
|
174
174
|
try {
|
|
175
175
|
return JSON.parse(n);
|
|
176
176
|
} catch (s) {
|
|
177
|
-
throw new
|
|
177
|
+
throw new h(`${t} is not valid JSON: ${s instanceof Error ? s.message : String(s)}`);
|
|
178
178
|
}
|
|
179
179
|
}
|
|
180
|
-
async function
|
|
180
|
+
async function k(e, t, n) {
|
|
181
181
|
const s = await C(e, t);
|
|
182
182
|
let r;
|
|
183
183
|
try {
|
|
@@ -187,54 +187,54 @@ async function x(e, t, n) {
|
|
|
187
187
|
}
|
|
188
188
|
return G(r, n);
|
|
189
189
|
}
|
|
190
|
-
async function
|
|
190
|
+
async function x(e, t) {
|
|
191
191
|
return {
|
|
192
|
-
actions:
|
|
193
|
-
functions:
|
|
194
|
-
state: typeof t.state == "string" ? await
|
|
195
|
-
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
|
|
196
196
|
};
|
|
197
197
|
}
|
|
198
|
-
const
|
|
199
|
-
function
|
|
198
|
+
const J = (e, t) => e.errors.length > 0 || !!t.strict && e.warnings.length > 0;
|
|
199
|
+
function v(e) {
|
|
200
200
|
return e.errors.length || e.warnings.length ? `${e.file}: ${e.errors.length} error(s), ${e.warnings.length} warning(s)
|
|
201
201
|
${[...e.errors, ...e.warnings].map(oe).join("")}` : `${e.file}: OK
|
|
202
202
|
`;
|
|
203
203
|
}
|
|
204
204
|
async function ie(e, { positional: t, flags: n }) {
|
|
205
205
|
if (!t.length)
|
|
206
|
-
return e.stderr(
|
|
207
|
-
const s = await
|
|
208
|
-
for (const o of t) r.push({ file: o, ...await
|
|
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
209
|
return e.stdout(n.json ? JSON.stringify(r, null, 2) + `
|
|
210
|
-
` : r.map(
|
|
210
|
+
` : r.map(v).join("")), r.some((o) => J(o, n)) ? 1 : 0;
|
|
211
211
|
}
|
|
212
212
|
const ae = [390, 640, 960, 1350];
|
|
213
213
|
async function ce(e, { positional: [t], flags: n }) {
|
|
214
214
|
if (!t)
|
|
215
|
-
return e.stderr(
|
|
215
|
+
return e.stderr(p), 2;
|
|
216
216
|
if (!e.render)
|
|
217
217
|
return e.stderr(`render needs a local Chrome or Chromium (set CHROME to its path) and Node 22 or newer.
|
|
218
218
|
`), 2;
|
|
219
|
-
const s = await
|
|
220
|
-
if (
|
|
219
|
+
const s = await x(e, n), r = { file: t, ...await k(e, t, s) };
|
|
220
|
+
if (J(r, n))
|
|
221
221
|
return e.stdout(n.json ? JSON.stringify({ file: t, validation: r, renders: [] }, null, 2) + `
|
|
222
|
-
` :
|
|
222
|
+
` : v(r)), 1;
|
|
223
223
|
const o = await e.render({
|
|
224
|
-
spec: await
|
|
224
|
+
spec: await $(e, t),
|
|
225
225
|
state: s.state,
|
|
226
226
|
messages: s.messages,
|
|
227
|
-
widths:
|
|
227
|
+
widths: y(n.widths)?.map(Number) ?? ae,
|
|
228
228
|
height: typeof n.height == "string" ? Number(n.height) : 800,
|
|
229
|
-
out: typeof n.out == "string" ? n.out : "syno-ui-render",
|
|
229
|
+
out: typeof n.out == "string" ? n.out : "syno-pkg-land-ui-render",
|
|
230
230
|
name: t.split(/[\\/]/).pop().replace(/\.json$/i, "")
|
|
231
231
|
}).catch((i) => {
|
|
232
|
-
throw new
|
|
232
|
+
throw new h(`render failed: ${i instanceof Error ? i.message : String(i)}`);
|
|
233
233
|
});
|
|
234
234
|
if (n.json) e.stdout(JSON.stringify({ file: t, validation: r, renders: o }, null, 2) + `
|
|
235
235
|
`);
|
|
236
236
|
else {
|
|
237
|
-
e.stdout(r.warnings.length ?
|
|
237
|
+
e.stdout(r.warnings.length ? v(r) : "");
|
|
238
238
|
for (const { width: i, screenshot: c, issues: d } of o)
|
|
239
239
|
e.stdout(`${t} @${i}px: ${d.length ? `${d.length} layout issue(s)` : "OK"} ${c}
|
|
240
240
|
` + d.map((l) => ` ${l.kind} ${l.key ?? "(outside the spec)"}: ${l.detail}
|
|
@@ -246,12 +246,14 @@ async function de(e, t) {
|
|
|
246
246
|
try {
|
|
247
247
|
return await le(re(e), t);
|
|
248
248
|
} catch (n) {
|
|
249
|
-
if (!(n instanceof
|
|
249
|
+
if (!(n instanceof h)) throw n;
|
|
250
250
|
return t.stderr(`${n.message}
|
|
251
251
|
`), 2;
|
|
252
252
|
}
|
|
253
253
|
}
|
|
254
254
|
async function le(e, t) {
|
|
255
|
+
if (e.flags.help === !0)
|
|
256
|
+
return t.stdout(p), 0;
|
|
255
257
|
const [n, ...s] = e.positional, r = e.flags.json === !0;
|
|
256
258
|
switch (n) {
|
|
257
259
|
case "catalog": {
|
|
@@ -264,11 +266,11 @@ async function le(e, t) {
|
|
|
264
266
|
const o = s[0] ?? "", i = _(o);
|
|
265
267
|
if (!i) {
|
|
266
268
|
const c = V(o);
|
|
267
|
-
return t.stderr(`Unknown component ${JSON.stringify(o)}.${c ? ` Did you mean "${c}"?` : ""} Run "syno-ui catalog".
|
|
269
|
+
return t.stderr(`Unknown component ${JSON.stringify(o)}.${c ? ` Did you mean "${c}"?` : ""} Run "syno-pkg-land-ui catalog".
|
|
268
270
|
`), 2;
|
|
269
271
|
}
|
|
270
272
|
return t.stdout(r ? JSON.stringify(i, null, 2) + `
|
|
271
|
-
` :
|
|
273
|
+
` : ue(i)), 0;
|
|
272
274
|
}
|
|
273
275
|
case "schema":
|
|
274
276
|
return t.stdout(JSON.stringify(W(), null, 2) + `
|
|
@@ -280,10 +282,10 @@ async function le(e, t) {
|
|
|
280
282
|
case "render":
|
|
281
283
|
return ce(t, { positional: s, flags: e.flags });
|
|
282
284
|
default:
|
|
283
|
-
return t.stderr(
|
|
285
|
+
return t.stderr(p), 2;
|
|
284
286
|
}
|
|
285
287
|
}
|
|
286
|
-
function
|
|
288
|
+
function ue(e) {
|
|
287
289
|
const t = Object.entries(e.props).map(([n, s]) => ` ${n}${s.required ? "" : "?"}: ${JSON.stringify(s.schema)}
|
|
288
290
|
`).join("");
|
|
289
291
|
return `${e.name}: ${e.description}
|
|
@@ -297,7 +299,7 @@ example: ${JSON.stringify(e.example)}
|
|
|
297
299
|
process.exitCode = await de(process.argv.slice(2), {
|
|
298
300
|
stdout: (e) => process.stdout.write(e),
|
|
299
301
|
stderr: (e) => process.stderr.write(e),
|
|
300
|
-
readFile: (e) =>
|
|
302
|
+
readFile: (e) => S(e, "utf8"),
|
|
301
303
|
// The DevTools connection uses the WebSocket global of Node 22 and newer.
|
|
302
304
|
render: typeof WebSocket == "function" ? ne(import.meta.url) : void 0
|
|
303
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",
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
"docs/json-ui.md"
|
|
18
18
|
],
|
|
19
19
|
"bin": {
|
|
20
|
-
"syno-ui": "./dist/cli.js"
|
|
20
|
+
"syno-pkg-land-ui": "./dist/cli.js"
|
|
21
21
|
},
|
|
22
22
|
"main": "./dist/index.js",
|
|
23
23
|
"module": "./dist/index.js",
|