@wildwinter/app-shell 0.55.0 → 0.57.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,90 @@
1
1
  import { PickSource } from '@wildwinter/toolkit/extensions';
2
2
  import { FieldDeclLike } from './value-control.cjs';
3
3
 
4
+ /**
5
+ * Whether a node's value for `decl` is set: held, and not the declaration's default. A record counts as its
6
+ * default when each of its fields does and it holds no other key, so `{}` and a record of defaults are both
7
+ * unset; anything else is compared with `defaultOf`, deeply and regardless of key order.
8
+ */
9
+ declare function isSet(decl: ValueDecl, value: unknown): boolean;
10
+ interface FoldSectionOptions {
11
+ /** The extension's id: the fold is remembered by it. */
12
+ extension: string;
13
+ /** The extension's name, the caption. */
14
+ caption: string;
15
+ /** The node the section is for, by any key unique to it: a row cleared while folded stays while the host
16
+ * keeps drawing this node. */
17
+ node: string;
18
+ /** The extension's fields for the node's kind, in the manifest's order. */
19
+ fields: readonly ValueDecl[];
20
+ /** The node's values for the extension, or undefined where it holds none. */
21
+ entry: Record<string, unknown> | undefined;
22
+ /** One field's row, drawn by the host. */
23
+ row: (decl: ValueDecl) => HTMLElement;
24
+ /** A heading above the first shown field of a group. */
25
+ group: (name: string) => HTMLElement;
26
+ /** Shown above the rows, folded or not (a lock line). */
27
+ lead?: readonly HTMLElement[];
28
+ /** Shown after the rows, folded or not (keys the extension doesn't declare). */
29
+ tail?: readonly HTMLElement[];
30
+ /** The section's own class, beside `shell-fold`. */
31
+ className?: string;
32
+ /** The caption's class, beside `shell-fold-cap`. */
33
+ captionClassName?: string;
34
+ }
35
+ interface ExtensionFold {
36
+ /** Draw one extension's section for one node: the caption and disclosure, then the rows the fold shows. */
37
+ section(o: FoldSectionOptions): HTMLElement;
38
+ /** Whether an extension's section is open (every field). Folded until opened. */
39
+ isOpen(extension: string): boolean;
40
+ setOpen(extension: string, open: boolean): void;
41
+ /** After a redraw: forget the rows kept for nodes it didn't draw, so leaving a node and coming back shows
42
+ * only what is set. A host that redraws its whole view calls it at the end of each, as a row cache's. */
43
+ sweep(): void;
44
+ }
45
+ /** The caption's words: the name, and the count when anything is set. */
46
+ declare function foldCaption(name: string, set: number): string;
47
+ /**
48
+ * The fold for a host's inspector: one per host, kept across its redraws, so the fold stays as left from node
49
+ * to node.
50
+ */
51
+ declare function extensionFold(): ExtensionFold;
52
+
53
+ /** A map whose values are records: edited in the grid, summarised in the inspector. */
54
+ declare function isRecordMap(decl: ValueDecl): boolean;
55
+ /** A map key's name: a node's from the host, else the key itself. */
56
+ declare function recordMapKeyLabel(decl: ValueDecl, key: string, adapter?: ValueAdapter): string;
57
+ /** A value as words, the way its control shows it: a pick's or a reference's name, flags joined, a boolean as
58
+ * the field's own name. Empty for a value that isn't set. */
59
+ declare function valueText(decl: ValueDecl, value: unknown, adapter?: ValueAdapter): string;
60
+ /** The inspector's summary of a map of records: a line per key, "TAM: smile, nod, WREN", the record's set
61
+ * fields in the manifest's order; a key with nothing set is its name alone. */
62
+ declare function recordMapSummary(decl: ValueDecl, value: unknown, adapter?: ValueAdapter): string[];
63
+ interface RecordMapGridOptions {
64
+ /** The map's declaration: `isRecordMap`. */
65
+ decl: ValueDecl;
66
+ /** The node's value, or undefined where it holds none. */
67
+ value: unknown;
68
+ /** The host's nodes, for a reference key and the cells' picks and references. */
69
+ adapter?: ValueAdapter;
70
+ /** Commit the whole map; undefined clears it. Absent: read-only. */
71
+ onCommit?: (value: unknown) => void;
72
+ disabled?: boolean;
73
+ /** The class on each cell's control, as the host's own rows carry. */
74
+ controlClassName?: string;
75
+ }
76
+ interface RecordMapGrid {
77
+ readonly el: HTMLElement;
78
+ update(opts: RecordMapGridOptions): void;
79
+ }
80
+ /**
81
+ * The grid: a row per key, a column per record field, each cell the row value-rows draws for that field (so
82
+ * picks, their checks and their problems are the same as in the inspector), a remove button per row, and the
83
+ * key adder under it. Keeps its cells across `update`, so a host that redraws on every change keeps the
84
+ * author's place.
85
+ */
86
+ declare function recordMapGrid(initial: RecordMapGridOptions): RecordMapGrid;
87
+
4
88
  /** A declaration of any type, as an extension's manifest writes it. */
