@wildwinter/app-shell 0.56.0 → 0.58.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.
Files changed (58) hide show
  1. package/README.md +215 -0
  2. package/dist/chunk-4JQWNC6Z.js +319 -0
  3. package/dist/chunk-4JQWNC6Z.js.map +1 -0
  4. package/dist/chunk-ICYPXUNA.js +8 -0
  5. package/dist/chunk-ICYPXUNA.js.map +1 -0
  6. package/dist/{chunk-CPNTROWD.js → chunk-OZQ2BYXH.js} +13 -4
  7. package/dist/chunk-OZQ2BYXH.js.map +1 -0
  8. package/dist/controls.css +52 -0
  9. package/dist/controls.css.map +1 -1
  10. package/dist/index.cjs +352 -3
  11. package/dist/index.cjs.map +1 -1
  12. package/dist/index.d.cts +17 -1
  13. package/dist/index.d.ts +17 -1
  14. package/dist/index.js +24 -1
  15. package/dist/index.js.map +1 -1
  16. package/dist/tool-window.cjs +11 -2
  17. package/dist/tool-window.cjs.map +1 -1
  18. package/dist/tool-window.d.cts +10 -4
  19. package/dist/tool-window.d.ts +10 -4
  20. package/dist/tool-window.js +1 -1
  21. package/dist/updater.cjs.map +1 -1
  22. package/dist/updater.js +1 -1
  23. package/dist/value-rows.cjs +200 -10
  24. package/dist/value-rows.cjs.map +1 -1
  25. package/dist/value-rows.d.cts +36 -1
  26. package/dist/value-rows.d.ts +36 -1
  27. package/dist/value-rows.js +197 -12
  28. package/dist/value-rows.js.map +1 -1
  29. package/dist/view-client.cjs +172 -0
  30. package/dist/view-client.cjs.map +1 -0
  31. package/dist/view-client.d.cts +46 -0
  32. package/dist/view-client.d.ts +46 -0
  33. package/dist/view-client.js +165 -0
  34. package/dist/view-client.js.map +1 -0
  35. package/dist/view-host-web.cjs +327 -0
  36. package/dist/view-host-web.cjs.map +1 -0
  37. package/dist/view-host-web.d.cts +61 -0
  38. package/dist/view-host-web.d.ts +61 -0
  39. package/dist/view-host-web.js +4 -0
  40. package/dist/view-host-web.js.map +1 -0
  41. package/dist/view-host.cjs +532 -0
  42. package/dist/view-host.cjs.map +1 -0
  43. package/dist/view-host.d.cts +178 -0
  44. package/dist/view-host.d.ts +178 -0
  45. package/dist/view-host.js +426 -0
  46. package/dist/view-host.js.map +1 -0
  47. package/dist/view-preload.cjs +16 -0
  48. package/dist/view-preload.cjs.map +1 -0
  49. package/dist/view-preload.js +8 -0
  50. package/dist/view-preload.js.map +1 -0
  51. package/dist/view-protocol.cjs +12 -0
  52. package/dist/view-protocol.cjs.map +1 -0
  53. package/dist/view-protocol.d.cts +257 -0
  54. package/dist/view-protocol.d.ts +257 -0
  55. package/dist/view-protocol.js +3 -0
  56. package/dist/view-protocol.js.map +1 -0
  57. package/package.json +25 -4
  58. package/dist/chunk-CPNTROWD.js.map +0 -1
@@ -902,13 +902,198 @@ function extensionFold() {
902
902
  };
903
903
  return fold;
904
904
  }
