@webx-ui/schema 0.8.1 → 0.9.1

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/dist/index.js CHANGED
@@ -1,46 +1,46 @@
1
- import { WxFormItem as ne, WxRepeater as te, WxTabs as oe, WxAlert as ie, WxText as re, WxHeading as se, WxCodeEditor as ae, WxTransfer as le, WxTreeSelect as de, WxCascader as ce, WxIconPicker as fe, WxAutocomplete as ue, WxTagsInput as pe, WxDateRangePicker as me, WxDateTimePicker as ye, WxTimePicker as be, WxRate as he, WxSlider as xe, WxSegmented as ge, WxCheckboxGroup as ke, WxColorPicker as we, WxDatePicker as ve, WxRadioGroup as We, WxCheckbox as $e, WxSwitch as Se, WxSelect as je, WxInputNumber as Ae, WxTextarea as Pe, WxInput as Oe, WxDivider as Te, WxCol as Ee, WxRow as Re, WxCard as Ne, WxTab as Ve, WxForm as Ce } from "@webx-ui/core";
2
- import { defineComponent as $, h as x, useModel as q, computed as y, useAttrs as Me, inject as U, openBlock as R, createBlock as N, unref as g, mergeProps as B, withCtx as V, createVNode as K, mergeModels as P, ref as ze, watch as H, renderSlot as Ie, provide as De, markRaw as _e, toRaw as Fe } from "vue";
1
+ import { WxFormItem as te, WxRepeater as oe, WxTabs as re, WxAlert as ie, WxText as se, WxHeading as ae, WxCodeEditor as le, WxTransfer as ce, WxTreeSelect as de, WxCascader as fe, WxIconPicker as ue, WxAutocomplete as pe, WxTagsInput as me, WxDateRangePicker as ye, WxDateTimePicker as be, WxTimePicker as xe, WxRate as he, WxSlider as ge, WxSegmented as we, WxCheckboxGroup as ke, WxColorPicker as ve, WxDatePicker as We, WxRadioGroup as $e, WxCheckbox as Se, WxSwitch as Ae, WxSelect as je, WxInputNumber as Pe, WxTextarea as Oe, WxInput as Te, WxDivider as Re, WxCol as Ee, WxRow as Ne, WxCard as Ve, WxTab as Ce, WxForm as Me } from "@webx-ui/core";
2
+ import { defineComponent as $, h, useModel as q, computed as y, useAttrs as ze, inject as B, openBlock as E, createBlock as N, unref as g, mergeProps as U, withCtx as V, createVNode as K, mergeModels as P, ref as Ie, watch as L, renderSlot as _e, provide as De, markRaw as Fe, toRaw as qe } from "vue";
3
3
  function W(e, t) {
4
4
  for (let n = 0; n < e.length; n += 1) {
5
5
  const o = e[n];
6
6
  if (o.id === t) return { list: e, index: n, node: o };
7
7
  if (o.children) {
8
- const i = W(o.children, t);
9
- if (i) return i;
8
+ const r = W(o.children, t);
9
+ if (r) return r;
10
10
  }
11
11
  }
12
12
  return null;
13
13
  }