5
89
  interface ValueDecl extends FieldDeclLike {
6
90
  /** The caption; the name when absent. */
@@ -86,4 +170,4 @@ interface ValueRows {
86
170
  }
87
171
  declare function valueRows(): ValueRows;
88
172
 
89
- export { type ValueAdapter, type ValueDecl, type ValueNode, type ValueRowHandle, type ValueRowOptions, type ValueRows, valueRow, valueRows };
173
+ export { type ExtensionFold, type FoldSectionOptions, type RecordMapGrid, type RecordMapGridOptions, type ValueAdapter, type ValueDecl, type ValueNode, type ValueRowHandle, type ValueRowOptions, type ValueRows, extensionFold, foldCaption, isRecordMap, isSet, recordMapGrid, recordMapKeyLabel, recordMapSummary, valueRow, valueRows, valueText };
@@ -1,6 +1,90 @@
1
1
  import { PickSource } from '@wildwinter/toolkit/extensions';
2
2
  import { FieldDeclLike } from './value-control.js';
3
3
 
4
+ /**
5
+ * Whether a node's value for `decl` is set: held, and not the declaration's default. A record counts as its
6
+ * default when each of its fields does and it holds no other key, so `{}` and a record of defaults are both
7
+ * unset; anything else is compared with `defaultOf`, deeply and regardless of key order.
8
+ */
9
+ declare function isSet(decl: ValueDecl, value: unknown): boolean;
10
+ interface FoldSectionOptions {
11
+ /** The extension's id: the fold is remembered by it. */
12
+ extension: string;
13
+ /** The extension's name, the caption. */
14
+ caption: string;
15
+ /** The node the section is for, by any key unique to it: a row cleared while folded stays while the host
16
+ * keeps drawing this node. */
17
+ node: string;
18
+ /** The extension's fields for the node's kind, in the manifest's order. */
19
+ fields: readonly ValueDecl[];
20
+ /** The node's values for the extension, or undefined where it holds none. */
21
+ entry: Record<string, unknown> | undefined;
22
+ /** One field's row, drawn by the host. */
23
+ row: (decl: ValueDecl) => HTMLElement;
24
+ /** A heading above the first shown field of a group. */
25
+ group: (name: string) => HTMLElement;
26
+ /** Shown above the rows, folded or not (a lock line). */
27
+ lead?: readonly HTMLElement[];
28
+ /** Shown after the rows, folded or not (keys the extension doesn't declare). */
29
+ tail?: readonly HTMLElement[];
30
+ /** The section's own class, beside `shell-fold`. */
31
+ className?: string;
32
+ /** The caption's class, beside `shell-fold-cap`. */
33
+ captionClassName?: string;
34
+ }
35
+ interface ExtensionFold {
36
+ /** Draw one extension's section for one node: the caption and disclosure, then the rows the fold shows. */
37
+ section(o: FoldSectionOptions): HTMLElement;
38
+ /** Whether an extension's section is open (every field). Folded until opened. */
39
+ isOpen(extension: string): boolean;
40
+ setOpen(extension: string, open: boolean): void;
41
+ /** After a redraw: forget the rows kept for nodes it didn't draw, so leaving a node and coming back shows
42
+ * only what is set. A host that redraws its whole view calls it at the end of each, as a row cache's. */
43
+ sweep(): void;
44
+ }
45
+ /** The caption's words: the name, and the count when anything is set. */
46
+ declare function foldCaption(name: string, set: number): string;
47
+ /**
48
+ * The fold for a host's inspector: one per host, kept across its redraws, so the fold stays as left from node
49
+ * to node.
50
+ */
51
+ declare function extensionFold(): ExtensionFold;
52
+
53
+ /** A map whose values are records: edited in the grid, summarised in the inspector. */
54
+ declare function isRecordMap(decl: ValueDecl): boolean;
55
+ /** A map key's name: a node's from the host, else the key itself. */
56
+ declare function recordMapKeyLabel(decl: ValueDecl, key: string, adapter?: ValueAdapter): string;
57
+ /** A value as words, the way its control shows it: a pick's or a reference's name, flags joined, a boolean as
58
+ * the field's own name. Empty for a value that isn't set. */
59
+ declare function valueText(decl: ValueDecl, value: unknown, adapter?: ValueAdapter): string;
60
+ /** The inspector's summary of a map of records: a line per key, "TAM: smile, nod, WREN", the record's set
61
+ * fields in the manifest's order; a key with nothing set is its name alone. */
62
+ declare function recordMapSummary(decl: ValueDecl, value: unknown, adapter?: ValueAdapter): string[];
63
+ interface RecordMapGridOptions {
64
+ /** The map's declaration: `isRecordMap`. */
65
+ decl: ValueDecl;
66
+ /** The node's value, or undefined where it holds none. */
67
+ value: unknown;
68
+ /** The host's nodes, for a reference key and the cells' picks and references. */
69
+ adapter?: ValueAdapter;
70
+ /** Commit the whole map; undefined clears it. Absent: read-only. */
71
+ onCommit?: (value: unknown) => void;
72
+ disabled?: boolean;
73
+ /** The class on each cell's control, as the host's own rows carry. */
74
+ controlClassName?: string;
75
+ }
76
+ interface RecordMapGrid {
77
+ readonly el: HTMLElement;
78
+ update(opts: RecordMapGridOptions): void;
79
+ }
80
+ /**
81
+ * The grid: a row per key, a column per record field, each cell the row value-rows draws for that field (so
82
+ * picks, their checks and their problems are the same as in the inspector), a remove button per row, and the
83
+ * key adder under it. Keeps its cells across `update`, so a host that redraws on every change keeps the
84
+ * author's place.
85
+ */
86
+ declare function recordMapGrid(initial: RecordMapGridOptions): RecordMapGrid;
87
+
4
88
  /** A declaration of any type, as an extension's manifest writes it. */
5
89
  interface ValueDecl extends FieldDeclLike {
6
90
  /** The caption; the name when absent. */
@@ -86,4 +170,4 @@ interface ValueRows {
86
170
  }
87
171
  declare function valueRows(): ValueRows;
88
172
 
89
- export { type ValueAdapter, type ValueDecl, type ValueNode, type ValueRowHandle, type ValueRowOptions, type ValueRows, valueRow, valueRows };
173
+ export { type ExtensionFold, type FoldSectionOptions, type RecordMapGrid, type RecordMapGridOptions, type ValueAdapter, type ValueDecl, type ValueNode, type ValueRowHandle, type ValueRowOptions, type ValueRows, extensionFold, foldCaption, isRecordMap, isSet, recordMapGrid, recordMapKeyLabel, recordMapSummary, valueRow, valueRows, valueText };
@@ -1,12 +1,275 @@
1
1
  import { fieldRow, fieldRowFocus } from './chunk-XJM733E6.js';
2
- import { el, iconBtn, moveItem } from './chunk-W4WC4FO5.js';
3
- import { pickChoices, valueProblems, defaultOf } from '@wildwinter/toolkit/extensions';
2
+ import { el, iconBtn, iconNode, moveItem } from './chunk-W4WC4FO5.js';
3
+ import { stableStringify, defaultOf, pickChoices, valueProblems } from '@wildwinter/toolkit/extensions';
4
4
 
5
+ var isObject = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
6
+ function isSet(decl, value) {
7
+ if (value === void 0) return false;
8
+ if (decl.type === "record" && decl.default === void 0 && isObject(value)) {
9
+ const fields = decl.fields ?? [];
10
+ const declared = new Set(fields.map((f) => f.name));
11
+ if (Object.entries(value).some(([k, v]) => !declared.has(k) && v !== void 0)) return true;
12
+ return fields.some((f) => isSet(f, value[f.name]));
13
+ }
14
+ return stableStringify(value) !== stableStringify(defaultOf(decl));
15
+ }
16
+ function foldCaption(name, set) {
17
+ return set > 0 ? `${name} (${set} set)` : name;
18
+ }
19
+ function extensionFold() {
20
+ const open = /* @__PURE__ */ new Set();
21
+ const shown = /* @__PURE__ */ new Map();
22
+ const keyOf = (o) => `${o.extension}\0${o.node}`;
23
+ const visible = (o, setNames) => {
24
+ const was = shown.get(keyOf(o));
25
+ const fields = was ? /* @__PURE__ */ new Set([...was.fields, ...setNames]) : new Set(setNames);
26
+ shown.set(keyOf(o), { fields, used: true });
27
+ return fields;
28
+ };
29
+ const fold = {
30
+ isOpen: (extension) => open.has(extension),
31
+ setOpen(extension, on) {
32
+ if (on) open.add(extension);
33
+ else open.delete(extension);
34
+ for (const key of shown.keys()) if (key.startsWith(`${extension}\0`)) shown.delete(key);
35
+ },
36
+ sweep() {
37
+ for (const [key, entry] of shown) {
38
+ if (!entry.used) shown.delete(key);
39
+ else entry.used = false;
40
+ }
41
+ },
42
+ section(o) {
43
+ const sec = el("div", `shell-fold${o.className ? ` ${o.className}` : ""}`);
44
+ sec.dataset["extension"] = o.extension;
45
+ const cap = el("button", `shell-fold-cap${o.captionClassName ? ` ${o.captionClassName}` : ""}`);
46
+ cap.type = "button";
47
+ const body = el("div", "shell-fold-body");
48
+ sec.append(cap, body);
49
+ const draw = () => {
50
+ const isOpen = open.has(o.extension);
51
+ const setNames = new Set(o.fields.filter((f) => isSet(f, o.entry?.[f.name])).map((f) => f.name));
52
+ const show = isOpen ? void 0 : visible(o, setNames);
53
+ cap.replaceChildren(iconNode(isOpen ? "expanded" : "collapsed"), el("span", "shell-fold-name", foldCaption(o.caption, setNames.size)));
54
+ cap.setAttribute("aria-expanded", String(isOpen));
55
+ cap.dataset["tip"] = isOpen ? `Show only the fields set here` : `Show every ${o.caption} field`;
56
+ sec.classList.toggle("shell-fold-open", isOpen);
57
+ const rows = [...o.lead ?? []];
58
+ let group;
59
+ for (const decl of o.fields) {
60
+ if (show && !show.has(decl.name)) continue;
61
+ const g = decl.group;
62
+ if (g !== void 0 && g !== group) {
63
+ group = g;
64
+ rows.push(o.group(g));
65
+ }
66
+ rows.push(o.row(decl));
67
+ }
68
+ rows.push(...o.tail ?? []);
69
+ body.replaceChildren(...rows);
70
+ };
71
+ cap.addEventListener("click", () => {
72
+ fold.setOpen(o.extension, !open.has(o.extension));
73
+ draw();
74
+ });
75
+ draw();
76
+ return sec;
77
+ }
78
+ };
79
+ return fold;
80
+ }
81
+ var isObject2 = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
82
+ function isRecordMap(decl) {
83
+ return decl.type === "map" && decl.of?.type === "record";
84
+ }
85
+ function recordMapKeyLabel(decl, key, adapter) {
86
+ const kind = decl.key?.type === "reference" ? decl.key.to ?? "" : void 0;
87
+ if (kind === void 0 || !adapter) return key;
88
+ return adapter.nodes(kind).find((n) => n.id === key)?.label ?? adapter.label?.(kind, key) ?? key;
89
+ }
90
+ function valueText(decl, value, adapter) {
91
+ if (!isSet(decl, value)) return "";
92
+ if (decl.type === "pick" && typeof value === "string") {
93
+ const choice = pickChoices(decl, {
94
+ ...adapter ? { nodes: (kind) => adapter.nodes(kind) } : {},
95
+ ...adapter?.list ? { list: (name) => adapter.list(name) } : {}
96
+ }).find((c) => c.value === value);
97
+ return choice?.label ?? value;
98
+ }
99
+ if (decl.type === "reference" && typeof value === "string" && decl.to !== void 0 && adapter) {
100
+ return adapter.nodes(decl.to).find((n) => n.id === value)?.label ?? adapter.label?.(decl.to, value) ?? value;
101
+ }
102
+ if (decl.type === "boolean") return value === true ? decl.label ?? decl.name : "";
103
+ if (Array.isArray(value)) return value.map(String).join(", ");
104
+ if (isObject2(value)) return JSON.stringify(value);
105
+ return String(value);
106
+ }
107
+ function recordMapSummary(decl, value, adapter) {
108
+ if (!isObject2(value)) return [];
109
+ const fields = decl.of?.fields ?? [];
110
+ return Object.entries(value).map(([key, record]) => {
111
+ const name = recordMapKeyLabel(decl, key, adapter);
112
+ const words = isObject2(record) ? fields.map((f) => valueText(f, record[f.name], adapter)).filter((w) => w !== "") : [];
113
+ return words.length > 0 ? `${name}: ${words.join(", ")}` : name;
114
+ });
115
+ }
116
+ function recordMapGrid(initial) {
117
+ let opts = initial;
118
+ const root = el("div", "shell-recordgrid");
119
+ const table = el("table", "shell-recordgrid-table");
120
+ const head = el("thead");
121
+ const body = el("tbody");
122
+ table.append(head, body);
123
+ const adder = el("div", "shell-recordgrid-add");
124
+ const empty = el("p", "shell-recordgrid-empty");
125
+ root.append(table, empty, adder);
126
+ const cells = /* @__PURE__ */ new Map();
127
+ let addKey = "";
128
+ const editable = () => opts.onCommit !== void 0 && opts.disabled !== true;
129
+ const held = () => isObject2(opts.value) ? opts.value : {};
130
+ const commit = (next) => {
131
+ const v = Object.keys(next).length > 0 ? next : void 0;
132
+ opts = { ...opts, value: v };
133
+ draw();
134
+ opts.onCommit?.(v);
135
+ };
136
+ const cell = (key, field, record) => {
137
+ const id = `${key}\0${field.name}`;
138
+ const o = {
139
+ decl: field,
140
+ value: record[field.name],
141
+ ...opts.adapter ? { adapter: opts.adapter } : {},
142
+ ...opts.disabled !== void 0 ? { disabled: opts.disabled } : {},
143
+ ...opts.controlClassName !== void 0 ? { controlClassName: opts.controlClassName } : {},
144
+ ...editable() ? {
145
+ onCommit: (v) => {
146
+ const map = held();
147
+ const rec = { ...isObject2(map[key]) ? map[key] : {} };
148
+ if (v === void 0) delete rec[field.name];
149
+ else rec[field.name] = v;
150
+ commit({ ...map, [key]: rec });
151
+ }
152
+ } : {},
153
+ className: "shell-recordgrid-cell"
154
+ };
155
+ const had = cells.get(id);
156
+ if (had && had.el.dataset["type"] === field.type) {
157
+ fieldRowFocus.settle(had.el);
158
+ had.update(o);
159
+ fieldRowFocus.restore(had.el);
160
+ return had.el;
161
+ }
162
+ const handle = valueRow(o);
163
+ handle.el.dataset["type"] = field.type;
164
+ cells.set(id, handle);
165
+ return handle.el;
166
+ };
167
+ const draw = () => {
168
+ const decl = opts.decl;
169
+ const fields = decl.of?.fields ?? [];
170
+ const map = held();
171
+ const keys = Object.keys(map);
172
+ const adapter = opts.adapter;
173
+ const keyKind = decl.key?.type === "reference" ? decl.key.to ?? "" : void 0;
174
+ const keyNodes = keyKind !== void 0 && adapter ? adapter.nodes(keyKind) : void 0;
175
+ const hr = el("tr");
176
+ hr.append(el("th", "shell-recordgrid-keyhead", recordMapKeyHeading(decl)));
177
+ for (const f of fields) {
178
+ const th = el("th", void 0, f.label ?? f.name);
179
+ const help = f.help ?? f.purpose;
180
+ if (help) th.dataset["tip"] = help;
181
+ hr.append(th);
182
+ }
183
+ hr.append(el("th", "shell-recordgrid-tools"));
184
+ head.replaceChildren(hr);
185
+ const used = /* @__PURE__ */ new Set();
186
+ const rows = [];
187
+ for (const key of keys) {
188
+ const record = isObject2(map[key]) ? map[key] : {};
189
+ const tr = el("tr");
190
+ tr.dataset["key"] = key;
191
+ const name = recordMapKeyLabel(decl, key, adapter);
192
+ const keyCell = el("th", "shell-recordgrid-key", name);
193
+ keyCell.setAttribute("scope", "row");
194
+ if (keyNodes !== void 0 && adapter && keyNodes.every((n) => n.id !== key) && adapter.label?.(keyKind, key) === void 0) {
195
+ keyCell.append(el("span", "shell-recordgrid-gone", " (not here any more)"));
196
+ }
197
+ tr.append(keyCell);
198
+ for (const f of fields) {
199
+ used.add(`${key}\0${f.name}`);
200
+ const td = el("td");
201
+ td.append(cell(key, f, record));
202
+ tr.append(td);
203
+ }
204
+ const tools = el("td", "shell-recordgrid-tools");
205
+ if (editable()) tools.append(iconBtn("close", `Remove ${name}`, () => {
206
+ const next = { ...held() };
207
+ delete next[key];
208
+ commit(next);
209
+ }));
210
+ tr.append(tools);
211
+ rows.push(tr);
212
+ }
213
+ for (const id of [...cells.keys()]) if (!used.has(id)) cells.delete(id);
214
+ body.replaceChildren(...rows);
215
+ table.hidden = keys.length === 0;
216
+ empty.textContent = keys.length === 0 ? "None yet." : "";
217
+ empty.hidden = keys.length !== 0;
218
+ adder.replaceChildren();
219
+ if (!editable()) return;
220
+ const add = (k) => {
221
+ if (k === "" || Object.prototype.hasOwnProperty.call(held(), k)) return;
222
+ commit({ ...held(), [k]: defaultOf(decl.of) });
223
+ };
224
+ if (keyNodes !== void 0) {
225
+ const pick = el("select", `field shell-valuerow-key${opts.controlClassName ? ` ${opts.controlClassName}` : ""}`);
226
+ const first = el("option", void 0, "Add...");
227
+ first.value = "";
228
+ pick.append(first);
229
+ for (const n of keyNodes.filter((n2) => !Object.prototype.hasOwnProperty.call(map, n2.id))) {
230
+ const opt = el("option", void 0, n.label);
231
+ opt.value = n.id;
232
+ pick.append(opt);
233
+ }
234
+ pick.disabled = pick.options.length === 1;
235
+ pick.addEventListener("change", () => add(pick.value));
236
+ adder.append(pick);
237
+ } else {
238
+ const input = el("input", "field shell-valuerow-key");
239
+ input.type = "text";
240
+ input.placeholder = "New key";
241
+ input.value = addKey;
242
+ input.addEventListener("input", () => {
243
+ addKey = input.value;
244
+ });
245
+ const go = () => {
246
+ const k = input.value.trim();
247
+ addKey = "";
248
+ add(k);
249
+ };
250
+ input.addEventListener("keydown", (e) => {
251
+ if (e.key === "Enter") go();
252
+ });
253
+ adder.append(input, iconBtn("add", "Add", go));
254
+ }
255
+ };
256
+ draw();
257
+ return { el: root, update: (o) => {
258
+ opts = o;
259
+ draw();
260
+ } };
261
+ }
262
+ function recordMapKeyHeading(decl) {
263
+ const to = decl.key?.type === "reference" ? decl.key.to : void 0;
264
+ return to ? to.charAt(0).toUpperCase() + to.slice(1) : "Key";
265
+ }
266
+
267
+ // src/value-rows.ts
5
268
  function nodeLabel(adapter, kind, id) {
6
269
  return adapter.nodes(kind).find((n) => n.id === id)?.label ?? adapter.label?.(kind, id);
7
270
  }
8
271
  var SCALARS = /* @__PURE__ */ new Set(["text", "multiline", "number", "boolean", "enum", "flags", "quality", "string"]);
9
- var isObject = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
272
+ var isObject3 = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
10
273
  var nameOf = (decl) => decl.label ?? decl.name;
11
274
  var asDecl = (d, name) => ({ ...d, name: d.name ?? name });
12
275
  function ownProblems(decl, value, adapter) {
@@ -245,31 +508,31 @@ function structuredRow(initial) {
245
508
  }, controls));
246
509
  };