905
+ var isObject2 = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
906
+ function isRecordMap(decl) {
907
+ return decl.type === "map" && decl.of?.type === "record";
908
+ }
909
+ function recordMapKeyLabel(decl, key, adapter) {
910
+ const kind = decl.key?.type === "reference" ? decl.key.to ?? "" : void 0;
911
+ if (kind === void 0 || !adapter) return key;
912
+ return adapter.nodes(kind).find((n) => n.id === key)?.label ?? adapter.label?.(kind, key) ?? key;
913
+ }
914
+ function valueText(decl, value, adapter) {
915
+ if (!isSet(decl, value)) return "";
916
+ if (decl.type === "pick" && typeof value === "string") {
917
+ const choice = extensions.pickChoices(decl, {
918
+ ...adapter ? { nodes: (kind) => adapter.nodes(kind) } : {},
919
+ ...adapter?.list ? { list: (name) => adapter.list(name) } : {}
920
+ }).find((c) => c.value === value);
921
+ return choice?.label ?? value;
922
+ }
923
+ if (decl.type === "reference" && typeof value === "string" && decl.to !== void 0 && adapter) {
924
+ return adapter.nodes(decl.to).find((n) => n.id === value)?.label ?? adapter.label?.(decl.to, value) ?? value;
925
+ }
926
+ if (decl.type === "boolean") return value === true ? decl.label ?? decl.name : "";
927
+ if (Array.isArray(value)) return value.map(String).join(", ");
928
+ if (isObject2(value)) return JSON.stringify(value);
929
+ return String(value);
930
+ }
931
+ function recordMapSummary(decl, value, adapter) {
932
+ if (!isObject2(value)) return [];
933
+ const fields = decl.of?.fields ?? [];
934
+ return Object.entries(value).map(([key, record]) => {
935
+ const name = recordMapKeyLabel(decl, key, adapter);
936
+ const words = isObject2(record) ? fields.map((f) => valueText(f, record[f.name], adapter)).filter((w) => w !== "") : [];
937
+ return words.length > 0 ? `${name}: ${words.join(", ")}` : name;
938
+ });
939
+ }
940
+ function recordMapGrid(initial) {
941
+ let opts = initial;
942
+ const root = el("div", "shell-recordgrid");
943
+ const table = el("table", "shell-recordgrid-table");
944
+ const head = el("thead");
945
+ const body = el("tbody");
946
+ table.append(head, body);
947
+ const adder = el("div", "shell-recordgrid-add");
948
+ const empty = el("p", "shell-recordgrid-empty");
949
+ root.append(table, empty, adder);
950
+ const cells = /* @__PURE__ */ new Map();
951
+ let addKey = "";
952
+ const editable = () => opts.onCommit !== void 0 && opts.disabled !== true;
953
+ const held = () => isObject2(opts.value) ? opts.value : {};
954
+ const commit = (next) => {
955
+ const v = Object.keys(next).length > 0 ? next : void 0;
956
+ opts = { ...opts, value: v };
957
+ draw();
958
+ opts.onCommit?.(v);
959
+ };
960
+ const cell = (key, field, record) => {
961
+ const id = `${key}\0${field.name}`;
962
+ const o = {
963
+ decl: field,
964
+ value: record[field.name],
965
+ ...opts.adapter ? { adapter: opts.adapter } : {},
966
+ ...opts.disabled !== void 0 ? { disabled: opts.disabled } : {},
967
+ ...opts.controlClassName !== void 0 ? { controlClassName: opts.controlClassName } : {},
968
+ ...editable() ? {
969
+ onCommit: (v) => {
970
+ const map = held();
971
+ const rec = { ...isObject2(map[key]) ? map[key] : {} };
972
+ if (v === void 0) delete rec[field.name];
973
+ else rec[field.name] = v;
974
+ commit({ ...map, [key]: rec });
975
+ }
976
+ } : {},
977
+ className: "shell-recordgrid-cell"
978
+ };
979
+ const had = cells.get(id);
980
+ if (had && had.el.dataset["type"] === field.type) {
981
+ fieldRowFocus.settle(had.el);
982
+ had.update(o);
983
+ fieldRowFocus.restore(had.el);
984
+ return had.el;
985
+ }
986
+ const handle = valueRow(o);
987
+ handle.el.dataset["type"] = field.type;
988
+ cells.set(id, handle);
989
+ return handle.el;
990
+ };
991
+ const draw = () => {
992
+ const decl = opts.decl;
993
+ const fields = decl.of?.fields ?? [];
994
+ const map = held();
995
+ const keys = Object.keys(map);
996
+ const adapter = opts.adapter;
997
+ const keyKind = decl.key?.type === "reference" ? decl.key.to ?? "" : void 0;
998
+ const keyNodes = keyKind !== void 0 && adapter ? adapter.nodes(keyKind) : void 0;
999
+ const hr = el("tr");
1000
+ hr.append(el("th", "shell-recordgrid-keyhead", recordMapKeyHeading(decl)));
1001
+ for (const f of fields) {
1002
+ const th = el("th", void 0, f.label ?? f.name);
1003
+ const help = f.help ?? f.purpose;
1004
+ if (help) th.dataset["tip"] = help;
1005
+ hr.append(th);
1006
+ }
1007
+ hr.append(el("th", "shell-recordgrid-tools"));
1008
+ head.replaceChildren(hr);
1009
+ const used = /* @__PURE__ */ new Set();
1010
+ const rows = [];
1011
+ for (const key of keys) {
1012
+ const record = isObject2(map[key]) ? map[key] : {};
1013
+ const tr = el("tr");
1014
+ tr.dataset["key"] = key;
1015
+ const name = recordMapKeyLabel(decl, key, adapter);
1016
+ const keyCell = el("th", "shell-recordgrid-key", name);
1017
+ keyCell.setAttribute("scope", "row");
1018
+ if (keyNodes !== void 0 && adapter && keyNodes.every((n) => n.id !== key) && adapter.label?.(keyKind, key) === void 0) {
1019
+ keyCell.append(el("span", "shell-recordgrid-gone", " (not here any more)"));
1020
+ }
1021
+ tr.append(keyCell);
1022
+ for (const f of fields) {
1023
+ used.add(`${key}\0${f.name}`);
1024
+ const td = el("td");
1025
+ td.append(cell(key, f, record));
1026
+ tr.append(td);
1027
+ }
1028
+ const tools = el("td", "shell-recordgrid-tools");
1029
+ if (editable()) tools.append(iconBtn("close", `Remove ${name}`, () => {
1030
+ const next = { ...held() };
1031
+ delete next[key];
1032
+ commit(next);
1033
+ }));
1034
+ tr.append(tools);
1035
+ rows.push(tr);
1036
+ }
1037
+ for (const id of [...cells.keys()]) if (!used.has(id)) cells.delete(id);
1038
+ body.replaceChildren(...rows);
1039
+ table.hidden = keys.length === 0;
1040
+ empty.textContent = keys.length === 0 ? "None yet." : "";
1041
+ empty.hidden = keys.length !== 0;
1042
+ adder.replaceChildren();
1043
+ if (!editable()) return;
1044
+ const add = (k) => {
1045
+ if (k === "" || Object.prototype.hasOwnProperty.call(held(), k)) return;
1046
+ commit({ ...held(), [k]: extensions.defaultOf(decl.of) });
1047
+ };
1048
+ if (keyNodes !== void 0) {
1049
+ const pick = el("select", `field shell-valuerow-key${opts.controlClassName ? ` ${opts.controlClassName}` : ""}`);
1050
+ const first = el("option", void 0, "Add...");
1051
+ first.value = "";
1052
+ pick.append(first);
1053
+ for (const n of keyNodes.filter((n2) => !Object.prototype.hasOwnProperty.call(map, n2.id))) {
1054
+ const opt = el("option", void 0, n.label);
1055
+ opt.value = n.id;
1056
+ pick.append(opt);
1057
+ }
1058
+ pick.disabled = pick.options.length === 1;
1059
+ pick.addEventListener("change", () => add(pick.value));
1060
+ adder.append(pick);
1061
+ } else {
1062
+ const input = el("input", "field shell-valuerow-key");
1063
+ input.type = "text";
1064
+ input.placeholder = "New key";
1065
+ input.value = addKey;
1066
+ input.addEventListener("input", () => {
1067
+ addKey = input.value;
1068
+ });
1069
+ const go = () => {
1070
+ const k = input.value.trim();
1071
+ addKey = "";
1072
+ add(k);
1073
+ };
1074
+ input.addEventListener("keydown", (e) => {
1075
+ if (e.key === "Enter") go();
1076
+ });
1077
+ adder.append(input, iconBtn("add", "Add", go));
1078
+ }
1079
+ };
1080
+ draw();
1081
+ return { el: root, update: (o) => {
1082
+ opts = o;
1083
+ draw();
1084
+ } };
1085
+ }
1086
+ function recordMapKeyHeading(decl) {
1087
+ const to = decl.key?.type === "reference" ? decl.key.to : void 0;
1088
+ return to ? to.charAt(0).toUpperCase() + to.slice(1) : "Key";
1089
+ }
905
1090
 