14
- function sn(e, t) {
14
+ function ln(e, t) {
15
15
  return W(e, t)?.node ?? null;
16
16
  }
17
- function j(e) {
17
+ function A(e) {
18
18
  const t = [], n = (o) => {
19
- for (const i of o)
20
- t.push(i.id), i.children && n(i.children);
19
+ for (const r of o)
20
+ t.push(r.id), r.children && n(r.children);
21
21
  };
22
22
  return n(e), t;
23
23
  }
24
24
  function I(e, t) {
25
25
  if (!t || t === "last") return e.length;
26
26
  if (t === "first") return 0;
27
- const [n, o] = t.split(":", 2), i = e.findIndex((r) => r.id === o);
28
- return i === -1 ? `no sibling "${o}" to insert ${n}` : n === "before" ? i : i + 1;
27
+ const [n, o] = t.split(":", 2), r = e.findIndex((i) => i.id === o);
28
+ return r === -1 ? `no sibling "${o}" to insert ${n}` : n === "before" ? r : r + 1;
29
29
  }
30
- function k(e) {
31
- if (Array.isArray(e)) return e.map(k);
30
+ function w(e) {
31
+ if (Array.isArray(e)) return e.map(w);
32
32
  if (e && typeof e == "object") {
33
33
  const t = {};
34
- for (const [n, o] of Object.entries(e)) t[n] = k(o);
34
+ for (const [n, o] of Object.entries(e)) t[n] = w(o);
35
35
  return t;
36
36
  }
37
37
  return e;
38
38
  }
39
- function qe(e, t) {
40
- const n = k(e), o = [];
41
- return t.forEach((i, r) => {
42
- const s = Ue(n, i);
43
- s && o.push({ index: r, op: i, message: s });
39
+ function Be(e, t) {
40
+ const n = w(e), o = [];
41
+ return t.forEach((r, i) => {
42
+ const s = Ue(n, r);
43
+ s && o.push({ index: i, op: r, message: s });
44
44
  }), { root: n, errors: o };
45
45
  }
46
46
  function Ue(e, t) {
@@ -48,55 +48,55 @@ function Ue(e, t) {
48
48
  if (!n) return `target "${t.target}" not found`;
49
49
  switch (t.op) {
50
50
  case "add": {
51
- const o = D(e, t.node);
51
+ const o = _(e, t.node);
52
52
  if (o) return `id "${o}" already exists in the screen`;
53
- const i = n.node.children ??= [], r = I(i, t.position);
54
- return typeof r == "string" ? r : (i.splice(r, 0, k(t.node)), null);
53
+ const r = n.node.children ??= [], i = I(r, t.position);
54
+ return typeof i == "string" ? i : (r.splice(i, 0, w(t.node)), null);
55
55
  }
56
56
  case "remove":
57
57
  return n.list.splice(n.index, 1), null;
58
58
  case "replace": {
59
- const o = e.filter((r) => r !== n.node), i = D(o, t.node, n.node);
60
- return i ? `id "${i}" already exists in the screen` : (n.list.splice(n.index, 1, k(t.node)), null);
59
+ const o = e.filter((i) => i !== n.node), r = _(o, t.node, n.node);
60
+ return r ? `id "${r}" already exists in the screen` : (n.list.splice(n.index, 1, w(t.node)), null);
61
61
  }
62
62
  case "move": {
63
63
  let o = n.list;
64
64
  if (t.to !== void 0) {
65
- const r = W(e, t.to);
66
- if (!r) return `destination "${t.to}" not found`;
67
- if (r.node === n.node || L(n.node, r.node))
65
+ const i = W(e, t.to);
66
+ if (!i) return `destination "${t.to}" not found`;
67
+ if (i.node === n.node || H(n.node, i.node))
68
68
  return `cannot move "${t.target}" into itself`;
69
- o = r.node.children ??= [];
69
+ o = i.node.children ??= [];
70
70
  }
71
71
  n.list.splice(n.index, 1);
72
- const i = I(o, t.position);
73
- return typeof i == "string" ? (n.list.splice(n.index, 0, n.node), i) : (o.splice(i, 0, n.node), null);
72
+ const r = I(o, t.position);
73
+ return typeof r == "string" ? (n.list.splice(n.index, 0, n.node), r) : (o.splice(r, 0, n.node), null);
74
74
  }
75
75
  case "set": {
76
- for (const [o, i] of Object.entries(t))
77
- o === "op" || o === "target" || (o === "props" ? n.node.props = { ...n.node.props, ...i } : n.node[o] = k(i));
76
+ for (const [o, r] of Object.entries(t))
77
+ o === "op" || o === "target" || (o === "props" ? n.node.props = { ...n.node.props, ...r } : n.node[o] = w(r));
78
78
  return null;
79
79
  }
80
80
  }
81
81
  }
82
- function L(e, t) {
83
- return (e.children ?? []).some((n) => n === t || L(n, t));
82
+ function H(e, t) {
83
+ return (e.children ?? []).some((n) => n === t || H(n, t));
84
84
  }
85
- function D(e, t, n) {
86
- const o = new Set(j(e));
87
- if (n) for (const i of j([n])) o.delete(i);
88
- return j([t]).find((i) => o.has(i)) ?? null;
85
+ function _(e, t, n) {
86
+ const o = new Set(A(e));
87
+ if (n) for (const r of A([n])) o.delete(r);
88
+ return A([t]).find((r) => o.has(r)) ?? null;
89
89
  }
90
- function A(e, t) {
90
+ function j(e, t) {
91
91
  return e === t ? !0 : e === null || t === null || typeof e != "object" || typeof t != "object" ? !1 : JSON.stringify(e) === JSON.stringify(t);
92
92
  }
93
93
  function O(e, t) {
94
94
  if ("all" in e) return e.all.every((o) => O(o, t));
95
95
  if ("any" in e) return e.any.some((o) => O(o, t));
96
96
  const n = t[e.when];
97
- return "in" in e ? e.in.some((o) => A(o, n)) : "not" in e ? !A(e.not, n) : A(e.is, n);
97
+ return "in" in e ? e.in.some((o) => j(o, n)) : "not" in e ? !j(e.not, n) : j(e.is, n);
98
98
  }
99
- function Be(e, t) {
99
+ function Ke(e, t) {
100
100
  const { visible: n } = e;
101
101
  return n === void 0 || n === !0 ? !0 : n === !1 ? !1 : O(n, t);
102
102
  }
@@ -113,180 +113,180 @@ const X = /* @__PURE__ */ new Set([
113
113
  "slot",
114
114
  "visible",
115
115
  "can"
116
- ]), Ke = /* @__PURE__ */ new Set(["add", "remove", "replace", "move", "set"]);
117
- function w(e) {
116
+ ]), Le = /* @__PURE__ */ new Set(["add", "remove", "replace", "move", "set"]);
117
+ function k(e) {
118
118
  return typeof e == "object" && e !== null && !Array.isArray(e);
119
119
  }
120
120
  function G(e, t, n) {
121
- if (!w(e)) {
121
+ if (!k(e)) {
122
122
  n.push({ path: t, message: "visible must be a boolean or a condition object" });
123
123
  return;
124
124
  }
125
125
  if ("all" in e || "any" in e) {
126
- const i = e.all ?? e.any;
127
- if (!Array.isArray(i)) {
126
+ const r = e.all ?? e.any;
127
+ if (!Array.isArray(r)) {
128
128
  n.push({ path: t, message: '"all" / "any" must be an array of conditions' });
129
129
  return;
130
130
  }
131
- i.forEach((r, s) => G(r, `${t}[${s}]`, n));
131
+ r.forEach((i, s) => G(i, `${t}[${s}]`, n));
132
132
  return;
133
133
  }
134
134
  if (typeof e.when != "string") {
135
135
  n.push({ path: t, message: 'a condition needs "when": the name of a field' });
136
136
  return;
137
137
  }
138
- const o = ["is", "in", "not"].filter((i) => i in e);
138
+ const o = ["is", "in", "not"].filter((r) => r in e);
139
139
  o.length !== 1 ? n.push({ path: t, message: 'a condition needs exactly one of "is", "in", "not"' }) : o[0] === "in" && !Array.isArray(e.in) && n.push({ path: t, message: '"in" must be an array' });
140
140
  }
141
141
  function C(e, t, n, o) {
142
- if (!w(e)) {
142
+ if (!k(e)) {
143
143
  n.push({ path: t, message: "a node must be an object" });
144
144
  return;
145
145
  }
146
- for (const i of Object.keys(e))
147
- X.has(i) || n.push({ path: t, message: `unknown key "${i}"` });
146
+ for (const r of Object.keys(e))
147
+ X.has(r) || n.push({ path: t, message: `unknown key "${r}"` });
148
148
  typeof e.id != "string" || e.id === "" ? n.push({ path: t, message: '"id" is required and must be a non-empty string' }) : o.has(e.id) ? n.push({ path: t, message: `duplicate id "${e.id}"` }) : o.add(e.id), (typeof e.type != "string" || e.type === "") && n.push({ path: t, message: '"type" is required and must be a non-empty string' });
149
- for (const i of ["name", "label", "help"])
150
- i in e && typeof e[i] != "string" && n.push({ path: t, message: `"${i}" must be a string` });
151
- "localized" in e && typeof e.localized != "boolean" && n.push({ path: t, message: '"localized" must be a boolean' }), "props" in e && !w(e.props) && n.push({ path: t, message: '"props" must be an object' }), "slot" in e && e.slot !== null && typeof e.slot != "string" && n.push({ path: t, message: '"slot" must be a string or null' }), "can" in e && e.can !== null && typeof e.can != "string" && n.push({ path: t, message: '"can" must be a string or null' }), "visible" in e && typeof e.visible != "boolean" && G(e.visible, `${t}.visible`, n), "children" in e && (Array.isArray(e.children) ? e.children.forEach(
152
- (i, r) => C(i, `${t}.children[${r}]`, n, o)
149
+ for (const r of ["name", "label", "help"])
150
+ r in e && typeof e[r] != "string" && n.push({ path: t, message: `"${r}" must be a string` });
151
+ "localized" in e && typeof e.localized != "boolean" && n.push({ path: t, message: '"localized" must be a boolean' }), "props" in e && !k(e.props) && n.push({ path: t, message: '"props" must be an object' }), "slot" in e && e.slot !== null && typeof e.slot != "string" && n.push({ path: t, message: '"slot" must be a string or null' }), "can" in e && e.can !== null && typeof e.can != "string" && n.push({ path: t, message: '"can" must be a string or null' }), "visible" in e && typeof e.visible != "boolean" && G(e.visible, `${t}.visible`, n), "children" in e && (Array.isArray(e.children) ? e.children.forEach(
152
+ (r, i) => C(r, `${t}.children[${i}]`, n, o)
153
153
  ) : n.push({ path: t, message: '"children" must be an array' }));
154
154
  }
155
- function an(e) {
155
+ function cn(e) {
156
156
  const t = [];
157
157
  if (!Array.isArray(e)) return [{ path: "root", message: "root must be an array of nodes" }];
158
158
  const n = /* @__PURE__ */ new Set();
159
- return e.forEach((o, i) => C(o, `root[${i}]`, t, n)), t;
159
+ return e.forEach((o, r) => C(o, `root[${r}]`, t, n)), t;
160
160
  }
161
- function ln(e) {
161
+ function dn(e) {
162
162
  const t = [];
163
163
  return Array.isArray(e) ? (e.forEach((n, o) => {
164
- const i = `patch[${o}]`;
165
- if (!w(n)) {
166
- t.push({ path: i, message: "an operation must be an object" });
164
+ const r = `patch[${o}]`;
165
+ if (!k(n)) {
166
+ t.push({ path: r, message: "an operation must be an object" });
167
167
  return;
168
168
  }
169
- if (typeof n.op != "string" || !Ke.has(n.op)) {
170
- t.push({ path: i, message: '"op" must be one of add, remove, replace, move, set' });
169
+ if (typeof n.op != "string" || !Le.has(n.op)) {
170
+ t.push({ path: r, message: '"op" must be one of add, remove, replace, move, set' });
171
171
  return;
172
172
  }
173
- if ((typeof n.target != "string" || n.target === "") && t.push({ path: i, message: '"target" is required: the id of a node' }), (n.op === "add" || n.op === "replace") && !w(n.node) ? t.push({ path: i, message: `"${n.op}" needs a "node"` }) : (n.op === "add" || n.op === "replace") && C(n.node, `${i}.node`, t, /* @__PURE__ */ new Set()), "position" in n && !He(n.position) && t.push({ path: i, message: '"position" must be first, last, before:<id> or after:<id>' }), n.op === "move" && "to" in n && typeof n.to != "string" && t.push({ path: i, message: '"to" must be the id of the new parent' }), n.op === "set")
174
- for (const r of Object.keys(n))
175
- r !== "op" && r !== "target" && (!X.has(r) || r === "id") && t.push({ path: i, message: `"set" cannot change "${r}"` });
173
+ if ((typeof n.target != "string" || n.target === "") && t.push({ path: r, message: '"target" is required: the id of a node' }), (n.op === "add" || n.op === "replace") && !k(n.node) ? t.push({ path: r, message: `"${n.op}" needs a "node"` }) : (n.op === "add" || n.op === "replace") && C(n.node, `${r}.node`, t, /* @__PURE__ */ new Set()), "position" in n && !He(n.position) && t.push({ path: r, message: '"position" must be first, last, before:<id> or after:<id>' }), n.op === "move" && "to" in n && typeof n.to != "string" && t.push({ path: r, message: '"to" must be the id of the new parent' }), n.op === "set")
174
+ for (const i of Object.keys(n))
175
+ i !== "op" && i !== "target" && (!X.has(i) || i === "id") && t.push({ path: r, message: `"set" cannot change "${i}"` });
176
176
  }), t) : [{ path: "patch", message: "a patch must be an array" }];
177
177
  }
178
178
  function He(e) {
179
179
  return typeof e == "string" && (e === "first" || e === "last" || e.startsWith("before:") || e.startsWith("after:"));
180
180
  }
181
- const _ = "trans::", M = /* @__PURE__ */ Symbol("wx-screen-errors");
181
+ const D = "trans::", M = /* @__PURE__ */ Symbol("wx-screen-errors");
182
182
  function F(e, t) {
183
- return e.can && !t.can(e.can) ? !1 : Be(e, t.model);
183
+ return e.can && !t.can(e.can) ? !1 : Ke(e, t.model);
184
184
  }
185
185
  function J(e, t) {
186
186
  let n;
187
- const o = (i) => {
188
- for (const r of i) {
189
- if (r.name === void 0) {
190
- o(r.children ?? []);
187
+ const o = (r) => {
188
+ for (const i of r) {
189
+ if (i.name === void 0) {
190
+ o(i.children ?? []);
191
191
  continue;
192
192
  }
193
- const s = t[r.name];
194
- r.default !== void 0 && s == null && (n ??= { ...t }, n[r.name] = r.default);
193
+ const s = t[i.name];
194
+ i.default !== void 0 && s == null && (n ??= { ...t }, n[i.name] = i.default);
195
195
  }
196
196
  };
197
197
  return o(e), n ?? t;
198
198
  }
199
- const Le = (e) => e;
199
+ const Xe = (e) => e;
200
200
  function T(e, t) {
201
- return typeof e == "string" && e.startsWith(_) ? t(e.slice(_.length)) : e;
201
+ return typeof e == "string" && e.startsWith(D) ? t(e.slice(D.length)) : e;
202
202
  }
203
- function E(e, t) {
203
+ function R(e, t) {
204
204
  if (typeof e == "string") return T(e, t);
205
- if (Array.isArray(e)) return e.map((n) => E(n, t));
205
+ if (Array.isArray(e)) return e.map((n) => R(n, t));
206
206
  if (e && typeof e == "object") {
207
207
  const n = {};
208
- for (const [o, i] of Object.entries(e)) n[o] = E(i, t);
208
+ for (const [o, r] of Object.entries(e)) n[o] = R(r, t);
209
209
  return n;
210
210
  }
211
211
  return e;
212
212
  }
213
- function Xe(e) {
214
- return x(
213
+ function Ge(e) {
214
+ return h(
215
215
  "div",
216
216
  { key: e.id, class: "wx-screen__unknown", role: "note" },
217
217
  `Unknown type: ${e.type}`
218
218
  );
219
219
  }
220
- function Ge(e, t, n) {
220
+ function Je(e, t, n) {
221
221
  const o = /* @__PURE__ */ new Map();
222
- for (const r of e.children ?? []) {
223
- const s = r.slot ?? t, d = o.get(s) ?? [];
224
- d.push(r), o.set(s, d);
222
+ for (const i of e.children ?? []) {
223
+ const s = i.slot ?? t, c = o.get(s) ?? [];
224
+ c.push(i), o.set(s, c);
225
225
  }
226
- const i = {};
227
- for (const [r, s] of o)
228
- i[r] = () => Y(s, n);
229
- return i;
226
+ const r = {};
227
+ for (const [i, s] of o)
228
+ r[i] = () => Q(s, n);
229
+ return r;
230
230
  }
231
- function Je(e, t) {
231
+ function Qe(e, t) {
232
232
  if (!F(e, t)) return null;
233
233
  const n = t.types[e.type];
234
- if (!n) return Xe(e);
234
+ if (!n) return Ge(e);
235
235
  if (n.kind === "layout" && e.children !== void 0 && !e.children.some((f) => F(f, t)))
236
236
  return null;
237
- const { translate: o } = t, i = {
237
+ const { translate: o } = t, r = {
238
238
  key: e.id,
239
- ...E(e.props ?? {}, o),
239
+ ...R(e.props ?? {}, o),
240
240
  ...n.bind?.(e)
241
- }, r = T(e.label, o);
241
+ }, i = T(e.label, o);
242
242
  if (n.kind === "field") {
243
- const f = e.name, b = n.labelProp !== void 0 && r !== void 0, u = x(n.component, {
244
- ...i,
245
- ...b ? { [n.labelProp]: r } : {},
243
+ const f = e.name, b = n.labelProp !== void 0 && i !== void 0, u = h(n.component, {
244
+ ...r,
245
+ ...b ? { [n.labelProp]: i } : {},
246
246
  /* A nested field draws the children itself, so it needs the node and the way down. */
247
247
  ...n.nested ? { node: e, context: t } : {},
248
248
  name: f,
249
249
  localized: e.localized || void 0,
250
250
  modelValue: f === void 0 ? void 0 : t.model[f],
251
- "onUpdate:modelValue": (c) => {
252
- f !== void 0 && t.update(f, c);
251
+ "onUpdate:modelValue": (d) => {
252
+ f !== void 0 && t.update(f, d);
253
253
  }
254
254
  });
255
- return x(
256
- ne,
255
+ return h(
256
+ te,
257
257
  {
258
258
  key: e.id,
259
259
  name: f,
260
- label: b ? void 0 : r,
260
+ label: b ? void 0 : i,
261
261
  help: T(e.help, o),
262
- wide: n.wide
262
+ wide: typeof n.wide == "function" ? n.wide(e) : n.wide
263
263
  },
264
264
  () => u
265
265
  );
266
266
  }
267
267
  if (n.kind === "layout")
268
- return n.labelProp && r !== void 0 && (i[n.labelProp] = r), x(n.component, i, Ge(e, n.childrenSlot ?? "default", t));
268
+ return n.labelProp && i !== void 0 && (r[n.labelProp] = i), h(n.component, r, Je(e, n.childrenSlot ?? "default", t));
269
269
  if (n.labelProp)
270
- return r !== void 0 && (i[n.labelProp] = r), x(n.component, i);
271
- const s = typeof i.text == "string" ? i.text : void 0, d = r ?? s;
272
- return s !== void 0 && r === void 0 && delete i.text, x(n.component, i, d === void 0 ? void 0 : () => d);
270
+ return i !== void 0 && (r[n.labelProp] = i), h(n.component, r);
271
+ const s = typeof r.text == "string" ? r.text : void 0, c = i ?? s;
272
+ return s !== void 0 && i === void 0 && delete r.text, h(n.component, r, c === void 0 ? void 0 : () => c);
273
273
  }
274
- function Y(e, t) {
274
+ function Q(e, t) {
275
275
  const n = [];
276
276
  for (const o of e) {
277
- const i = Je(o, t);
278
- i && n.push(i);
277
+ const r = Qe(o, t);
278
+ r && n.push(r);
279
279
  }
280
280
  return n;
281
281
  }
282
- const Q = $({
282
+ const Y = $({
283
283
  name: "WxScreenNodes",
284
284
  props: {
285
285
  nodes: { type: Array, required: !0 },
286
286
  context: { type: Object, required: !0 }
287
287
  },
288
288
  setup(e) {
289
- return () => Y(e.nodes, e.context);
289
+ return () => Q(e.nodes, e.context);
290
290
  }
291
291
  }), Ye = /* @__PURE__ */ $({
292
292
  name: "WxScreenRepeater",
@@ -303,50 +303,52 @@ const Q = $({
303
303
  }),
304
304
  emits: ["update:modelValue"],
305
305
  setup(e) {
306
- const t = e, n = q(e, "modelValue"), o = y(() => Array.isArray(n.value) ? n.value : []), i = Me();
307
- function r(u) {
306
+ const t = e, n = q(e, "modelValue"), o = y(() => Array.isArray(n.value) ? n.value : []), r = ze();
307
+ function i(u) {
308
308
  return u.flatMap(
309
- (c) => c.name === void 0 ? r(c.children ?? []) : [c.name]
309
+ (d) => d.name === void 0 ? i(d.children ?? []) : [d.name]
310
310
  );
311
311
  }
312
- const s = U(M, null), d = y(() => {
312
+ const s = B(M, null), c = y(() => {
313
313
  const u = s?.value;
314
314
  if (t.name === void 0) return;
315
- const c = r(t.node.children ?? []);
315
+ const d = i(t.node.children ?? []);
316
316
  return o.value.map((l, a) => {
317
317
  const p = `${t.name}.${a}.`, m = {};
318
- for (const [h, v] of Object.entries(u ?? {})) {
319
- if (!h.startsWith(p)) continue;
320
- const z = h.slice(p.length), S = c.find((ee) => z.startsWith(`${ee}.`));
318
+ for (const [x, v] of Object.entries(u ?? {})) {
319
+ if (!x.startsWith(p)) continue;
320
+ const z = x.slice(p.length), S = d.find((ne) => z.startsWith(`${ne}.`));
321
321
  m[z] = v, S !== void 0 && m[S] === void 0 && (m[S] = v);
322
322
  }
323
323
  return m;
324
324
  });
325
325
  });
326
326
  function f(u) {
327
- const c = t.context.translate(`webx-admin::screens.repeater.${u}`);
328
- return c.includes("::") ? void 0 : c;
327
+ const d = t.context.translate(`webx-admin::screens.repeater.${u}`);
328
+ return d.includes("::") ? void 0 : d;
329
329
  }
330
330
  const b = y(() => {
331
- const u = { collapsed: !0 };
332
- for (const [c, l] of [
331
+ const u = { collapsed: !0, confirmRemove: !0 };
332
+ for (const [d, l] of [
333
333
  ["addLabel", "add"],
334
334
  ["removeLabel", "remove"],
335
+ ["removeQuestion", "remove-question"],
336
+ ["cancelLabel", "cancel"],
335
337
  ["dragLabel", "reorder"],
336
338
  ["emptyText", "empty"]
337
339
  ]) {
338
340
  const a = f(l);
339
- a !== void 0 && (u[c] = a);
341
+ a !== void 0 && (u[d] = a);
340
342
  }
341
- return { ...u, ...i };
343
+ return { ...u, ...r };
342
344
  });
343
- return (u, c) => (R(), N(g(te), B(b.value, {
345
+ return (u, d) => (E(), N(g(oe), U(b.value, {
344
346
  "model-value": o.value,
345
- "row-errors": d.value,
346
- "onUpdate:modelValue": c[0] || (c[0] = (l) => n.value = l)
347
+ "row-errors": c.value,
348
+ "onUpdate:modelValue": d[0] || (d[0] = (l) => n.value = l)
347
349
  }), {
348
350
  default: V(({ item: l, update: a }) => [
349
- K(g(Q), {
351
+ K(g(Y), {
350
352
  nodes: e.node.children ?? [],
351
353
  context: {
352
354
  ...e.context,
@@ -358,7 +360,7 @@ const Q = $({
358
360
  _: 1
359
361
  }, 16, ["model-value", "row-errors"]));
360
362
  }
361
- }), Qe = /* @__PURE__ */ $({
363
+ }), Ze = /* @__PURE__ */ $({
362
364
  name: "WxScreenTabs",
363
365
  inheritAttrs: !1,
364
366
  __name: "ScreenTabs",
@@ -366,19 +368,19 @@ const Q = $({
366
368
  fields: { default: () => ({}) }
367
369
  },
368
370
  setup(e) {
369
- const t = e, n = U(M, null), o = ze(void 0), i = y(() => {
370
- const r = new Set(Object.keys(n?.value ?? {}));
371
- return Object.entries(t.fields).filter(([, s]) => s.some((d) => r.has(d))).map(([s]) => s);
371
+ const t = e, n = B(M, null), o = Ie(void 0), r = y(() => {
372
+ const i = new Set(Object.keys(n?.value ?? {}));
373
+ return Object.entries(t.fields).filter(([, s]) => s.some((c) => i.has(c))).map(([s]) => s);
372
374
  });
373
- return H(i, (r) => {
374
- const s = r[0];
375
- s !== void 0 && (o.value !== void 0 && r.includes(String(o.value)) || (o.value = s));
376
- }), (r, s) => (R(), N(g(oe), B({
375
+ return L(r, (i) => {
376
+ const s = i[0];
377
+ s !== void 0 && (o.value !== void 0 && i.includes(String(o.value)) || (o.value = s));
378
+ }), (i, s) => (E(), N(g(re), U({
377
379
  modelValue: o.value,
378
- "onUpdate:modelValue": s[0] || (s[0] = (d) => o.value = d)
379
- }, r.$attrs), {
380
+ "onUpdate:modelValue": s[0] || (s[0] = (c) => o.value = c)
381
+ }, i.$attrs), {
380
382
  default: V(() => [
381
- Ie(r.$slots, "default")
383
+ _e(i.$slots, "default")
382
384
  ]),
383
385
  _: 3
384
386
  }, 16, ["modelValue"]));
@@ -389,9 +391,15 @@ function Z(e) {
389
391
  (t) => t.name === void 0 ? Z(t) : [t.name]
390
392
  );
391
393
  }
392
- const Ze = {
394
+ const en = /* @__PURE__ */ new Set(["wx-row", "wx-col", "wx-transfer", "wx-code-editor", "wx-rich-text"]);
395
+ function ee(e) {
396
+ return (e.children ?? []).some(
397
+ (t) => en.has(t.type) || t.type !== "wx-repeater" && ee(t)
398
+ );
399
+ }
400
+ const nn = {
393
401
  "wx-tabs": {
394
- component: Qe,
402
+ component: Ze,
395
403
  kind: "layout",
396
404
  // Which fields each tab holds, so a refused save can open the tab it was refused on.
397
405
  bind: (e) => ({
@@ -399,15 +407,15 @@ const Ze = {
399
407
  })
400
408
  },
401
409
  "wx-tab": {
402
- component: Ve,
410
+ component: Ce,
403
411
  kind: "layout",
404
412
  labelProp: "label",
405
413
  // A tab is selected by value, and the node's id is the one stable thing it has.
406
414
  bind: (e) => ({ value: e.id })
407
415
  },
408
- "wx-card": { component: Ne, kind: "layout", labelProp: "title" },
416
+ "wx-card": { component: Ve, kind: "layout", labelProp: "title" },
409
417
  "wx-row": {
410
- component: Re,
418
+ component: Ne,
411
419
  kind: "layout",
412
420
  // Marked so the renderer can hold a row at the width of one field (see `ScreenRenderer.vue`).
413
421
  bind: (e) => ({ class: ["wx-screen__row", e.props?.class] })
@@ -419,78 +427,78 @@ const Ze = {
419
427
  // without touching a `WxCol` that some field happens to use inside itself.
420
428
  bind: (e) => ({ class: ["wx-screen__col", e.props?.class] })
421
429
  },
422
- "wx-divider": { component: Te, kind: "layout", labelProp: "label" },
423
- "wx-input": { component: Oe, kind: "field" },
424
- "wx-textarea": { component: Pe, kind: "field" },
425
- "wx-input-number": { component: Ae, kind: "field" },
430
+ "wx-divider": { component: Re, kind: "layout", labelProp: "label" },
431
+ "wx-input": { component: Te, kind: "field" },
432
+ "wx-textarea": { component: Oe, kind: "field" },
433
+ "wx-input-number": { component: Pe, kind: "field" },
426
434
  "wx-select": { component: je, kind: "field" },
427
435
  // The label beside the control rather than above it: on, off, and what is being turned.
428
- "wx-switch": { component: Se, kind: "field", labelProp: "label" },
429
- "wx-checkbox": { component: $e, kind: "field", labelProp: "label" },
430
- "wx-radio-group": { component: We, kind: "field" },
431
- "wx-date-picker": { component: ve, kind: "field" },
432
- "wx-color-picker": { component: we, kind: "field" },
436
+ "wx-switch": { component: Ae, kind: "field", labelProp: "label" },
437
+ "wx-checkbox": { component: Se, kind: "field", labelProp: "label" },
438
+ "wx-radio-group": { component: $e, kind: "field" },
439
+ "wx-date-picker": { component: We, kind: "field" },
440
+ "wx-color-picker": { component: ve, kind: "field" },
433
441
  "wx-checkbox-group": { component: ke, kind: "field" },
434
- "wx-segmented": { component: ge, kind: "field" },
435
- "wx-slider": { component: xe, kind: "field" },
442
+ "wx-segmented": { component: we, kind: "field" },
443
+ "wx-slider": { component: ge, kind: "field" },
436
444
  "wx-rate": { component: he, kind: "field" },
437
- "wx-time-picker": { component: be, kind: "field" },
445
+ "wx-time-picker": { component: xe, kind: "field" },
438
446
  "wx-date-time-picker": {
439
- component: ye,
447
+ component: be,
440
448
  kind: "field",
441
449
  // A moment, not a wall clock. Without the offset the server reads the hour in its own
442
450
  // timezone and the browser in the reader's, and one value shows two different times. Bound
443
451
  // over `props` on purpose: the server parses exactly this shape.
444
452
  bind: () => ({ valueFormat: "yyyy-MM-dd'T'HH:mm:ssXXX" })
445
453
  },
446
- "wx-date-range-picker": { component: me, kind: "field" },
447
- "wx-tags-input": { component: pe, kind: "field" },
448
- "wx-autocomplete": { component: ue, kind: "field" },
449
- "wx-icon-picker": { component: fe, kind: "field" },
450
- "wx-cascader": { component: ce, kind: "field" },
454
+ "wx-date-range-picker": { component: ye, kind: "field" },
455
+ "wx-tags-input": { component: me, kind: "field" },
456
+ "wx-autocomplete": { component: pe, kind: "field" },
457
+ "wx-icon-picker": { component: ue, kind: "field" },
458
+ "wx-cascader": { component: fe, kind: "field" },
451
459
  "wx-tree-select": { component: de, kind: "field" },
452
460
  // Wide: two lists with the buttons between them do not fit in half a form.
453
- "wx-transfer": { component: le, kind: "field", wide: !0 },
461
+ "wx-transfer": { component: ce, kind: "field", wide: !0 },
454
462
  // Wide for the reason an editor is: code is read in long lines.
455
- "wx-code-editor": { component: ae, kind: "field", wide: !0 },
456
- "wx-repeater": { component: Ye, kind: "field", nested: !0, wide: !0 },
457
- "wx-heading": { component: se, kind: "display" },
458
- "wx-text": { component: re, kind: "display" },
463
+ "wx-code-editor": { component: le, kind: "field", wide: !0 },
464
+ "wx-repeater": { component: Ye, kind: "field", nested: !0, wide: ee },
465
+ "wx-heading": { component: ae, kind: "display" },
466
+ "wx-text": { component: se, kind: "display" },
459
467
  "wx-alert": { component: ie, kind: "display", labelProp: "title" }
460
468
  };
461
- function dn(e) {
469
+ function fn(e) {
462
470
  return e;
463
471
  }
464
- function en(e) {
472
+ function tn(e) {
465
473
  const t = e.component;
466
474
  return t.name ?? t.__name ?? "anonymous";
467
475
  }
468
- function nn(e) {
476
+ function on(e) {
469
477
  return e.kind === "field" ? "form item" : e.labelProp ? `prop \`${e.labelProp}\`` : e.kind === "display" ? "default slot" : "—";
470
478
  }
471
- function tn(e) {
479
+ function rn(e) {
472
480
  return Object.entries(e).map(([t, n]) => ({
473
481
  type: t,
474
482
  kind: n.kind,
475
- component: en(n),
476
- label: nn(n)
483
+ component: tn(n),
484
+ label: on(n)
477
485
  }));
478
486
  }
479
- function cn(e) {
480
- const t = tn(e).map((r) => [
481
- `\`${r.type}\``,
482
- r.kind,
483
- `\`${r.component}\``,
484
- r.label
487
+ function un(e) {
488
+ const t = rn(e).map((i) => [
489
+ `\`${i.type}\``,
490
+ i.kind,
491
+ `\`${i.component}\``,
492
+ i.label
485
493
  ]), n = ["Type", "Kind", "Component", "`label` goes to"], o = n.map(
486
- (r, s) => Math.max(r.length, ...t.map((d) => d[s].length))
487
- ), i = (r) => `| ${r.map((s, d) => s.padEnd(o[d])).join(" | ")} |`;
488
- return [i(n), i(o.map((r) => "-".repeat(r))), ...t.map(i)].join(
494
+ (i, s) => Math.max(i.length, ...t.map((c) => c[s].length))
495
+ ), r = (i) => `| ${i.map((s, c) => s.padEnd(o[c])).join(" | ")} |`;
496
+ return [r(n), r(o.map((i) => "-".repeat(i))), ...t.map(r)].join(
489
497
  `
490
498
  `
491
499
  );
492
500
  }
493
- const fn = /* @__PURE__ */ $({
501
+ const pn = /* @__PURE__ */ $({
494
502
  name: "WxScreenRenderer",
495
503
  __name: "ScreenRenderer",
496
504
  props: /* @__PURE__ */ P({
@@ -510,18 +518,18 @@ const fn = /* @__PURE__ */ $({
510
518
  }),
511
519
  emits: /* @__PURE__ */ P(["patchError"], ["update:modelValue"]),
512
520
  setup(e, { expose: t, emit: n }) {
513
- const o = e, i = n, r = q(e, "modelValue"), s = y(() => qe(o.root, o.patch));
514
- function d(l) {
521
+ const o = e, r = n, i = q(e, "modelValue"), s = y(() => Be(o.root, o.patch));
522
+ function c(l) {
515
523
  return l.flatMap(
516
- (a) => a.name === void 0 ? d(a.children ?? []) : [a.name]
524
+ (a) => a.name === void 0 ? c(a.children ?? []) : [a.name]
517
525
  );
518
526
  }
519
527
  const f = y(() => {
520
528
  if (o.errors === void 0) return;
521
- const l = d(s.value.root), a = { ...o.errors };
529
+ const l = c(s.value.root), a = { ...o.errors };
522
530
  for (const [p, m] of Object.entries(o.errors)) {
523
- const h = l.find((v) => p.startsWith(`${v}.`));
524
- h !== void 0 && a[h] === void 0 && (a[h] = m);
531
+ const x = l.find((v) => p.startsWith(`${v}.`));
532
+ x !== void 0 && a[x] === void 0 && (a[x] = m);
525
533
  }
526
534
  return a;
527
535
  }), b = y(() => {
@@ -534,34 +542,34 @@ const fn = /* @__PURE__ */ $({
534
542
  }
535
543
  return l;
536
544
  });
537
- De(M, f), H(
545
+ De(M, f), L(
538
546
  () => s.value.errors,
539
547
  (l) => {
540
548
  for (const a of l)
541
549
  console.error(`[webx-ui/schema] patch[${a.index}] ${a.op.op}: ${a.message}`);
542
- i("patchError", l);
550
+ r("patchError", l);
543
551
  },
544
552
  { immediate: !0 }
545
553
  );
546
554
  const u = y(() => {
547
555
  const l = {};
548
- for (const [a, p] of Object.entries({ ...Ze, ...o.types }))
549
- l[a] = { ...p, component: _e(Fe(p.component)) };
556
+ for (const [a, p] of Object.entries({ ...nn, ...o.types }))
557
+ l[a] = { ...p, component: Fe(qe(p.component)) };
550
558
  return l;
551
- }), c = y(() => ({
559
+ }), d = y(() => ({
552
560
  types: u.value,
553
561
  // Drawn with the defaults filled in; `update` below writes to the model as it is.
554
- model: J(s.value.root, r.value),
562
+ model: J(s.value.root, i.value),
555
563
  update: (l, a) => {
556
- r.value = { ...r.value, [l]: a };
564
+ i.value = { ...i.value, [l]: a };
557
565
  },
558
- translate: o.translate ?? Le,
566
+ translate: o.translate ?? Xe,
559
567
  can: o.can ?? (() => !0)
560
568
  }));
561
569
  return t({
562
570
  /** The tree after the patch — what is actually on screen. */
563
571
  tree: y(() => s.value.root)
564
- }), (l, a) => (R(), N(g(Ce), {
572
+ }), (l, a) => (E(), N(g(Me), {
565
573
  class: "wx-screen",
566
574
  errors: b.value,
567
575
  disabled: e.disabled,
@@ -570,9 +578,9 @@ const fn = /* @__PURE__ */ $({
570
578
  size: e.size
571
579
  }, {
572
580
  default: V(() => [
573
- K(g(Q), {
581
+ K(g(Y), {
574
582
  nodes: s.value.root,
575
- context: c.value
583
+ context: d.value
576
584
  }, null, 8, ["nodes", "context"])
577
585
  ]),
578
586
  _: 1
@@ -580,22 +588,22 @@ const fn = /* @__PURE__ */ $({
580
588
  }
581
589
  });
582
590
  export {
583
- _ as TRANS_MARKER,
584
- Q as WxScreenNodes,
585
- fn as WxScreenRenderer,
586
- qe as applyPatch,
587
- j as collectIds,
588
- Ze as coreTypes,
589
- dn as defineTypes,
590
- tn as describeTypes,
591
+ D as TRANS_MARKER,
592
+ Y as WxScreenNodes,
593
+ pn as WxScreenRenderer,
594
+ Be as applyPatch,
595
+ A as collectIds,
596
+ nn as coreTypes,
597
+ fn as defineTypes,
598
+ rn as describeTypes,
591
599
  O as evaluateCondition,
592
- sn as findNode,
593
- Be as isVisible,
600
+ ln as findNode,
601
+ Ke as isVisible,
594
602
  M as screenErrorsKey,
595
- E as translateDeep,
596
- cn as typesTable,
597
- ln as validatePatch,
598
- an as validateScreen,
603
+ R as translateDeep,
604
+ un as typesTable,
605
+ dn as validatePatch,
606
+ cn as validateScreen,
599
607
  J as withFieldDefaults,
600
608
  T as words
601
609
  };
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":["../src/patch.ts","../src/visible.ts","../src/validate.ts","../src/render.ts","../src/ScreenRepeater.vue","../src/ScreenTabs.vue","../src/registry.ts","../src/ScreenRenderer.vue"],"sourcesContent":["import type { Patch, PatchError, PatchOperation, PatchPosition, ScreenNode } from './types'\n\ninterface Located {\n /** The array the node sits in: the root, or a parent's `children`. */\n list: ScreenNode[]\n index: number\n node: ScreenNode\n}\n\n/** Depth-first search by `id`, remembering the array the match lives in. */\nexport function locate(root: ScreenNode[], id: string): Located | null {\n for (let index = 0; index < root.length; index += 1) {\n const node = root[index]!\n if (node.id === id) return { list: root, index, node }\n if (node.children) {\n const found = locate(node.children, id)\n if (found) return found\n }\n }\n return null\n}\n\nexport function findNode(root: ScreenNode[], id: string): ScreenNode | null {\n return locate(root, id)?.node ?? null\n}\n\n/** Every `id` in the tree, in document order. Duplicates are kept, so callers can spot them. */\nexport function collectIds(root: ScreenNode[]): string[] {\n const ids: string[] = []\n const walk = (nodes: ScreenNode[]) => {\n for (const node of nodes) {\n ids.push(node.id)\n if (node.children) walk(node.children)\n }\n }\n walk(root)\n return ids\n}\n\n/** Index a node should be inserted at in `list`, or a message when the anchor is missing. */\nfunction indexFor(list: ScreenNode[], position: PatchPosition | undefined): number | string {\n if (!position || position === 'last') return list.length\n if (position === 'first') return 0\n const [where, anchor] = position.split(':', 2) as ['before' | 'after', string]\n const at = list.findIndex((node) => node.id === anchor)\n if (at === -1) return `no sibling \"${anchor}\" to insert ${where}`\n return where === 'before' ? at : at + 1\n}\n\n/**\n * Deep copy of a JSON value. `structuredClone` refuses a Vue reactive proxy, and a\n * tree that came out of a `ref` is exactly that; reading through the proxy is fine.\n */\nexport function clone<T>(value: T): T {\n if (Array.isArray(value)) return value.map(clone) as T\n if (value && typeof value === 'object') {\n const out: Record<string, unknown> = {}\n for (const [key, item] of Object.entries(value)) out[key] = clone(item)\n return out as T\n }\n return value\n}\n\n/**\n * Applies a patch to a tree and returns the result as a new tree; the input is not\n * touched. An operation that cannot be applied — a `target` that does not exist, an\n * anchor that is missing — is skipped and reported, and the ones after it still run:\n * a project patch that survived a rename in the module must not silence the rest.\n */\nexport function applyPatch(\n root: ScreenNode[],\n patch: Patch,\n): { root: ScreenNode[]; errors: PatchError[] } {\n const tree = clone(root)\n const errors: PatchError[] = []\n\n patch.forEach((op, index) => {\n const message = apply(tree, op)\n if (message) errors.push({ index, op, message })\n })\n\n return { root: tree, errors }\n}\n\n/** Mutates `tree`; returns a message when the operation was refused. */\nfunction apply(tree: ScreenNode[], op: PatchOperation): string | null {\n const found = locate(tree, op.target)\n if (!found) return `target \"${op.target}\" not found`\n\n switch (op.op) {\n case 'add': {\n const clash = duplicateIn(tree, op.node)\n if (clash) return `id \"${clash}\" already exists in the screen`\n const list = (found.node.children ??= [])\n const at = indexFor(list, op.position)\n if (typeof at === 'string') return at\n list.splice(at, 0, clone(op.node))\n return null\n }\n case 'remove':\n found.list.splice(found.index, 1)\n return null\n case 'replace': {\n // The replaced node's own ids are gone, so only the rest of the tree can clash.\n const others = tree.filter((node) => node !== found.node)\n const clash = duplicateIn(others, op.node, found.node)\n if (clash) return `id \"${clash}\" already exists in the screen`\n found.list.splice(found.index, 1, clone(op.node))\n return null\n }\n case 'move': {\n let list = found.list\n if (op.to !== undefined) {\n const parent = locate(tree, op.to)\n if (!parent) return `destination \"${op.to}\" not found`\n if (parent.node === found.node || contains(found.node, parent.node)) {\n return `cannot move \"${op.target}\" into itself`\n }\n list = parent.node.children ??= []\n }\n found.list.splice(found.index, 1)\n const at = indexFor(list, op.position)\n if (typeof at === 'string') {\n // Put it back where it was: a refused move leaves the tree untouched.\n found.list.splice(found.index, 0, found.node)\n return at\n }\n list.splice(at, 0, found.node)\n return null\n }\n case 'set': {\n for (const [key, value] of Object.entries(op)) {\n if (key === 'op' || key === 'target') continue\n if (key === 'props') {\n found.node.props = { ...found.node.props, ...(value as Record<string, unknown>) }\n } else {\n ;(found.node as unknown as Record<string, unknown>)[key] = clone(value)\n }\n }\n return null\n }\n }\n}\n\nfunction contains(ancestor: ScreenNode, node: ScreenNode): boolean {\n return (ancestor.children ?? []).some((child) => child === node || contains(child, node))\n}\n\n/** First id of `incoming` that already exists in `tree`, ignoring `except`'s own subtree. */\nfunction duplicateIn(tree: ScreenNode[], incoming: ScreenNode, except?: ScreenNode): string | null {\n const existing = new Set(collectIds(tree))\n if (except) for (const id of collectIds([except])) existing.delete(id)\n return collectIds([incoming]).find((id) => existing.has(id)) ?? null\n}\n","import type { ScreenModel, ScreenNode, VisibilityCondition } from './types'\n\n/** Loose enough for `{ \"is\": 1 }` to match a numeric input, strict enough for `\"1\"` not to. */\nfunction same(a: unknown, b: unknown): boolean {\n if (a === b) return true\n if (a === null || b === null || typeof a !== 'object' || typeof b !== 'object') return false\n return JSON.stringify(a) === JSON.stringify(b)\n}\n\nexport function evaluateCondition(condition: VisibilityCondition, model: ScreenModel): boolean {\n if ('all' in condition) return condition.all.every((item) => evaluateCondition(item, model))\n if ('any' in condition) return condition.any.some((item) => evaluateCondition(item, model))\n\n const value = model[condition.when]\n if ('in' in condition) return condition.in.some((item) => same(item, value))\n if ('not' in condition) return !same(condition.not, value)\n return same(condition.is, value)\n}\n\n/** Whether a node should render, given the current model. Absent `visible` means yes. */\nexport function isVisible(node: ScreenNode, model: ScreenModel): boolean {\n const { visible } = node\n if (visible === undefined || visible === true) return true\n if (visible === false) return false\n return evaluateCondition(visible, model)\n}\n","import type { Patch, ScreenError, ScreenNode, VisibilityCondition } from './types'\n\nconst NODE_KEYS = new Set([\n 'id',\n 'type',\n 'name',\n 'label',\n 'help',\n 'localized',\n 'default',\n 'props',\n 'children',\n 'slot',\n 'visible',\n 'can',\n])\n\nconst OPS = new Set(['add', 'remove', 'replace', 'move', 'set'])\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value)\n}\n\nfunction checkCondition(value: unknown, path: string, errors: ScreenError[]): void {\n if (!isRecord(value)) {\n errors.push({ path, message: 'visible must be a boolean or a condition object' })\n return\n }\n if ('all' in value || 'any' in value) {\n const list = (value.all ?? value.any) as unknown\n if (!Array.isArray(list)) {\n errors.push({ path, message: '\"all\" / \"any\" must be an array of conditions' })\n return\n }\n list.forEach((item, index) => checkCondition(item, `${path}[${index}]`, errors))\n return\n }\n if (typeof value.when !== 'string') {\n errors.push({ path, message: 'a condition needs \"when\": the name of a field' })\n return\n }\n const forms = ['is', 'in', 'not'].filter((key) => key in value)\n if (forms.length !== 1) {\n errors.push({ path, message: 'a condition needs exactly one of \"is\", \"in\", \"not\"' })\n } else if (forms[0] === 'in' && !Array.isArray(value.in)) {\n errors.push({ path, message: '\"in\" must be an array' })\n }\n}\n\nfunction checkNode(value: unknown, path: string, errors: ScreenError[], seen: Set<string>): void {\n if (!isRecord(value)) {\n errors.push({ path, message: 'a node must be an object' })\n return\n }\n\n for (const key of Object.keys(value)) {\n if (!NODE_KEYS.has(key)) errors.push({ path, message: `unknown key \"${key}\"` })\n }\n\n if (typeof value.id !== 'string' || value.id === '') {\n errors.push({ path, message: '\"id\" is required and must be a non-empty string' })\n } else if (seen.has(value.id)) {\n errors.push({ path, message: `duplicate id \"${value.id}\"` })\n } else {\n seen.add(value.id)\n }\n\n if (typeof value.type !== 'string' || value.type === '') {\n errors.push({ path, message: '\"type\" is required and must be a non-empty string' })\n }\n\n for (const key of ['name', 'label', 'help'] as const) {\n if (key in value && typeof value[key] !== 'string') {\n errors.push({ path, message: `\"${key}\" must be a string` })\n }\n }\n if ('localized' in value && typeof value.localized !== 'boolean') {\n errors.push({ path, message: '\"localized\" must be a boolean' })\n }\n if ('props' in value && !isRecord(value.props)) {\n errors.push({ path, message: '\"props\" must be an object' })\n }\n if ('slot' in value && value.slot !== null && typeof value.slot !== 'string') {\n errors.push({ path, message: '\"slot\" must be a string or null' })\n }\n if ('can' in value && value.can !== null && typeof value.can !== 'string') {\n errors.push({ path, message: '\"can\" must be a string or null' })\n }\n if ('visible' in value && typeof value.visible !== 'boolean') {\n checkCondition(value.visible as VisibilityCondition, `${path}.visible`, errors)\n }\n\n if ('children' in value) {\n if (!Array.isArray(value.children)) {\n errors.push({ path, message: '\"children\" must be an array' })\n } else {\n value.children.forEach((child, index) =>\n checkNode(child, `${path}.children[${index}]`, errors, seen),\n )\n }\n }\n}\n\n/**\n * Checks a tree the way the JSON schema would, without a schema library: required\n * keys, closed key set, value types, and — what a schema cannot say — unique ids.\n * An empty list means the tree is sound.\n */\nexport function validateScreen(root: unknown): ScreenError[] {\n const errors: ScreenError[] = []\n if (!Array.isArray(root)) return [{ path: 'root', message: 'root must be an array of nodes' }]\n const seen = new Set<string>()\n root.forEach((node, index) => checkNode(node, `root[${index}]`, errors, seen))\n return errors\n}\n\n/** Same for a patch: each operation has the keys its `op` calls for. */\nexport function validatePatch(patch: unknown): ScreenError[] {\n const errors: ScreenError[] = []\n if (!Array.isArray(patch)) return [{ path: 'patch', message: 'a patch must be an array' }]\n\n patch.forEach((op, index) => {\n const path = `patch[${index}]`\n if (!isRecord(op)) {\n errors.push({ path, message: 'an operation must be an object' })\n return\n }\n if (typeof op.op !== 'string' || !OPS.has(op.op)) {\n errors.push({ path, message: '\"op\" must be one of add, remove, replace, move, set' })\n return\n }\n if (typeof op.target !== 'string' || op.target === '') {\n errors.push({ path, message: '\"target\" is required: the id of a node' })\n }\n if ((op.op === 'add' || op.op === 'replace') && !isRecord(op.node)) {\n errors.push({ path, message: `\"${op.op}\" needs a \"node\"` })\n } else if (op.op === 'add' || op.op === 'replace') {\n checkNode(op.node, `${path}.node`, errors, new Set())\n }\n if ('position' in op && !isPosition(op.position)) {\n errors.push({ path, message: '\"position\" must be first, last, before:<id> or after:<id>' })\n }\n if (op.op === 'move' && 'to' in op && typeof op.to !== 'string') {\n errors.push({ path, message: '\"to\" must be the id of the new parent' })\n }\n if (op.op === 'set') {\n for (const key of Object.keys(op)) {\n if (key !== 'op' && key !== 'target' && (!NODE_KEYS.has(key) || key === 'id')) {\n errors.push({ path, message: `\"set\" cannot change \"${key}\"` })\n }\n }\n }\n })\n\n return errors\n}\n\nfunction isPosition(value: unknown): boolean {\n return (\n typeof value === 'string' &&\n (value === 'first' ||\n value === 'last' ||\n value.startsWith('before:') ||\n value.startsWith('after:'))\n )\n}\n\nexport type { Patch, ScreenNode }\n","import { defineComponent, h, type InjectionKey, type PropType, type Ref, type VNode } from 'vue'\nimport { WxFormItem } from '@webx-ui/core'\nimport { isVisible } from './visible'\nimport type { ScreenModel, ScreenNode, Translate, TypeRegistry, ValidationErrors } from './types'\n\nexport const TRANS_MARKER = 'trans::'\n\n/** What the recursive renderer needs at every level. */\nexport interface RenderContext {\n types: TypeRegistry\n model: ScreenModel\n update: (name: string, value: unknown) => void\n translate: Translate\n can: (permission: string) => boolean\n}\n\n/**\n * The refusal of the last save, for the nodes that have to act on it rather than only draw it:\n * the tabs, which open the one the failing field is on. Fields draw theirs through `WxForm`.\n */\nexport const screenErrorsKey: InjectionKey<Ref<ValidationErrors | undefined>> =\n Symbol('wx-screen-errors')\n\n/** Whether a node would draw anything at all for this administrator and these values. */\nfunction shown(node: ScreenNode, context: RenderContext): boolean {\n if (node.can && !context.can(node.can)) return false\n return isVisible(node, context.model)\n}\n\n/**\n * The model as the fields draw it: a field with nothing in it — absent or null — shows its\n * `default`. The site reads a missing value the same way, so a switch whose default is on is\n * drawn on rather than contradicting the page. Only what is drawn changes: writes still go to\n * the real model, so an untouched field is not sent and nothing is stored for it.\n *\n * Fields only, through layout and not into a named node — a repeater's children are the fields\n * of its rows, and each row fills its own. Returns the model itself when there is nothing to fill.\n */\nexport function withFieldDefaults(nodes: ScreenNode[], model: ScreenModel): ScreenModel {\n let filled: ScreenModel | undefined\n\n const walk = (list: ScreenNode[]): void => {\n for (const node of list) {\n if (node.name === undefined) {\n walk(node.children ?? [])\n continue\n }\n const value = model[node.name]\n if (node.default !== undefined && (value === undefined || value === null)) {\n filled ??= { ...model }\n filled[node.name] = node.default\n }\n }\n }\n\n walk(nodes)\n return filled ?? model\n}\n\n/** Without a dictionary the key itself shows — honest, and easy to spot in a screenshot. */\nexport const keyAsIs: Translate = (key) => key\n\n/** Translates a marked string; anything else — including `undefined` — passes through. */\nexport function words<T>(value: T, translate: Translate): T {\n if (typeof value === 'string' && value.startsWith(TRANS_MARKER)) {\n return translate(value.slice(TRANS_MARKER.length)) as T\n }\n return value\n}\n\n/** Same, through arrays and objects: `props.options[].label` is the common case. */\nexport function translateDeep<T>(value: T, translate: Translate): T {\n if (typeof value === 'string') return words(value, translate)\n if (Array.isArray(value)) return value.map((item) => translateDeep(item, translate)) as T\n if (value && typeof value === 'object') {\n const out: Record<string, unknown> = {}\n for (const [key, item] of Object.entries(value)) out[key] = translateDeep(item, translate)\n return out as T\n }\n return value\n}\n\nfunction renderUnknown(node: ScreenNode): VNode {\n return h(\n 'div',\n { key: node.id, class: 'wx-screen__unknown', role: 'note' },\n `Unknown type: ${node.type}`,\n )\n}\n\n/** Children grouped by the slot they asked for. */\nfunction childSlots(\n node: ScreenNode,\n defaultSlot: string,\n context: RenderContext,\n): Record<string, () => VNode[]> {\n const groups = new Map<string, ScreenNode[]>()\n for (const child of node.children ?? []) {\n const name = child.slot ?? defaultSlot\n const list = groups.get(name) ?? []\n list.push(child)\n groups.set(name, list)\n }\n const slots: Record<string, () => VNode[]> = {}\n for (const [name, children] of groups) {\n slots[name] = () => renderNodes(children, context)\n }\n return slots\n}\n\nexport function renderNode(node: ScreenNode, context: RenderContext): VNode | null {\n if (!shown(node, context)) return null\n\n const entry = context.types[node.type]\n if (!entry) return renderUnknown(node)\n\n /*\n * A container with nothing in it is not drawn. A screen declares the card the fields of a\n * project go into (`project-fields`) so that a patch knows where to stand, and on every site\n * that patches nothing it was an empty card with a heading — a promise of fields that are not\n * there. Only a container that has children to lose: one described without any is a component\n * that draws itself.\n */\n if (\n entry.kind === 'layout' &&\n node.children !== undefined &&\n !node.children.some((child) => shown(child, context))\n ) {\n return null\n }\n\n const { translate } = context\n const props: Record<string, unknown> = {\n key: node.id,\n ...translateDeep(node.props ?? {}, translate),\n ...entry.bind?.(node),\n }\n const label = words(node.label, translate)\n\n if (entry.kind === 'field') {\n const name = node.name\n // A control that carries its own label takes it, and the form item goes without one.\n const own = entry.labelProp !== undefined && label !== undefined\n const control = h(entry.component, {\n ...props,\n ...(own ? { [entry.labelProp as string]: label } : {}),\n /* A nested field draws the children itself, so it needs the node and the way down. */\n ...(entry.nested ? { node, context } : {}),\n name,\n localized: node.localized || undefined,\n modelValue: name === undefined ? undefined : context.model[name],\n 'onUpdate:modelValue': (value: unknown) => {\n if (name !== undefined) context.update(name, value)\n },\n })\n return h(\n WxFormItem,\n {\n key: node.id,\n name,\n label: own ? undefined : label,\n help: words(node.help, translate),\n wide: entry.wide,\n },\n () => control,\n )\n }\n\n if (entry.kind === 'layout') {\n if (entry.labelProp && label !== undefined) props[entry.labelProp] = label\n return h(entry.component, props, childSlots(node, entry.childrenSlot ?? 'default', context))\n }\n\n // display\n if (entry.labelProp) {\n if (label !== undefined) props[entry.labelProp] = label\n return h(entry.component, props)\n }\n\n // A paragraph is its label, or `props.text` — the way the blocks reference has always written\n // `wx-text`. Handed on as a prop it reached a component without one and drew nothing at all.\n const text = typeof props.text === 'string' ? props.text : undefined\n const body = label ?? text\n\n if (text !== undefined && label === undefined) delete props.text\n\n return h(entry.component, props, body === undefined ? undefined : () => body)\n}\n\nexport function renderNodes(nodes: ScreenNode[], context: RenderContext): VNode[] {\n const out: VNode[] = []\n for (const node of nodes) {\n const rendered = renderNode(node, context)\n if (rendered) out.push(rendered)\n }\n return out\n}\n\n/** A list of nodes as a component, so the tree can recurse through slots. */\nexport const WxScreenNodes = defineComponent({\n name: 'WxScreenNodes',\n props: {\n nodes: { type: Array as PropType<ScreenNode[]>, required: true },\n context: { type: Object as PropType<RenderContext>, required: true },\n },\n setup(props) {\n return () => renderNodes(props.nodes, props.context)\n },\n})\n","<script setup lang=\"ts\">\nimport { computed, inject, useAttrs } from 'vue'\nimport { WxRepeater } from '@webx-ui/core'\nimport { screenErrorsKey, withFieldDefaults, WxScreenNodes, type RenderContext } from './render'\nimport type { ScreenModel, ScreenNode } from './types'\n\ndefineOptions({ name: 'WxScreenRepeater', inheritAttrs: false })\n\n/**\n * The one type with a nested model: the value is a list of records, and the node's\n * children are the fields of one of them. Every child is bound by its own `name` to a key\n * of the item, which is why a repeater is the only place where a name means nesting.\n *\n * Nothing of `WxRepeater`'s own is declared here — `title`, `itemLabel`, `min` and the\n * rest ride in as attributes, so a prop the screen did not set stays unset instead of\n * arriving as `false`.\n */\nconst props = defineProps<{\n /** The node being drawn — its children are one item's fields. */\n node: ScreenNode\n /** The renderer's context; each row gets a copy bound to its own item. */\n context: RenderContext\n /** The renderer hands every field these two. A repeater has no use for either. */\n name?: string\n localized?: boolean\n}>()\n\nconst model = defineModel<ScreenModel[]>({ default: () => [] })\n\nconst items = computed<ScreenModel[]>(() => (Array.isArray(model.value) ? model.value : []))\n\nconst attrs = useAttrs()\n\n/** The names one item's fields answer to — through layout, not into a nested repeater. */\nfunction fieldNames(nodes: ScreenNode[]): string[] {\n return nodes.flatMap((child) =>\n child.name === undefined ? fieldNames(child.children ?? []) : [child.name],\n )\n}\n\nconst refusal = inject(screenErrorsKey, null)\n\n/**\n * The refusal, row by row, under the names the row's fields answer to.\n *\n * The server names a field of a row by its path — `articles.2.url`, and a translated one down to\n * the language, `articles.2.title.en` — while the field inside the row is simply `url` or\n * `title`. Each row gets its own part, the same way the renderer maps `slug.en` onto `slug`,\n * and nothing else: without it a row's `title` shows the record's own `title` error.\n */\nconst rowErrors = computed<Record<string, string[]>[] | undefined>(() => {\n const errors = refusal?.value\n\n if (props.name === undefined) return undefined\n\n const fields = fieldNames(props.node.children ?? [])\n\n return items.value.map((_item, index) => {\n const prefix = `${props.name}.${index}.`\n const out: Record<string, string[]> = {}\n\n for (const [key, messages] of Object.entries(errors ?? {})) {\n if (!key.startsWith(prefix)) continue\n\n const rest = key.slice(prefix.length)\n const field = fields.find((name) => rest.startsWith(`${name}.`))\n\n out[rest] = messages\n if (field !== undefined && out[field] === undefined) out[field] = messages\n }\n\n return out\n })\n})\n\n/**\n * The panel's words, where the core has only English defaults: the core does not know the\n * panel's dictionary, and a translated form with \"Add\" and \"Remove\" in the middle of it is what\n * that looks like. A key the dictionary does not have — a renderer without one — comes back as\n * itself, and then the core's own word is the better answer.\n */\nfunction word(key: string): string | undefined {\n const line = props.context.translate(`webx-admin::screens.repeater.${key}`)\n\n return line.includes('::') ? undefined : line\n}\n\n/**\n * Folded unless the node says otherwise: a list of records opened all at once is a form a\n * kilometre long, and the header of each row already says which one it is. A row added now is\n * the core's business and opens anyway.\n */\nconst bound = computed(() => {\n const defaults: Record<string, unknown> = { collapsed: true }\n\n for (const [prop, key] of [\n ['addLabel', 'add'],\n ['removeLabel', 'remove'],\n ['dragLabel', 'reorder'],\n ['emptyText', 'empty'],\n ] as const) {\n const line = word(key)\n if (line !== undefined) defaults[prop] = line\n }\n\n return { ...defaults, ...attrs }\n})\n</script>\n\n<template>\n <wx-repeater\n v-bind=\"bound\"\n :model-value=\"items\"\n :row-errors=\"rowErrors\"\n @update:model-value=\"model = $event\"\n >\n <template #default=\"{ item, update }\">\n <wx-screen-nodes\n :nodes=\"node.children ?? []\"\n :context=\"{\n ...context,\n model: withFieldDefaults(node.children ?? [], item),\n update: (key: string, value: unknown) => update({ [key]: value }),\n }\"\n />\n </template>\n </wx-repeater>\n</template>\n","<script setup lang=\"ts\">\nimport { computed, inject, ref, watch } from 'vue'\nimport { WxTabs, type TabValue } from '@webx-ui/core'\nimport { screenErrorsKey } from './render'\n\n/**\n * The tabs of a described screen: `WxTabs`, and the one thing a form of tabs needs that a strip\n * of tabs does not — a refused save opens the tab the refusal is on.\n *\n * Without it a 422 can land on a tab nobody is looking at: the message is drawn under a field\n * that is not on screen, and the form looks as if it refused for no reason. A page hosting a\n * screen cannot do this itself, because the tabs are the description's and the page never sees\n * which field sits on which of them; the registry does, and hands the answer in as `fields`.\n *\n * The tab being looked at wins when it has a failing field of its own: the editor is already\n * where the problem is, and moving them would be moving them away from it.\n */\ndefineOptions({ name: 'WxScreenTabs', inheritAttrs: false })\n\nconst props = withDefaults(\n defineProps<{\n /** The names of the fields under each tab, in the order the tabs are read. */\n fields?: Record<string, string[]>\n }>(),\n { fields: () => ({}) },\n)\n\nconst errors = inject(screenErrorsKey, null)\n\nconst active = ref<TabValue | undefined>(undefined)\n\n/** The tabs holding a failing field, in the order they are read. The renderer has already put\n `slug.en` under `slug`, so a name is looked up as it is. */\nconst failing = computed<string[]>(() => {\n const names = new Set(Object.keys(errors?.value ?? {}))\n\n return Object.entries(props.fields)\n .filter(([, fields]) => fields.some((field) => names.has(field)))\n .map(([tab]) => tab)\n})\n\nwatch(failing, (tabs) => {\n const first = tabs[0]\n\n if (first === undefined) return\n if (active.value !== undefined && tabs.includes(String(active.value))) return\n\n active.value = first\n})\n</script>\n\n<template>\n <wx-tabs v-model=\"active\" v-bind=\"$attrs\">\n <slot />\n </wx-tabs>\n</template>\n","import {\n WxAlert,\n WxAutocomplete,\n WxCard,\n WxCascader,\n WxCheckbox,\n WxCheckboxGroup,\n WxCodeEditor,\n WxCol,\n WxColorPicker,\n WxDatePicker,\n WxDateRangePicker,\n WxDateTimePicker,\n WxDivider,\n WxHeading,\n WxIconPicker,\n WxInput,\n WxInputNumber,\n WxRadioGroup,\n WxRate,\n WxRow,\n WxSegmented,\n WxSelect,\n WxSlider,\n WxSwitch,\n WxTab,\n WxTagsInput,\n WxText,\n WxTextarea,\n WxTimePicker,\n WxTransfer,\n WxTreeSelect,\n} from '@webx-ui/core'\nimport ScreenRepeater from './ScreenRepeater.vue'\nimport ScreenTabs from './ScreenTabs.vue'\nimport type { NodeKind, ScreenNode, TypeEntry, TypeRegistry } from './types'\n\n/** Every field name under a node, however deep — what a tab has to open for. */\nfunction fieldNames(node: ScreenNode): string[] {\n return (node.children ?? []).flatMap((child) =>\n child.name === undefined ? fieldNames(child) : [child.name],\n )\n}\n\n/**\n * The types every panel has: the core's layout, form and display components under\n * their full names. A module or a project adds its own the same way — `wx-media` comes\n * from `module-media`, `map` from whoever has a map.\n */\nexport const coreTypes: TypeRegistry = {\n 'wx-tabs': {\n component: ScreenTabs,\n kind: 'layout',\n // Which fields each tab holds, so a refused save can open the tab it was refused on.\n bind: (node) => ({\n fields: Object.fromEntries((node.children ?? []).map((tab) => [tab.id, fieldNames(tab)])),\n }),\n },\n 'wx-tab': {\n component: WxTab,\n kind: 'layout',\n labelProp: 'label',\n // A tab is selected by value, and the node's id is the one stable thing it has.\n bind: (node) => ({ value: node.id }),\n },\n 'wx-card': { component: WxCard, kind: 'layout', labelProp: 'title' },\n 'wx-row': {\n component: WxRow,\n kind: 'layout',\n // Marked so the renderer can hold a row at the width of one field (see `ScreenRenderer.vue`).\n bind: (node) => ({ class: ['wx-screen__row', node.props?.class] }),\n },\n 'wx-col': {\n component: WxCol,\n kind: 'layout',\n // Marked so the renderer can stack what a column holds (see `ScreenRenderer.vue`),\n // without touching a `WxCol` that some field happens to use inside itself.\n bind: (node) => ({ class: ['wx-screen__col', node.props?.class] }),\n },\n 'wx-divider': { component: WxDivider, kind: 'layout', labelProp: 'label' },\n\n 'wx-input': { component: WxInput, kind: 'field' },\n 'wx-textarea': { component: WxTextarea, kind: 'field' },\n 'wx-input-number': { component: WxInputNumber, kind: 'field' },\n 'wx-select': { component: WxSelect, kind: 'field' },\n // The label beside the control rather than above it: on, off, and what is being turned.\n 'wx-switch': { component: WxSwitch, kind: 'field', labelProp: 'label' },\n 'wx-checkbox': { component: WxCheckbox, kind: 'field', labelProp: 'label' },\n 'wx-radio-group': { component: WxRadioGroup, kind: 'field' },\n 'wx-date-picker': { component: WxDatePicker, kind: 'field' },\n 'wx-color-picker': { component: WxColorPicker, kind: 'field' },\n 'wx-checkbox-group': { component: WxCheckboxGroup, kind: 'field' },\n 'wx-segmented': { component: WxSegmented, kind: 'field' },\n 'wx-slider': { component: WxSlider, kind: 'field' },\n 'wx-rate': { component: WxRate, kind: 'field' },\n 'wx-time-picker': { component: WxTimePicker, kind: 'field' },\n 'wx-date-time-picker': {\n component: WxDateTimePicker,\n kind: 'field',\n // A moment, not a wall clock. Without the offset the server reads the hour in its own\n // timezone and the browser in the reader's, and one value shows two different times. Bound\n // over `props` on purpose: the server parses exactly this shape.\n bind: () => ({ valueFormat: \"yyyy-MM-dd'T'HH:mm:ssXXX\" }),\n },\n 'wx-date-range-picker': { component: WxDateRangePicker, kind: 'field' },\n 'wx-tags-input': { component: WxTagsInput, kind: 'field' },\n 'wx-autocomplete': { component: WxAutocomplete, kind: 'field' },\n 'wx-icon-picker': { component: WxIconPicker, kind: 'field' },\n 'wx-cascader': { component: WxCascader, kind: 'field' },\n 'wx-tree-select': { component: WxTreeSelect, kind: 'field' },\n // Wide: two lists with the buttons between them do not fit in half a form.\n 'wx-transfer': { component: WxTransfer, kind: 'field', wide: true },\n // Wide for the reason an editor is: code is read in long lines.\n 'wx-code-editor': { component: WxCodeEditor, kind: 'field', wide: true },\n 'wx-repeater': { component: ScreenRepeater, kind: 'field', nested: true, wide: true },\n\n 'wx-heading': { component: WxHeading, kind: 'display' },\n 'wx-text': { component: WxText, kind: 'display' },\n 'wx-alert': { component: WxAlert, kind: 'display', labelProp: 'title' },\n}\n\n/** Identity with a type: keeps a project's registry object checked without an import of the type. */\nexport function defineTypes<T extends TypeRegistry>(types: T): T {\n return types\n}\n\nexport interface TypeDescription {\n type: string\n kind: NodeKind\n component: string\n /** Where the node's `label` ends up, in words. */\n label: string\n}\n\nfunction componentName(entry: TypeEntry): string {\n const component = entry.component as { name?: string; __name?: string }\n return component.name ?? component.__name ?? 'anonymous'\n}\n\nfunction labelDestination(entry: TypeEntry): string {\n if (entry.kind === 'field') return 'form item'\n if (entry.labelProp) return `prop \\`${entry.labelProp}\\``\n return entry.kind === 'display' ? 'default slot' : '—'\n}\n\n/** One row per type, in registry order — what the documentation table is made of. */\nexport function describeTypes(types: TypeRegistry): TypeDescription[] {\n return Object.entries(types).map(([type, entry]) => ({\n type,\n kind: entry.kind,\n component: componentName(entry),\n label: labelDestination(entry),\n }))\n}\n\n/**\n * The registry as a Markdown table, padded the way Prettier pads one, so the generated\n * block in the guide survives `prettier --check` and a test can compare it verbatim.\n */\nexport function typesTable(types: TypeRegistry): string {\n const rows = describeTypes(types).map((row) => [\n `\\`${row.type}\\``,\n row.kind,\n `\\`${row.component}\\``,\n row.label,\n ])\n const header = ['Type', 'Kind', 'Component', '`label` goes to']\n const widths = header.map((cell, column) =>\n Math.max(cell.length, ...rows.map((row) => row[column]!.length)),\n )\n const line = (cells: string[]) =>\n `| ${cells.map((cell, column) => cell.padEnd(widths[column]!)).join(' | ')} |`\n return [line(header), line(widths.map((width) => '-'.repeat(width))), ...rows.map(line)].join(\n '\\n',\n )\n}\n","<script setup lang=\"ts\">\nimport { computed, markRaw, provide, toRaw, watch } from 'vue'\nimport { WxForm } from '@webx-ui/core'\nimport { applyPatch } from './patch'\nimport { coreTypes } from './registry'\nimport {\n keyAsIs,\n screenErrorsKey,\n withFieldDefaults,\n WxScreenNodes,\n type RenderContext,\n} from './render'\nimport type {\n Patch,\n PatchError,\n ScreenModel,\n ScreenNode,\n Translate,\n TypeRegistry,\n ValidationErrors,\n} from './types'\n\ndefineOptions({ name: 'WxScreenRenderer' })\n\nconst props = withDefaults(\n defineProps<{\n /** The tree to draw — a module's screen, already patched by the server. */\n root: ScreenNode[]\n /** Client-side patch applied on top, in order. */\n patch?: Patch\n /** Server-side validation errors, keyed by field name; shown under the fields. */\n errors?: ValidationErrors\n /** Project types, merged over the core ones. */\n types?: TypeRegistry\n /** Turns `trans::` strings into words. Without it the key shows. */\n translate?: Translate\n /** Decides `can`. Without it every node is allowed. */\n can?: (permission: string) => boolean\n disabled?: boolean\n labelPosition?: 'top' | 'left'\n labelWidth?: string\n size?: 'sm' | 'md' | 'lg'\n }>(),\n {\n patch: () => [],\n errors: undefined,\n types: undefined,\n translate: undefined,\n can: undefined,\n disabled: false,\n labelPosition: undefined,\n labelWidth: undefined,\n size: undefined,\n },\n)\n\nconst emit = defineEmits<{\n /** Operations that could not be applied. Also reported to the console. */\n patchError: [errors: PatchError[]]\n}>()\n\nconst model = defineModel<ScreenModel>({ default: () => ({}) })\n\nconst applied = computed(() => applyPatch(props.root, props.patch))\n\n/** Every field name on the screen, however deep — a repeater is one field, not its items. */\nfunction names(nodes: ScreenNode[]): string[] {\n return nodes.flatMap((node) =>\n node.name === undefined ? names(node.children ?? []) : [node.name],\n )\n}\n\n/**\n * The refusal, under the names the fields answer to.\n *\n * Laravel names the language that failed — `slug.en` — and `WxFormItem` looks its error up by\n * the field's own name, so a refused translated field showed nothing at all: the save failed and\n * every field looked fine. A key is matched against the field names rather than cut at its first\n * dot, because a name may carry a dot of its own (`general.project-name`, CLAUDE.md §4).\n */\nconst failing = computed<ValidationErrors | undefined>(() => {\n if (props.errors === undefined) return undefined\n\n const fields = names(applied.value.root)\n const out: ValidationErrors = { ...props.errors }\n\n for (const [key, messages] of Object.entries(props.errors)) {\n const field = fields.find((name) => key.startsWith(`${name}.`))\n\n if (field !== undefined && out[field] === undefined) out[field] = messages\n }\n\n return out\n})\n\n/**\n * What the form draws: the same, less a row's refusal put under the repeater's own name.\n *\n * `duties.1.text.ru` is a field of the second row, and the row draws it there (`ScreenRepeater`);\n * under the repeater as a whole it read as a second, different refusal of the list itself. The\n * tabs still need it under `duties`, since that is the name they know the field by.\n */\nconst fieldErrors = computed<ValidationErrors | undefined>(() => {\n if (props.errors === undefined || failing.value === undefined) return undefined\n\n const out: ValidationErrors = { ...failing.value }\n\n for (const name of Object.keys(out)) {\n if (props.errors[name] !== undefined) continue\n\n const rows = Object.keys(props.errors).filter((key) => key.startsWith(`${name}.`))\n\n if (rows.length > 0 && rows.every((key) => /^\\d+\\./.test(key.slice(name.length + 1)))) {\n delete out[name]\n }\n }\n\n return out\n})\n\n// For the nodes that act on a refusal rather than only draw it — the tabs (`ScreenTabs.vue`)\n// and the rows of a repeater.\nprovide(screenErrorsKey, failing)\n\nwatch(\n () => applied.value.errors,\n (errors) => {\n for (const error of errors) {\n console.error(`[webx-ui/schema] patch[${error.index}] ${error.op.op}: ${error.message}`)\n }\n emit('patchError', errors)\n },\n { immediate: true },\n)\n\n/**\n * A registry kept in a `ref` arrives as a reactive proxy, and Vue warns about a\n * component that is one; the raw component is what `h()` wants anyway.\n */\nconst registry = computed<TypeRegistry>(() => {\n const merged: TypeRegistry = {}\n for (const [type, entry] of Object.entries({ ...coreTypes, ...props.types })) {\n merged[type] = { ...entry, component: markRaw(toRaw(entry.component)) }\n }\n return merged\n})\n\nconst context = computed<RenderContext>(() => ({\n types: registry.value,\n // Drawn with the defaults filled in; `update` below writes to the model as it is.\n model: withFieldDefaults(applied.value.root, model.value),\n update: (name, value) => {\n model.value = { ...model.value, [name]: value }\n },\n translate: props.translate ?? keyAsIs,\n can: props.can ?? (() => true),\n}))\n\ndefineExpose({\n /** The tree after the patch — what is actually on screen. */\n tree: computed(() => applied.value.root),\n})\n</script>\n\n<template>\n <wx-form\n class=\"wx-screen\"\n :errors=\"fieldErrors\"\n :disabled=\"disabled\"\n :label-position=\"labelPosition\"\n :label-width=\"labelWidth\"\n :size=\"size\"\n >\n <wx-screen-nodes :nodes=\"applied.root\" :context=\"context\" />\n </wx-form>\n</template>\n\n<style>\n/*\n * A column is a stack of fields, like a card's body. The form's own gap reaches only its\n * direct children, so two fields dropped into one `wx-col` stood flush: the label of the\n * second read as the hint of the first. Same step as the form and the card.\n */\n.wx-screen__col {\n display: flex;\n flex-direction: column;\n gap: var(--wx-gap, var(--wx-space-16));\n}\n\n/*\n * A row splits one field's width between two, it does not spread them across the card. Every\n * field stops at `--wx-field-max-width`, so a row as wide as the card put \"Start\" at the left\n * edge and \"End\" a thousand pixels away — two fields that belong together read as unrelated,\n * and each still left most of its column empty.\n *\n * Plus the gutter the row pulls back with its negative margins, so its outer edges line up with\n * the fields above and below. The columns answer to the row's width, so a pair of halves is\n * `sm: 12` — `md` needs 768px of room and a row this size never has it.\n */\n.wx-screen__row {\n max-width: calc(var(--wx-field-max-width, 640px) + var(--wx-row-gutter, 0px));\n}\n\n/* Global on purpose: the placeholder is created by a render function, outside any scope. */\n.wx-screen__unknown {\n padding: var(--wx-space-8) var(--wx-space-12);\n border: 1px dashed var(--wx-color-danger);\n border-radius: var(--wx-radius-control);\n background: var(--wx-color-danger-soft);\n color: var(--wx-color-danger);\n font-family: var(--wx-font-family-mono);\n font-size: var(--wx-font-size-sm);\n}\n</style>\n"],"names":["locate","root","id","index","node","found","findNode","collectIds","ids","walk","nodes","indexFor","list","position","where","anchor","at","clone","value","out","key","item","applyPatch","patch","tree","errors","op","message","apply","clash","duplicateIn","others","parent","contains","ancestor","child","incoming","except","existing","same","a","b","evaluateCondition","condition","model","isVisible","visible","NODE_KEYS","OPS","isRecord","checkCondition","path","forms","checkNode","seen","validateScreen","validatePatch","isPosition","TRANS_MARKER","screenErrorsKey","shown","context","withFieldDefaults","filled","keyAsIs","words","translate","translateDeep","renderUnknown","h","childSlots","defaultSlot","groups","name","slots","children","renderNodes","renderNode","entry","props","label","own","control","WxFormItem","text","body","rendered","WxScreenNodes","defineComponent","__props","_useModel","items","computed","attrs","useAttrs","fieldNames","refusal","inject","rowErrors","fields","_item","prefix","messages","rest","field","word","line","bound","defaults","prop","_createBlock","_unref","WxRepeater","_mergeProps","_cache","$event","_withCtx","update","_createVNode","active","ref","failing","names","tab","watch","tabs","first","_openBlock","$attrs","_renderSlot","_ctx","coreTypes","ScreenTabs","WxTab","WxCard","WxRow","WxCol","WxDivider","WxInput","WxTextarea","WxInputNumber","WxSelect","WxSwitch","WxCheckbox","WxRadioGroup","WxDatePicker","WxColorPicker","WxCheckboxGroup","WxSegmented","WxSlider","WxRate","WxTimePicker","WxDateTimePicker","WxDateRangePicker","WxTagsInput","WxAutocomplete","WxIconPicker","WxCascader","WxTreeSelect","WxTransfer","WxCodeEditor","ScreenRepeater","WxHeading","WxText","WxAlert","defineTypes","types","componentName","component","labelDestination","describeTypes","type","typesTable","rows","row","header","widths","cell","column","cells","width","emit","__emit","applied","fieldErrors","provide","error","registry","merged","markRaw","toRaw","__expose","WxForm"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sources":["../src/patch.ts","../src/visible.ts","../src/validate.ts","../src/render.ts","../src/ScreenRepeater.vue","../src/ScreenTabs.vue","../src/registry.ts","../src/ScreenRenderer.vue"],"sourcesContent":["import type { Patch, PatchError, PatchOperation, PatchPosition, ScreenNode } from './types'\n\ninterface Located {\n /** The array the node sits in: the root, or a parent's `children`. */\n list: ScreenNode[]\n index: number\n node: ScreenNode\n}\n\n/** Depth-first search by `id`, remembering the array the match lives in. */\nexport function locate(root: ScreenNode[], id: string): Located | null {\n for (let index = 0; index < root.length; index += 1) {\n const node = root[index]!\n if (node.id === id) return { list: root, index, node }\n if (node.children) {\n const found = locate(node.children, id)\n if (found) return found\n }\n }\n return null\n}\n\nexport function findNode(root: ScreenNode[], id: string): ScreenNode | null {\n return locate(root, id)?.node ?? null\n}\n\n/** Every `id` in the tree, in document order. Duplicates are kept, so callers can spot them. */\nexport function collectIds(root: ScreenNode[]): string[] {\n const ids: string[] = []\n const walk = (nodes: ScreenNode[]) => {\n for (const node of nodes) {\n ids.push(node.id)\n if (node.children) walk(node.children)\n }\n }\n walk(root)\n return ids\n}\n\n/** Index a node should be inserted at in `list`, or a message when the anchor is missing. */\nfunction indexFor(list: ScreenNode[], position: PatchPosition | undefined): number | string {\n if (!position || position === 'last') return list.length\n if (position === 'first') return 0\n const [where, anchor] = position.split(':', 2) as ['before' | 'after', string]\n const at = list.findIndex((node) => node.id === anchor)\n if (at === -1) return `no sibling \"${anchor}\" to insert ${where}`\n return where === 'before' ? at : at + 1\n}\n\n/**\n * Deep copy of a JSON value. `structuredClone` refuses a Vue reactive proxy, and a\n * tree that came out of a `ref` is exactly that; reading through the proxy is fine.\n */\nexport function clone<T>(value: T): T {\n if (Array.isArray(value)) return value.map(clone) as T\n if (value && typeof value === 'object') {\n const out: Record<string, unknown> = {}\n for (const [key, item] of Object.entries(value)) out[key] = clone(item)\n return out as T\n }\n return value\n}\n\n/**\n * Applies a patch to a tree and returns the result as a new tree; the input is not\n * touched. An operation that cannot be applied — a `target` that does not exist, an\n * anchor that is missing — is skipped and reported, and the ones after it still run:\n * a project patch that survived a rename in the module must not silence the rest.\n */\nexport function applyPatch(\n root: ScreenNode[],\n patch: Patch,\n): { root: ScreenNode[]; errors: PatchError[] } {\n const tree = clone(root)\n const errors: PatchError[] = []\n\n patch.forEach((op, index) => {\n const message = apply(tree, op)\n if (message) errors.push({ index, op, message })\n })\n\n return { root: tree, errors }\n}\n\n/** Mutates `tree`; returns a message when the operation was refused. */\nfunction apply(tree: ScreenNode[], op: PatchOperation): string | null {\n const found = locate(tree, op.target)\n if (!found) return `target \"${op.target}\" not found`\n\n switch (op.op) {\n case 'add': {\n const clash = duplicateIn(tree, op.node)\n if (clash) return `id \"${clash}\" already exists in the screen`\n const list = (found.node.children ??= [])\n const at = indexFor(list, op.position)\n if (typeof at === 'string') return at\n list.splice(at, 0, clone(op.node))\n return null\n }\n case 'remove':\n found.list.splice(found.index, 1)\n return null\n case 'replace': {\n // The replaced node's own ids are gone, so only the rest of the tree can clash.\n const others = tree.filter((node) => node !== found.node)\n const clash = duplicateIn(others, op.node, found.node)\n if (clash) return `id \"${clash}\" already exists in the screen`\n found.list.splice(found.index, 1, clone(op.node))\n return null\n }\n case 'move': {\n let list = found.list\n if (op.to !== undefined) {\n const parent = locate(tree, op.to)\n if (!parent) return `destination \"${op.to}\" not found`\n if (parent.node === found.node || contains(found.node, parent.node)) {\n return `cannot move \"${op.target}\" into itself`\n }\n list = parent.node.children ??= []\n }\n found.list.splice(found.index, 1)\n const at = indexFor(list, op.position)\n if (typeof at === 'string') {\n // Put it back where it was: a refused move leaves the tree untouched.\n found.list.splice(found.index, 0, found.node)\n return at\n }\n list.splice(at, 0, found.node)\n return null\n }\n case 'set': {\n for (const [key, value] of Object.entries(op)) {\n if (key === 'op' || key === 'target') continue\n if (key === 'props') {\n found.node.props = { ...found.node.props, ...(value as Record<string, unknown>) }\n } else {\n ;(found.node as unknown as Record<string, unknown>)[key] = clone(value)\n }\n }\n return null\n }\n }\n}\n\nfunction contains(ancestor: ScreenNode, node: ScreenNode): boolean {\n return (ancestor.children ?? []).some((child) => child === node || contains(child, node))\n}\n\n/** First id of `incoming` that already exists in `tree`, ignoring `except`'s own subtree. */\nfunction duplicateIn(tree: ScreenNode[], incoming: ScreenNode, except?: ScreenNode): string | null {\n const existing = new Set(collectIds(tree))\n if (except) for (const id of collectIds([except])) existing.delete(id)\n return collectIds([incoming]).find((id) => existing.has(id)) ?? null\n}\n","import type { ScreenModel, ScreenNode, VisibilityCondition } from './types'\n\n/** Loose enough for `{ \"is\": 1 }` to match a numeric input, strict enough for `\"1\"` not to. */\nfunction same(a: unknown, b: unknown): boolean {\n if (a === b) return true\n if (a === null || b === null || typeof a !== 'object' || typeof b !== 'object') return false\n return JSON.stringify(a) === JSON.stringify(b)\n}\n\nexport function evaluateCondition(condition: VisibilityCondition, model: ScreenModel): boolean {\n if ('all' in condition) return condition.all.every((item) => evaluateCondition(item, model))\n if ('any' in condition) return condition.any.some((item) => evaluateCondition(item, model))\n\n const value = model[condition.when]\n if ('in' in condition) return condition.in.some((item) => same(item, value))\n if ('not' in condition) return !same(condition.not, value)\n return same(condition.is, value)\n}\n\n/** Whether a node should render, given the current model. Absent `visible` means yes. */\nexport function isVisible(node: ScreenNode, model: ScreenModel): boolean {\n const { visible } = node\n if (visible === undefined || visible === true) return true\n if (visible === false) return false\n return evaluateCondition(visible, model)\n}\n","import type { Patch, ScreenError, ScreenNode, VisibilityCondition } from './types'\n\nconst NODE_KEYS = new Set([\n 'id',\n 'type',\n 'name',\n 'label',\n 'help',\n 'localized',\n 'default',\n 'props',\n 'children',\n 'slot',\n 'visible',\n 'can',\n])\n\nconst OPS = new Set(['add', 'remove', 'replace', 'move', 'set'])\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value)\n}\n\nfunction checkCondition(value: unknown, path: string, errors: ScreenError[]): void {\n if (!isRecord(value)) {\n errors.push({ path, message: 'visible must be a boolean or a condition object' })\n return\n }\n if ('all' in value || 'any' in value) {\n const list = (value.all ?? value.any) as unknown\n if (!Array.isArray(list)) {\n errors.push({ path, message: '\"all\" / \"any\" must be an array of conditions' })\n return\n }\n list.forEach((item, index) => checkCondition(item, `${path}[${index}]`, errors))\n return\n }\n if (typeof value.when !== 'string') {\n errors.push({ path, message: 'a condition needs \"when\": the name of a field' })\n return\n }\n const forms = ['is', 'in', 'not'].filter((key) => key in value)\n if (forms.length !== 1) {\n errors.push({ path, message: 'a condition needs exactly one of \"is\", \"in\", \"not\"' })\n } else if (forms[0] === 'in' && !Array.isArray(value.in)) {\n errors.push({ path, message: '\"in\" must be an array' })\n }\n}\n\nfunction checkNode(value: unknown, path: string, errors: ScreenError[], seen: Set<string>): void {\n if (!isRecord(value)) {\n errors.push({ path, message: 'a node must be an object' })\n return\n }\n\n for (const key of Object.keys(value)) {\n if (!NODE_KEYS.has(key)) errors.push({ path, message: `unknown key \"${key}\"` })\n }\n\n if (typeof value.id !== 'string' || value.id === '') {\n errors.push({ path, message: '\"id\" is required and must be a non-empty string' })\n } else if (seen.has(value.id)) {\n errors.push({ path, message: `duplicate id \"${value.id}\"` })\n } else {\n seen.add(value.id)\n }\n\n if (typeof value.type !== 'string' || value.type === '') {\n errors.push({ path, message: '\"type\" is required and must be a non-empty string' })\n }\n\n for (const key of ['name', 'label', 'help'] as const) {\n if (key in value && typeof value[key] !== 'string') {\n errors.push({ path, message: `\"${key}\" must be a string` })\n }\n }\n if ('localized' in value && typeof value.localized !== 'boolean') {\n errors.push({ path, message: '\"localized\" must be a boolean' })\n }\n if ('props' in value && !isRecord(value.props)) {\n errors.push({ path, message: '\"props\" must be an object' })\n }\n if ('slot' in value && value.slot !== null && typeof value.slot !== 'string') {\n errors.push({ path, message: '\"slot\" must be a string or null' })\n }\n if ('can' in value && value.can !== null && typeof value.can !== 'string') {\n errors.push({ path, message: '\"can\" must be a string or null' })\n }\n if ('visible' in value && typeof value.visible !== 'boolean') {\n checkCondition(value.visible as VisibilityCondition, `${path}.visible`, errors)\n }\n\n if ('children' in value) {\n if (!Array.isArray(value.children)) {\n errors.push({ path, message: '\"children\" must be an array' })\n } else {\n value.children.forEach((child, index) =>\n checkNode(child, `${path}.children[${index}]`, errors, seen),\n )\n }\n }\n}\n\n/**\n * Checks a tree the way the JSON schema would, without a schema library: required\n * keys, closed key set, value types, and — what a schema cannot say — unique ids.\n * An empty list means the tree is sound.\n */\nexport function validateScreen(root: unknown): ScreenError[] {\n const errors: ScreenError[] = []\n if (!Array.isArray(root)) return [{ path: 'root', message: 'root must be an array of nodes' }]\n const seen = new Set<string>()\n root.forEach((node, index) => checkNode(node, `root[${index}]`, errors, seen))\n return errors\n}\n\n/** Same for a patch: each operation has the keys its `op` calls for. */\nexport function validatePatch(patch: unknown): ScreenError[] {\n const errors: ScreenError[] = []\n if (!Array.isArray(patch)) return [{ path: 'patch', message: 'a patch must be an array' }]\n\n patch.forEach((op, index) => {\n const path = `patch[${index}]`\n if (!isRecord(op)) {\n errors.push({ path, message: 'an operation must be an object' })\n return\n }\n if (typeof op.op !== 'string' || !OPS.has(op.op)) {\n errors.push({ path, message: '\"op\" must be one of add, remove, replace, move, set' })\n return\n }\n if (typeof op.target !== 'string' || op.target === '') {\n errors.push({ path, message: '\"target\" is required: the id of a node' })\n }\n if ((op.op === 'add' || op.op === 'replace') && !isRecord(op.node)) {\n errors.push({ path, message: `\"${op.op}\" needs a \"node\"` })\n } else if (op.op === 'add' || op.op === 'replace') {\n checkNode(op.node, `${path}.node`, errors, new Set())\n }\n if ('position' in op && !isPosition(op.position)) {\n errors.push({ path, message: '\"position\" must be first, last, before:<id> or after:<id>' })\n }\n if (op.op === 'move' && 'to' in op && typeof op.to !== 'string') {\n errors.push({ path, message: '\"to\" must be the id of the new parent' })\n }\n if (op.op === 'set') {\n for (const key of Object.keys(op)) {\n if (key !== 'op' && key !== 'target' && (!NODE_KEYS.has(key) || key === 'id')) {\n errors.push({ path, message: `\"set\" cannot change \"${key}\"` })\n }\n }\n }\n })\n\n return errors\n}\n\nfunction isPosition(value: unknown): boolean {\n return (\n typeof value === 'string' &&\n (value === 'first' ||\n value === 'last' ||\n value.startsWith('before:') ||\n value.startsWith('after:'))\n )\n}\n\nexport type { Patch, ScreenNode }\n","import { defineComponent, h, type InjectionKey, type PropType, type Ref, type VNode } from 'vue'\nimport { WxFormItem } from '@webx-ui/core'\nimport { isVisible } from './visible'\nimport type { ScreenModel, ScreenNode, Translate, TypeRegistry, ValidationErrors } from './types'\n\nexport const TRANS_MARKER = 'trans::'\n\n/** What the recursive renderer needs at every level. */\nexport interface RenderContext {\n types: TypeRegistry\n model: ScreenModel\n update: (name: string, value: unknown) => void\n translate: Translate\n can: (permission: string) => boolean\n}\n\n/**\n * The refusal of the last save, for the nodes that have to act on it rather than only draw it:\n * the tabs, which open the one the failing field is on. Fields draw theirs through `WxForm`.\n */\nexport const screenErrorsKey: InjectionKey<Ref<ValidationErrors | undefined>> =\n Symbol('wx-screen-errors')\n\n/** Whether a node would draw anything at all for this administrator and these values. */\nfunction shown(node: ScreenNode, context: RenderContext): boolean {\n if (node.can && !context.can(node.can)) return false\n return isVisible(node, context.model)\n}\n\n/**\n * The model as the fields draw it: a field with nothing in it — absent or null — shows its\n * `default`. The site reads a missing value the same way, so a switch whose default is on is\n * drawn on rather than contradicting the page. Only what is drawn changes: writes still go to\n * the real model, so an untouched field is not sent and nothing is stored for it.\n *\n * Fields only, through layout and not into a named node — a repeater's children are the fields\n * of its rows, and each row fills its own. Returns the model itself when there is nothing to fill.\n */\nexport function withFieldDefaults(nodes: ScreenNode[], model: ScreenModel): ScreenModel {\n let filled: ScreenModel | undefined\n\n const walk = (list: ScreenNode[]): void => {\n for (const node of list) {\n if (node.name === undefined) {\n walk(node.children ?? [])\n continue\n }\n const value = model[node.name]\n if (node.default !== undefined && (value === undefined || value === null)) {\n filled ??= { ...model }\n filled[node.name] = node.default\n }\n }\n }\n\n walk(nodes)\n return filled ?? model\n}\n\n/** Without a dictionary the key itself shows — honest, and easy to spot in a screenshot. */\nexport const keyAsIs: Translate = (key) => key\n\n/** Translates a marked string; anything else — including `undefined` — passes through. */\nexport function words<T>(value: T, translate: Translate): T {\n if (typeof value === 'string' && value.startsWith(TRANS_MARKER)) {\n return translate(value.slice(TRANS_MARKER.length)) as T\n }\n return value\n}\n\n/** Same, through arrays and objects: `props.options[].label` is the common case. */\nexport function translateDeep<T>(value: T, translate: Translate): T {\n if (typeof value === 'string') return words(value, translate)\n if (Array.isArray(value)) return value.map((item) => translateDeep(item, translate)) as T\n if (value && typeof value === 'object') {\n const out: Record<string, unknown> = {}\n for (const [key, item] of Object.entries(value)) out[key] = translateDeep(item, translate)\n return out as T\n }\n return value\n}\n\nfunction renderUnknown(node: ScreenNode): VNode {\n return h(\n 'div',\n { key: node.id, class: 'wx-screen__unknown', role: 'note' },\n `Unknown type: ${node.type}`,\n )\n}\n\n/** Children grouped by the slot they asked for. */\nfunction childSlots(\n node: ScreenNode,\n defaultSlot: string,\n context: RenderContext,\n): Record<string, () => VNode[]> {\n const groups = new Map<string, ScreenNode[]>()\n for (const child of node.children ?? []) {\n const name = child.slot ?? defaultSlot\n const list = groups.get(name) ?? []\n list.push(child)\n groups.set(name, list)\n }\n const slots: Record<string, () => VNode[]> = {}\n for (const [name, children] of groups) {\n slots[name] = () => renderNodes(children, context)\n }\n return slots\n}\n\nexport function renderNode(node: ScreenNode, context: RenderContext): VNode | null {\n if (!shown(node, context)) return null\n\n const entry = context.types[node.type]\n if (!entry) return renderUnknown(node)\n\n /*\n * A container with nothing in it is not drawn. A screen declares the card the fields of a\n * project go into (`project-fields`) so that a patch knows where to stand, and on every site\n * that patches nothing it was an empty card with a heading — a promise of fields that are not\n * there. Only a container that has children to lose: one described without any is a component\n * that draws itself.\n */\n if (\n entry.kind === 'layout' &&\n node.children !== undefined &&\n !node.children.some((child) => shown(child, context))\n ) {\n return null\n }\n\n const { translate } = context\n const props: Record<string, unknown> = {\n key: node.id,\n ...translateDeep(node.props ?? {}, translate),\n ...entry.bind?.(node),\n }\n const label = words(node.label, translate)\n\n if (entry.kind === 'field') {\n const name = node.name\n // A control that carries its own label takes it, and the form item goes without one.\n const own = entry.labelProp !== undefined && label !== undefined\n const control = h(entry.component, {\n ...props,\n ...(own ? { [entry.labelProp as string]: label } : {}),\n /* A nested field draws the children itself, so it needs the node and the way down. */\n ...(entry.nested ? { node, context } : {}),\n name,\n localized: node.localized || undefined,\n modelValue: name === undefined ? undefined : context.model[name],\n 'onUpdate:modelValue': (value: unknown) => {\n if (name !== undefined) context.update(name, value)\n },\n })\n return h(\n WxFormItem,\n {\n key: node.id,\n name,\n label: own ? undefined : label,\n help: words(node.help, translate),\n wide: typeof entry.wide === 'function' ? entry.wide(node) : entry.wide,\n },\n () => control,\n )\n }\n\n if (entry.kind === 'layout') {\n if (entry.labelProp && label !== undefined) props[entry.labelProp] = label\n return h(entry.component, props, childSlots(node, entry.childrenSlot ?? 'default', context))\n }\n\n // display\n if (entry.labelProp) {\n if (label !== undefined) props[entry.labelProp] = label\n return h(entry.component, props)\n }\n\n // A paragraph is its label, or `props.text` — the way the blocks reference has always written\n // `wx-text`. Handed on as a prop it reached a component without one and drew nothing at all.\n const text = typeof props.text === 'string' ? props.text : undefined\n const body = label ?? text\n\n if (text !== undefined && label === undefined) delete props.text\n\n return h(entry.component, props, body === undefined ? undefined : () => body)\n}\n\nexport function renderNodes(nodes: ScreenNode[], context: RenderContext): VNode[] {\n const out: VNode[] = []\n for (const node of nodes) {\n const rendered = renderNode(node, context)\n if (rendered) out.push(rendered)\n }\n return out\n}\n\n/** A list of nodes as a component, so the tree can recurse through slots. */\nexport const WxScreenNodes = defineComponent({\n name: 'WxScreenNodes',\n props: {\n nodes: { type: Array as PropType<ScreenNode[]>, required: true },\n context: { type: Object as PropType<RenderContext>, required: true },\n },\n setup(props) {\n return () => renderNodes(props.nodes, props.context)\n },\n})\n","<script setup lang=\"ts\">\nimport { computed, inject, useAttrs } from 'vue'\nimport { WxRepeater } from '@webx-ui/core'\nimport { screenErrorsKey, withFieldDefaults, WxScreenNodes, type RenderContext } from './render'\nimport type { ScreenModel, ScreenNode } from './types'\n\ndefineOptions({ name: 'WxScreenRepeater', inheritAttrs: false })\n\n/**\n * The one type with a nested model: the value is a list of records, and the node's\n * children are the fields of one of them. Every child is bound by its own `name` to a key\n * of the item, which is why a repeater is the only place where a name means nesting.\n *\n * Nothing of `WxRepeater`'s own is declared here — `title`, `itemLabel`, `min` and the\n * rest ride in as attributes, so a prop the screen did not set stays unset instead of\n * arriving as `false`.\n */\nconst props = defineProps<{\n /** The node being drawn — its children are one item's fields. */\n node: ScreenNode\n /** The renderer's context; each row gets a copy bound to its own item. */\n context: RenderContext\n /** The renderer hands every field these two. A repeater has no use for either. */\n name?: string\n localized?: boolean\n}>()\n\nconst model = defineModel<ScreenModel[]>({ default: () => [] })\n\nconst items = computed<ScreenModel[]>(() => (Array.isArray(model.value) ? model.value : []))\n\nconst attrs = useAttrs()\n\n/** The names one item's fields answer to — through layout, not into a nested repeater. */\nfunction fieldNames(nodes: ScreenNode[]): string[] {\n return nodes.flatMap((child) =>\n child.name === undefined ? fieldNames(child.children ?? []) : [child.name],\n )\n}\n\nconst refusal = inject(screenErrorsKey, null)\n\n/**\n * The refusal, row by row, under the names the row's fields answer to.\n *\n * The server names a field of a row by its path — `articles.2.url`, and a translated one down to\n * the language, `articles.2.title.en` — while the field inside the row is simply `url` or\n * `title`. Each row gets its own part, the same way the renderer maps `slug.en` onto `slug`,\n * and nothing else: without it a row's `title` shows the record's own `title` error.\n */\nconst rowErrors = computed<Record<string, string[]>[] | undefined>(() => {\n const errors = refusal?.value\n\n if (props.name === undefined) return undefined\n\n const fields = fieldNames(props.node.children ?? [])\n\n return items.value.map((_item, index) => {\n const prefix = `${props.name}.${index}.`\n const out: Record<string, string[]> = {}\n\n for (const [key, messages] of Object.entries(errors ?? {})) {\n if (!key.startsWith(prefix)) continue\n\n const rest = key.slice(prefix.length)\n const field = fields.find((name) => rest.startsWith(`${name}.`))\n\n out[rest] = messages\n if (field !== undefined && out[field] === undefined) out[field] = messages\n }\n\n return out\n })\n})\n\n/**\n * The panel's words, where the core has only English defaults: the core does not know the\n * panel's dictionary, and a translated form with \"Add\" and \"Remove\" in the middle of it is what\n * that looks like. A key the dictionary does not have — a renderer without one — comes back as\n * itself, and then the core's own word is the better answer.\n */\nfunction word(key: string): string | undefined {\n const line = props.context.translate(`webx-admin::screens.repeater.${key}`)\n\n return line.includes('::') ? undefined : line\n}\n\n/**\n * Folded unless the node says otherwise: a list of records opened all at once is a form a\n * kilometre long, and the header of each row already says which one it is. A row added now is\n * the core's business and opens anyway. And a row asks before it goes: in a screen it is data\n * somebody typed, and the bin sits right by the header one clicks to unfold it.\n */\nconst bound = computed(() => {\n const defaults: Record<string, unknown> = { collapsed: true, confirmRemove: true }\n\n for (const [prop, key] of [\n ['addLabel', 'add'],\n ['removeLabel', 'remove'],\n ['removeQuestion', 'remove-question'],\n ['cancelLabel', 'cancel'],\n ['dragLabel', 'reorder'],\n ['emptyText', 'empty'],\n ] as const) {\n const line = word(key)\n if (line !== undefined) defaults[prop] = line\n }\n\n return { ...defaults, ...attrs }\n})\n</script>\n\n<template>\n <wx-repeater\n v-bind=\"bound\"\n :model-value=\"items\"\n :row-errors=\"rowErrors\"\n @update:model-value=\"model = $event\"\n >\n <template #default=\"{ item, update }\">\n <wx-screen-nodes\n :nodes=\"node.children ?? []\"\n :context=\"{\n ...context,\n model: withFieldDefaults(node.children ?? [], item),\n update: (key: string, value: unknown) => update({ [key]: value }),\n }\"\n />\n </template>\n </wx-repeater>\n</template>\n","<script setup lang=\"ts\">\nimport { computed, inject, ref, watch } from 'vue'\nimport { WxTabs, type TabValue } from '@webx-ui/core'\nimport { screenErrorsKey } from './render'\n\n/**\n * The tabs of a described screen: `WxTabs`, and the one thing a form of tabs needs that a strip\n * of tabs does not — a refused save opens the tab the refusal is on.\n *\n * Without it a 422 can land on a tab nobody is looking at: the message is drawn under a field\n * that is not on screen, and the form looks as if it refused for no reason. A page hosting a\n * screen cannot do this itself, because the tabs are the description's and the page never sees\n * which field sits on which of them; the registry does, and hands the answer in as `fields`.\n *\n * The tab being looked at wins when it has a failing field of its own: the editor is already\n * where the problem is, and moving them would be moving them away from it.\n */\ndefineOptions({ name: 'WxScreenTabs', inheritAttrs: false })\n\nconst props = withDefaults(\n defineProps<{\n /** The names of the fields under each tab, in the order the tabs are read. */\n fields?: Record<string, string[]>\n }>(),\n { fields: () => ({}) },\n)\n\nconst errors = inject(screenErrorsKey, null)\n\nconst active = ref<TabValue | undefined>(undefined)\n\n/** The tabs holding a failing field, in the order they are read. The renderer has already put\n `slug.en` under `slug`, so a name is looked up as it is. */\nconst failing = computed<string[]>(() => {\n const names = new Set(Object.keys(errors?.value ?? {}))\n\n return Object.entries(props.fields)\n .filter(([, fields]) => fields.some((field) => names.has(field)))\n .map(([tab]) => tab)\n})\n\nwatch(failing, (tabs) => {\n const first = tabs[0]\n\n if (first === undefined) return\n if (active.value !== undefined && tabs.includes(String(active.value))) return\n\n active.value = first\n})\n</script>\n\n<template>\n <wx-tabs v-model=\"active\" v-bind=\"$attrs\">\n <slot />\n </wx-tabs>\n</template>\n","import {\n WxAlert,\n WxAutocomplete,\n WxCard,\n WxCascader,\n WxCheckbox,\n WxCheckboxGroup,\n WxCodeEditor,\n WxCol,\n WxColorPicker,\n WxDatePicker,\n WxDateRangePicker,\n WxDateTimePicker,\n WxDivider,\n WxHeading,\n WxIconPicker,\n WxInput,\n WxInputNumber,\n WxRadioGroup,\n WxRate,\n WxRow,\n WxSegmented,\n WxSelect,\n WxSlider,\n WxSwitch,\n WxTab,\n WxTagsInput,\n WxText,\n WxTextarea,\n WxTimePicker,\n WxTransfer,\n WxTreeSelect,\n} from '@webx-ui/core'\nimport ScreenRepeater from './ScreenRepeater.vue'\nimport ScreenTabs from './ScreenTabs.vue'\nimport type { NodeKind, ScreenNode, TypeEntry, TypeRegistry } from './types'\n\n/** Every field name under a node, however deep — what a tab has to open for. */\nfunction fieldNames(node: ScreenNode): string[] {\n return (node.children ?? []).flatMap((child) =>\n child.name === undefined ? fieldNames(child) : [child.name],\n )\n}\n\n/** Wide in a row of a repeater: what spreads its fields across, or is wide on its own. */\nconst WIDE_IN_A_ROW = new Set(['wx-row', 'wx-col', 'wx-transfer', 'wx-code-editor', 'wx-rich-text'])\n\n/**\n * A repeater takes the whole width only when its rows need it — fields side by side, an editor.\n * Rows of plain fields stacked one under another stop where a field does: a row as wide as a\n * monitor put the bin a screen away from the inputs it removes.\n */\nfunction sideBySide(node: ScreenNode): boolean {\n return (node.children ?? []).some(\n (child) => WIDE_IN_A_ROW.has(child.type) || (child.type !== 'wx-repeater' && sideBySide(child)),\n )\n}\n\n/**\n * The types every panel has: the core's layout, form and display components under\n * their full names. A module or a project adds its own the same way — `wx-media` comes\n * from `module-media`, `map` from whoever has a map.\n */\nexport const coreTypes: TypeRegistry = {\n 'wx-tabs': {\n component: ScreenTabs,\n kind: 'layout',\n // Which fields each tab holds, so a refused save can open the tab it was refused on.\n bind: (node) => ({\n fields: Object.fromEntries((node.children ?? []).map((tab) => [tab.id, fieldNames(tab)])),\n }),\n },\n 'wx-tab': {\n component: WxTab,\n kind: 'layout',\n labelProp: 'label',\n // A tab is selected by value, and the node's id is the one stable thing it has.\n bind: (node) => ({ value: node.id }),\n },\n 'wx-card': { component: WxCard, kind: 'layout', labelProp: 'title' },\n 'wx-row': {\n component: WxRow,\n kind: 'layout',\n // Marked so the renderer can hold a row at the width of one field (see `ScreenRenderer.vue`).\n bind: (node) => ({ class: ['wx-screen__row', node.props?.class] }),\n },\n 'wx-col': {\n component: WxCol,\n kind: 'layout',\n // Marked so the renderer can stack what a column holds (see `ScreenRenderer.vue`),\n // without touching a `WxCol` that some field happens to use inside itself.\n bind: (node) => ({ class: ['wx-screen__col', node.props?.class] }),\n },\n 'wx-divider': { component: WxDivider, kind: 'layout', labelProp: 'label' },\n\n 'wx-input': { component: WxInput, kind: 'field' },\n 'wx-textarea': { component: WxTextarea, kind: 'field' },\n 'wx-input-number': { component: WxInputNumber, kind: 'field' },\n 'wx-select': { component: WxSelect, kind: 'field' },\n // The label beside the control rather than above it: on, off, and what is being turned.\n 'wx-switch': { component: WxSwitch, kind: 'field', labelProp: 'label' },\n 'wx-checkbox': { component: WxCheckbox, kind: 'field', labelProp: 'label' },\n 'wx-radio-group': { component: WxRadioGroup, kind: 'field' },\n 'wx-date-picker': { component: WxDatePicker, kind: 'field' },\n 'wx-color-picker': { component: WxColorPicker, kind: 'field' },\n 'wx-checkbox-group': { component: WxCheckboxGroup, kind: 'field' },\n 'wx-segmented': { component: WxSegmented, kind: 'field' },\n 'wx-slider': { component: WxSlider, kind: 'field' },\n 'wx-rate': { component: WxRate, kind: 'field' },\n 'wx-time-picker': { component: WxTimePicker, kind: 'field' },\n 'wx-date-time-picker': {\n component: WxDateTimePicker,\n kind: 'field',\n // A moment, not a wall clock. Without the offset the server reads the hour in its own\n // timezone and the browser in the reader's, and one value shows two different times. Bound\n // over `props` on purpose: the server parses exactly this shape.\n bind: () => ({ valueFormat: \"yyyy-MM-dd'T'HH:mm:ssXXX\" }),\n },\n 'wx-date-range-picker': { component: WxDateRangePicker, kind: 'field' },\n 'wx-tags-input': { component: WxTagsInput, kind: 'field' },\n 'wx-autocomplete': { component: WxAutocomplete, kind: 'field' },\n 'wx-icon-picker': { component: WxIconPicker, kind: 'field' },\n 'wx-cascader': { component: WxCascader, kind: 'field' },\n 'wx-tree-select': { component: WxTreeSelect, kind: 'field' },\n // Wide: two lists with the buttons between them do not fit in half a form.\n 'wx-transfer': { component: WxTransfer, kind: 'field', wide: true },\n // Wide for the reason an editor is: code is read in long lines.\n 'wx-code-editor': { component: WxCodeEditor, kind: 'field', wide: true },\n 'wx-repeater': { component: ScreenRepeater, kind: 'field', nested: true, wide: sideBySide },\n\n 'wx-heading': { component: WxHeading, kind: 'display' },\n 'wx-text': { component: WxText, kind: 'display' },\n 'wx-alert': { component: WxAlert, kind: 'display', labelProp: 'title' },\n}\n\n/** Identity with a type: keeps a project's registry object checked without an import of the type. */\nexport function defineTypes<T extends TypeRegistry>(types: T): T {\n return types\n}\n\nexport interface TypeDescription {\n type: string\n kind: NodeKind\n component: string\n /** Where the node's `label` ends up, in words. */\n label: string\n}\n\nfunction componentName(entry: TypeEntry): string {\n const component = entry.component as { name?: string; __name?: string }\n return component.name ?? component.__name ?? 'anonymous'\n}\n\nfunction labelDestination(entry: TypeEntry): string {\n if (entry.kind === 'field') return 'form item'\n if (entry.labelProp) return `prop \\`${entry.labelProp}\\``\n return entry.kind === 'display' ? 'default slot' : '—'\n}\n\n/** One row per type, in registry order — what the documentation table is made of. */\nexport function describeTypes(types: TypeRegistry): TypeDescription[] {\n return Object.entries(types).map(([type, entry]) => ({\n type,\n kind: entry.kind,\n component: componentName(entry),\n label: labelDestination(entry),\n }))\n}\n\n/**\n * The registry as a Markdown table, padded the way Prettier pads one, so the generated\n * block in the guide survives `prettier --check` and a test can compare it verbatim.\n */\nexport function typesTable(types: TypeRegistry): string {\n const rows = describeTypes(types).map((row) => [\n `\\`${row.type}\\``,\n row.kind,\n `\\`${row.component}\\``,\n row.label,\n ])\n const header = ['Type', 'Kind', 'Component', '`label` goes to']\n const widths = header.map((cell, column) =>\n Math.max(cell.length, ...rows.map((row) => row[column]!.length)),\n )\n const line = (cells: string[]) =>\n `| ${cells.map((cell, column) => cell.padEnd(widths[column]!)).join(' | ')} |`\n return [line(header), line(widths.map((width) => '-'.repeat(width))), ...rows.map(line)].join(\n '\\n',\n )\n}\n","<script setup lang=\"ts\">\nimport { computed, markRaw, provide, toRaw, watch } from 'vue'\nimport { WxForm } from '@webx-ui/core'\nimport { applyPatch } from './patch'\nimport { coreTypes } from './registry'\nimport {\n keyAsIs,\n screenErrorsKey,\n withFieldDefaults,\n WxScreenNodes,\n type RenderContext,\n} from './render'\nimport type {\n Patch,\n PatchError,\n ScreenModel,\n ScreenNode,\n Translate,\n TypeRegistry,\n ValidationErrors,\n} from './types'\n\ndefineOptions({ name: 'WxScreenRenderer' })\n\nconst props = withDefaults(\n defineProps<{\n /** The tree to draw — a module's screen, already patched by the server. */\n root: ScreenNode[]\n /** Client-side patch applied on top, in order. */\n patch?: Patch\n /** Server-side validation errors, keyed by field name; shown under the fields. */\n errors?: ValidationErrors\n /** Project types, merged over the core ones. */\n types?: TypeRegistry\n /** Turns `trans::` strings into words. Without it the key shows. */\n translate?: Translate\n /** Decides `can`. Without it every node is allowed. */\n can?: (permission: string) => boolean\n disabled?: boolean\n labelPosition?: 'top' | 'left'\n labelWidth?: string\n size?: 'sm' | 'md' | 'lg'\n }>(),\n {\n patch: () => [],\n errors: undefined,\n types: undefined,\n translate: undefined,\n can: undefined,\n disabled: false,\n labelPosition: undefined,\n labelWidth: undefined,\n size: undefined,\n },\n)\n\nconst emit = defineEmits<{\n /** Operations that could not be applied. Also reported to the console. */\n patchError: [errors: PatchError[]]\n}>()\n\nconst model = defineModel<ScreenModel>({ default: () => ({}) })\n\nconst applied = computed(() => applyPatch(props.root, props.patch))\n\n/** Every field name on the screen, however deep — a repeater is one field, not its items. */\nfunction names(nodes: ScreenNode[]): string[] {\n return nodes.flatMap((node) =>\n node.name === undefined ? names(node.children ?? []) : [node.name],\n )\n}\n\n/**\n * The refusal, under the names the fields answer to.\n *\n * Laravel names the language that failed — `slug.en` — and `WxFormItem` looks its error up by\n * the field's own name, so a refused translated field showed nothing at all: the save failed and\n * every field looked fine. A key is matched against the field names rather than cut at its first\n * dot, because a name may carry a dot of its own (`general.project-name`, CLAUDE.md §4).\n */\nconst failing = computed<ValidationErrors | undefined>(() => {\n if (props.errors === undefined) return undefined\n\n const fields = names(applied.value.root)\n const out: ValidationErrors = { ...props.errors }\n\n for (const [key, messages] of Object.entries(props.errors)) {\n const field = fields.find((name) => key.startsWith(`${name}.`))\n\n if (field !== undefined && out[field] === undefined) out[field] = messages\n }\n\n return out\n})\n\n/**\n * What the form draws: the same, less a row's refusal put under the repeater's own name.\n *\n * `duties.1.text.ru` is a field of the second row, and the row draws it there (`ScreenRepeater`);\n * under the repeater as a whole it read as a second, different refusal of the list itself. The\n * tabs still need it under `duties`, since that is the name they know the field by.\n */\nconst fieldErrors = computed<ValidationErrors | undefined>(() => {\n if (props.errors === undefined || failing.value === undefined) return undefined\n\n const out: ValidationErrors = { ...failing.value }\n\n for (const name of Object.keys(out)) {\n if (props.errors[name] !== undefined) continue\n\n const rows = Object.keys(props.errors).filter((key) => key.startsWith(`${name}.`))\n\n if (rows.length > 0 && rows.every((key) => /^\\d+\\./.test(key.slice(name.length + 1)))) {\n delete out[name]\n }\n }\n\n return out\n})\n\n// For the nodes that act on a refusal rather than only draw it — the tabs (`ScreenTabs.vue`)\n// and the rows of a repeater.\nprovide(screenErrorsKey, failing)\n\nwatch(\n () => applied.value.errors,\n (errors) => {\n for (const error of errors) {\n console.error(`[webx-ui/schema] patch[${error.index}] ${error.op.op}: ${error.message}`)\n }\n emit('patchError', errors)\n },\n { immediate: true },\n)\n\n/**\n * A registry kept in a `ref` arrives as a reactive proxy, and Vue warns about a\n * component that is one; the raw component is what `h()` wants anyway.\n */\nconst registry = computed<TypeRegistry>(() => {\n const merged: TypeRegistry = {}\n for (const [type, entry] of Object.entries({ ...coreTypes, ...props.types })) {\n merged[type] = { ...entry, component: markRaw(toRaw(entry.component)) }\n }\n return merged\n})\n\nconst context = computed<RenderContext>(() => ({\n types: registry.value,\n // Drawn with the defaults filled in; `update` below writes to the model as it is.\n model: withFieldDefaults(applied.value.root, model.value),\n update: (name, value) => {\n model.value = { ...model.value, [name]: value }\n },\n translate: props.translate ?? keyAsIs,\n can: props.can ?? (() => true),\n}))\n\ndefineExpose({\n /** The tree after the patch — what is actually on screen. */\n tree: computed(() => applied.value.root),\n})\n</script>\n\n<template>\n <wx-form\n class=\"wx-screen\"\n :errors=\"fieldErrors\"\n :disabled=\"disabled\"\n :label-position=\"labelPosition\"\n :label-width=\"labelWidth\"\n :size=\"size\"\n >\n <wx-screen-nodes :nodes=\"applied.root\" :context=\"context\" />\n </wx-form>\n</template>\n\n<style>\n/*\n * A column is a stack of fields, like a card's body. The form's own gap reaches only its\n * direct children, so two fields dropped into one `wx-col` stood flush: the label of the\n * second read as the hint of the first. Same step as the form and the card.\n */\n.wx-screen__col {\n display: flex;\n flex-direction: column;\n gap: var(--wx-gap, var(--wx-space-16));\n}\n\n/*\n * A row splits one field's width between two, it does not spread them across the card. Every\n * field stops at `--wx-field-max-width`, so a row as wide as the card put \"Start\" at the left\n * edge and \"End\" a thousand pixels away — two fields that belong together read as unrelated,\n * and each still left most of its column empty.\n *\n * Plus the gutter the row pulls back with its negative margins, so its outer edges line up with\n * the fields above and below. The columns answer to the row's width, so a pair of halves is\n * `sm: 12` — `md` needs 768px of room and a row this size never has it.\n */\n.wx-screen__row {\n max-width: calc(var(--wx-field-max-width, 640px) + var(--wx-row-gutter, 0px));\n}\n\n/* Global on purpose: the placeholder is created by a render function, outside any scope. */\n.wx-screen__unknown {\n padding: var(--wx-space-8) var(--wx-space-12);\n border: 1px dashed var(--wx-color-danger);\n border-radius: var(--wx-radius-control);\n background: var(--wx-color-danger-soft);\n color: var(--wx-color-danger);\n font-family: var(--wx-font-family-mono);\n font-size: var(--wx-font-size-sm);\n}\n</style>\n"],"names":["locate","root","id","index","node","found","findNode","collectIds","ids","walk","nodes","indexFor","list","position","where","anchor","at","clone","value","out","key","item","applyPatch","patch","tree","errors","op","message","apply","clash","duplicateIn","others","parent","contains","ancestor","child","incoming","except","existing","same","a","b","evaluateCondition","condition","model","isVisible","visible","NODE_KEYS","OPS","isRecord","checkCondition","path","forms","checkNode","seen","validateScreen","validatePatch","isPosition","TRANS_MARKER","screenErrorsKey","shown","context","withFieldDefaults","filled","keyAsIs","words","translate","translateDeep","renderUnknown","childSlots","defaultSlot","groups","name","slots","children","renderNodes","renderNode","entry","props","label","own","control","WxFormItem","text","body","rendered","WxScreenNodes","defineComponent","__props","_useModel","items","computed","attrs","useAttrs","fieldNames","refusal","inject","rowErrors","fields","_item","prefix","messages","rest","field","word","line","bound","defaults","prop","_createBlock","_unref","WxRepeater","_mergeProps","_cache","$event","_withCtx","update","_createVNode","active","ref","failing","names","tab","watch","tabs","first","_openBlock","$attrs","_renderSlot","_ctx","WIDE_IN_A_ROW","sideBySide","coreTypes","ScreenTabs","WxTab","WxCard","WxRow","WxCol","WxDivider","WxInput","WxTextarea","WxInputNumber","WxSelect","WxSwitch","WxCheckbox","WxRadioGroup","WxDatePicker","WxColorPicker","WxCheckboxGroup","WxSegmented","WxSlider","WxRate","WxTimePicker","WxDateTimePicker","WxDateRangePicker","WxTagsInput","WxAutocomplete","WxIconPicker","WxCascader","WxTreeSelect","WxTransfer","WxCodeEditor","ScreenRepeater","WxHeading","WxText","WxAlert","defineTypes","types","componentName","component","labelDestination","describeTypes","type","typesTable","rows","row","header","widths","cell","column","cells","width","emit","__emit","applied","fieldErrors","provide","error","registry","merged","markRaw","toRaw","__expose","WxForm"],"mappings":"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"}
package/dist/types.d.ts CHANGED
@@ -130,8 +130,9 @@ export interface TypeEntry {
130
130
  /**
131
131
  * A `field` whose control is not a field in the reading sense — an editor, a list of
132
132
  * blocks, a table. It keeps the whole width instead of stopping at `--wx-field-max-width`.
133
+ * A function decides per node — a repeater is wide only when its rows lay fields side by side.
133
134
  */
134
- wide?: boolean;
135
+ wide?: boolean | ((node: ScreenNode) => boolean);
135
136
  }
136
137
  export type TypeRegistry = Record<string, TypeEntry>;
137
138
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@webx-ui/schema",
3
- "version": "0.8.1",
3
+ "version": "0.9.1",
4
4
  "description": "Screens as JSON for WebX UI admin panels: the node format, patches, the type registry and the renderer.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -44,7 +44,7 @@
44
44
  "vue": "^3.5.0"
45
45
  },
46
46
  "dependencies": {
47
- "@webx-ui/core": "^0.39.0"
47
+ "@webx-ui/core": "^0.41.0"
48
48
  },
49
49
  "devDependencies": {
50
50
  "@types/node": "^24.10.1",