247
510
  if (decl.type === "record") {
248
- const value = isObject(o.value) ? o.value : void 0;
511
+ const value = isObject3(o.value) ? o.value : void 0;
249
512
  const required = value === void 0 ? [] : valueProblems(decl, value).filter((p) => p.code === "required");
250
513
  for (const f of decl.fields ?? []) {
251
514
  const missing = required.find((p) => p.path === f.name);
252
515
  child(`f:${f.name}`, f, value?.[f.name], (v) => {
253
- const next = { ...isObject(opts.value) ? opts.value : {} };
516
+ const next = { ...isObject3(opts.value) ? opts.value : {} };
254
517
  if (v === void 0) delete next[f.name];
255
518
  else next[f.name] = v;
256
519
  commit(Object.keys(next).length > 0 ? next : void 0);
257
520
  }, void 0, void 0, missing ? "Required." : void 0);
258
521
  }
259
522
  } else if (decl.type === "map" && decl.of) {
260
- const value = isObject(o.value) ? o.value : {};
523
+ const value = isObject3(o.value) ? o.value : {};
261
524
  const keyNodes = decl.key?.type === "reference" && o.adapter ? o.adapter.nodes(decl.key.to ?? "") : void 0;
262
525
  const keyKind = decl.key?.to ?? "";
263
526
  const keyLabel = (k) => (o.adapter && keyNodes !== void 0 ? nodeLabel(o.adapter, keyKind, k) : void 0) ?? k;
264
527
  for (const k of Object.keys(value)) {
265
528
  const remove = editable() ? [iconBtn("close", `Remove ${keyLabel(k)}`, () => {
266
- const next = { ...isObject(opts.value) ? opts.value : {} };
529
+ const next = { ...isObject3(opts.value) ? opts.value : {} };
267
530
  delete next[k];
268
531
  commit(Object.keys(next).length > 0 ? next : void 0);
269
532
  })] : [];
270
533
  const gone = keyNodes !== void 0 && o.adapter && nodeLabel(o.adapter, keyKind, k) === void 0 ? `${k} is not here any more.` : void 0;
271
534
  child(`k:${k}`, asDecl(decl.of, k), value[k], (v) => {
272
- const next = { ...isObject(opts.value) ? opts.value : {} };
535
+ const next = { ...isObject3(opts.value) ? opts.value : {} };
273
536
  next[k] = v === void 0 ? defaultOf(decl.of) : v;
274
537
  commit(next);
275
538
  }, remove, keyLabel(k), gone);
@@ -313,7 +576,7 @@ function structuredRow(initial) {
313
576
  }
314
577
  } else if (decl.type === "list" && decl.of) {
315
578
  const value = Array.isArray(o.value) ? o.value : [];
316
- const idOf = (item, i) => decl.id !== void 0 && isObject(item) && typeof item[decl.id] === "string" ? `id:${item[decl.id]}` : `i:${i}`;
579
+ const idOf = (item, i) => decl.id !== void 0 && isObject3(item) && typeof item[decl.id] === "string" ? `id:${item[decl.id]}` : `i:${i}`;
317
580
  value.forEach((item, i) => {
318
581
  const set = (next) => commit(next.length > 0 ? next : void 0);
319
582
  const controls = editable() ? [
@@ -327,7 +590,7 @@ function structuredRow(initial) {
327
590
  }, i === value.length - 1),
328
591
  iconBtn("close", "Remove", () => set(value.filter((_, j) => j !== i)), false, true)
329
592
  ] : [];
330
- const itemLabel = decl.id !== void 0 && isObject(item) && typeof item[decl.id] === "string" ? item[decl.id] : `${i + 1}`;
593
+ const itemLabel = decl.id !== void 0 && isObject3(item) && typeof item[decl.id] === "string" ? item[decl.id] : `${i + 1}`;
331
594
  child(idOf(item, i), asDecl(decl.of, itemLabel), item, (v) => {
332
595
  const next = [...Array.isArray(opts.value) ? opts.value : []];
333
596
  next[i] = v === void 0 ? defaultOf(decl.of) : v;
@@ -338,8 +601,8 @@ function structuredRow(initial) {
338
601
  if (editable()) {
339
602
  adder.append(iconBtn("add", "Add", () => {
340
603
  const fresh = defaultOf(decl.of);
341
- if (decl.id !== void 0 && isObject(fresh)) {
342
- const taken = new Set(value.map((x) => isObject(x) ? x[decl.id] : void 0));
604
+ if (decl.id !== void 0 && isObject3(fresh)) {
605
+ const taken = new Set(value.map((x) => isObject3(x) ? x[decl.id] : void 0));
343
606
  let n = value.length + 1;
344
607
  while (taken.has(`item-${n}`)) n++;
345
608
  fresh[decl.id] = `item-${n}`;
@@ -388,6 +651,6 @@ function valueRows() {
388
651
  };
389
652
  }
390
653
 
391
- export { valueRow, valueRows };
654
+ export { extensionFold, foldCaption, isRecordMap, isSet, recordMapGrid, recordMapKeyLabel, recordMapSummary, valueRow, valueRows, valueText };
392
655
  //# sourceMappingURL=value-rows.js.map
393
656
  //# sourceMappingURL=value-rows.js.map