906
1091
  // src/value-rows.ts
907
1092
  function nodeLabel(adapter, kind, id) {
908
1093
  return adapter.nodes(kind).find((n) => n.id === id)?.label ?? adapter.label?.(kind, id);
909
1094
  }
910
1095
  var SCALARS = /* @__PURE__ */ new Set(["text", "multiline", "number", "boolean", "enum", "flags", "quality", "string"]);
911
- var isObject2 = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
1096
+ var isObject3 = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
912
1097
  var nameOf = (decl) => decl.label ?? decl.name;
913
1098
  var asDecl = (d, name) => ({ ...d, name: d.name ?? name });
914
1099
  function ownProblems(decl, value, adapter) {
@@ -1147,31 +1332,31 @@ function structuredRow(initial) {
1147
1332
  }, controls));
1148
1333
  };
1149
1334
  if (decl.type === "record") {
1150
- const value = isObject2(o.value) ? o.value : void 0;
1335
+ const value = isObject3(o.value) ? o.value : void 0;
1151
1336
  const required = value === void 0 ? [] : extensions.valueProblems(decl, value).filter((p) => p.code === "required");
1152
1337
  for (const f of decl.fields ?? []) {
1153
1338
  const missing = required.find((p) => p.path === f.name);
1154
1339
  child(`f:${f.name}`, f, value?.[f.name], (v) => {
1155
- const next = { ...isObject2(opts.value) ? opts.value : {} };
1340
+ const next = { ...isObject3(opts.value) ? opts.value : {} };
1156
1341
  if (v === void 0) delete next[f.name];
1157
1342
  else next[f.name] = v;
1158
1343
  commit(Object.keys(next).length > 0 ? next : void 0);
1159
1344
  }, void 0, void 0, missing ? "Required." : void 0);
1160
1345
  }
1161
1346
  } else if (decl.type === "map" && decl.of) {
1162
- const value = isObject2(o.value) ? o.value : {};
1347
+ const value = isObject3(o.value) ? o.value : {};
1163
1348
  const keyNodes = decl.key?.type === "reference" && o.adapter ? o.adapter.nodes(decl.key.to ?? "") : void 0;
1164
1349
  const keyKind = decl.key?.to ?? "";
1165
1350
  const keyLabel = (k) => (o.adapter && keyNodes !== void 0 ? nodeLabel(o.adapter, keyKind, k) : void 0) ?? k;
1166
1351
  for (const k of Object.keys(value)) {
1167
1352
  const remove = editable() ? [iconBtn("close", `Remove ${keyLabel(k)}`, () => {
1168
- const next = { ...isObject2(opts.value) ? opts.value : {} };
1353
+ const next = { ...isObject3(opts.value) ? opts.value : {} };
1169
1354
  delete next[k];
1170
1355
  commit(Object.keys(next).length > 0 ? next : void 0);
1171
1356
  })] : [];
1172
1357
  const gone = keyNodes !== void 0 && o.adapter && nodeLabel(o.adapter, keyKind, k) === void 0 ? `${k} is not here any more.` : void 0;
1173
1358
  child(`k:${k}`, asDecl(decl.of, k), value[k], (v) => {
1174
- const next = { ...isObject2(opts.value) ? opts.value : {} };
1359
+ const next = { ...isObject3(opts.value) ? opts.value : {} };
1175
1360
  next[k] = v === void 0 ? extensions.defaultOf(decl.of) : v;
1176
1361
  commit(next);
1177
1362
  }, remove, keyLabel(k), gone);
@@ -1215,7 +1400,7 @@ function structuredRow(initial) {
1215
1400
  }
1216
1401
  } else if (decl.type === "list" && decl.of) {
1217
1402
  const value = Array.isArray(o.value) ? o.value : [];
1218
- const idOf = (item, i) => decl.id !== void 0 && isObject2(item) && typeof item[decl.id] === "string" ? `id:${item[decl.id]}` : `i:${i}`;
1403
+ const idOf = (item, i) => decl.id !== void 0 && isObject3(item) && typeof item[decl.id] === "string" ? `id:${item[decl.id]}` : `i:${i}`;
1219
1404
  value.forEach((item, i) => {
1220
1405
  const set = (next) => commit(next.length > 0 ? next : void 0);
1221
1406
  const controls = editable() ? [
@@ -1229,7 +1414,7 @@ function structuredRow(initial) {
1229
1414
  }, i === value.length - 1),
1230
1415
  iconBtn("close", "Remove", () => set(value.filter((_, j) => j !== i)), false, true)
1231
1416
  ] : [];
1232
- const itemLabel = decl.id !== void 0 && isObject2(item) && typeof item[decl.id] === "string" ? item[decl.id] : `${i + 1}`;
1417
+ const itemLabel = decl.id !== void 0 && isObject3(item) && typeof item[decl.id] === "string" ? item[decl.id] : `${i + 1}`;
1233
1418
  child(idOf(item, i), asDecl(decl.of, itemLabel), item, (v) => {
1234
1419
  const next = [...Array.isArray(opts.value) ? opts.value : []];
1235
1420
  next[i] = v === void 0 ? extensions.defaultOf(decl.of) : v;
@@ -1240,8 +1425,8 @@ function structuredRow(initial) {
1240
1425
  if (editable()) {
1241
1426
  adder.append(iconBtn("add", "Add", () => {
1242
1427
  const fresh = extensions.defaultOf(decl.of);
1243
- if (decl.id !== void 0 && isObject2(fresh)) {
1244
- const taken = new Set(value.map((x) => isObject2(x) ? x[decl.id] : void 0));
1428
+ if (decl.id !== void 0 && isObject3(fresh)) {
1429
+ const taken = new Set(value.map((x) => isObject3(x) ? x[decl.id] : void 0));
1245
1430
  let n = value.length + 1;
1246
1431
  while (taken.has(`item-${n}`)) n++;
1247
1432
  fresh[decl.id] = `item-${n}`;
@@ -1292,8 +1477,13 @@ function valueRows() {
1292
1477
 
1293
1478
  exports.extensionFold = extensionFold;
1294
1479
  exports.foldCaption = foldCaption;
1480
+ exports.isRecordMap = isRecordMap;
1295
1481
  exports.isSet = isSet;
1482
+ exports.recordMapGrid = recordMapGrid;
1483
+ exports.recordMapKeyLabel = recordMapKeyLabel;
1484
+ exports.recordMapSummary = recordMapSummary;
1296
1485
  exports.valueRow = valueRow;
1297
1486
  exports.valueRows = valueRows;
1487
+ exports.valueText = valueText;
1298
1488
  //# sourceMappingURL=value-rows.cjs.map
1299
1489
  //# sourceMappingURL=value-rows.cjs.map