@wildwinter/app-shell 0.54.0 → 0.56.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.
@@ -826,13 +826,89 @@ var fieldRowFocus = {
826
826
  settle: (row) => keeper.settle(row),
827
827
  restore: (row) => keeper.restore(row)
828
828
  };
829
+ var isObject = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
830
+ function isSet(decl, value) {
831
+ if (value === void 0) return false;
832
+ if (decl.type === "record" && decl.default === void 0 && isObject(value)) {
833
+ const fields = decl.fields ?? [];
834
+ const declared = new Set(fields.map((f) => f.name));
835
+ if (Object.entries(value).some(([k, v]) => !declared.has(k) && v !== void 0)) return true;
836
+ return fields.some((f) => isSet(f, value[f.name]));
837
+ }
838
+ return extensions.stableStringify(value) !== extensions.stableStringify(extensions.defaultOf(decl));
839
+ }
840
+ function foldCaption(name, set) {
841
+ return set > 0 ? `${name} (${set} set)` : name;
842
+ }
843
+ function extensionFold() {
844
+ const open = /* @__PURE__ */ new Set();
845
+ const shown = /* @__PURE__ */ new Map();
846
+ const keyOf = (o) => `${o.extension}\0${o.node}`;
847
+ const visible = (o, setNames) => {
848
+ const was = shown.get(keyOf(o));
849
+ const fields = was ? /* @__PURE__ */ new Set([...was.fields, ...setNames]) : new Set(setNames);
850
+ shown.set(keyOf(o), { fields, used: true });
851
+ return fields;
852
+ };
853
+ const fold = {
854
+ isOpen: (extension) => open.has(extension),
855
+ setOpen(extension, on) {
856
+ if (on) open.add(extension);
857
+ else open.delete(extension);
858
+ for (const key of shown.keys()) if (key.startsWith(`${extension}\0`)) shown.delete(key);
859
+ },
860
+ sweep() {
861
+ for (const [key, entry] of shown) {
862
+ if (!entry.used) shown.delete(key);
863
+ else entry.used = false;
864
+ }
865
+ },
866
+ section(o) {
867
+ const sec = el("div", `shell-fold${o.className ? ` ${o.className}` : ""}`);
868
+ sec.dataset["extension"] = o.extension;
869
+ const cap = el("button", `shell-fold-cap${o.captionClassName ? ` ${o.captionClassName}` : ""}`);
870
+ cap.type = "button";
871
+ const body = el("div", "shell-fold-body");
872
+ sec.append(cap, body);
873
+ const draw = () => {
874
+ const isOpen = open.has(o.extension);
875
+ const setNames = new Set(o.fields.filter((f) => isSet(f, o.entry?.[f.name])).map((f) => f.name));
876
+ const show2 = isOpen ? void 0 : visible(o, setNames);
877
+ cap.replaceChildren(iconNode(isOpen ? "expanded" : "collapsed"), el("span", "shell-fold-name", foldCaption(o.caption, setNames.size)));
878
+ cap.setAttribute("aria-expanded", String(isOpen));
879
+ cap.dataset["tip"] = isOpen ? `Show only the fields set here` : `Show every ${o.caption} field`;
880
+ sec.classList.toggle("shell-fold-open", isOpen);
881
+ const rows = [...o.lead ?? []];
882
+ let group;
883
+ for (const decl of o.fields) {
884
+ if (show2 && !show2.has(decl.name)) continue;
885
+ const g = decl.group;
886
+ if (g !== void 0 && g !== group) {
887
+ group = g;
888
+ rows.push(o.group(g));
889
+ }
890
+ rows.push(o.row(decl));
891
+ }
892
+ rows.push(...o.tail ?? []);
893
+ body.replaceChildren(...rows);
894
+ };
895
+ cap.addEventListener("click", () => {
896
+ fold.setOpen(o.extension, !open.has(o.extension));
897
+ draw();
898
+ });
899
+ draw();
900
+ return sec;
901
+ }
902
+ };
903
+ return fold;
904
+ }
829
905
 
830
906
  // src/value-rows.ts
831
907
  function nodeLabel(adapter, kind, id) {
832
908
  return adapter.nodes(kind).find((n) => n.id === id)?.label ?? adapter.label?.(kind, id);
833
909
  }
834
910
  var SCALARS = /* @__PURE__ */ new Set(["text", "multiline", "number", "boolean", "enum", "flags", "quality", "string"]);
835
- var isObject = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
911
+ var isObject2 = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
836
912
  var nameOf = (decl) => decl.label ?? decl.name;
837
913
  var asDecl = (d, name) => ({ ...d, name: d.name ?? name });
838
914
  function ownProblems(decl, value, adapter) {
@@ -1071,31 +1147,31 @@ function structuredRow(initial) {
1071
1147
  }, controls));
1072
1148
  };
1073
1149
  if (decl.type === "record") {
1074
- const value = isObject(o.value) ? o.value : void 0;
1150
+ const value = isObject2(o.value) ? o.value : void 0;
1075
1151
  const required = value === void 0 ? [] : extensions.valueProblems(decl, value).filter((p) => p.code === "required");
1076
1152
  for (const f of decl.fields ?? []) {
1077
1153
  const missing = required.find((p) => p.path === f.name);
1078
1154
  child(`f:${f.name}`, f, value?.[f.name], (v) => {
1079
- const next = { ...isObject(opts.value) ? opts.value : {} };
1155
+ const next = { ...isObject2(opts.value) ? opts.value : {} };
1080
1156
  if (v === void 0) delete next[f.name];
1081
1157
  else next[f.name] = v;
1082
1158
  commit(Object.keys(next).length > 0 ? next : void 0);
1083
1159
  }, void 0, void 0, missing ? "Required." : void 0);
1084
1160
  }
1085
1161
  } else if (decl.type === "map" && decl.of) {
1086
- const value = isObject(o.value) ? o.value : {};
1162
+ const value = isObject2(o.value) ? o.value : {};
1087
1163
  const keyNodes = decl.key?.type === "reference" && o.adapter ? o.adapter.nodes(decl.key.to ?? "") : void 0;
1088
1164
  const keyKind = decl.key?.to ?? "";
1089
1165
  const keyLabel = (k) => (o.adapter && keyNodes !== void 0 ? nodeLabel(o.adapter, keyKind, k) : void 0) ?? k;
1090
1166
  for (const k of Object.keys(value)) {
1091
1167
  const remove = editable() ? [iconBtn("close", `Remove ${keyLabel(k)}`, () => {
1092
- const next = { ...isObject(opts.value) ? opts.value : {} };
1168
+ const next = { ...isObject2(opts.value) ? opts.value : {} };
1093
1169
  delete next[k];
1094
1170
  commit(Object.keys(next).length > 0 ? next : void 0);
1095
1171
  })] : [];
1096
1172
  const gone = keyNodes !== void 0 && o.adapter && nodeLabel(o.adapter, keyKind, k) === void 0 ? `${k} is not here any more.` : void 0;
1097
1173
  child(`k:${k}`, asDecl(decl.of, k), value[k], (v) => {
1098
- const next = { ...isObject(opts.value) ? opts.value : {} };
1174
+ const next = { ...isObject2(opts.value) ? opts.value : {} };
1099
1175
  next[k] = v === void 0 ? extensions.defaultOf(decl.of) : v;
1100
1176
  commit(next);
1101
1177
  }, remove, keyLabel(k), gone);
@@ -1139,7 +1215,7 @@ function structuredRow(initial) {
1139
1215
  }
1140
1216
  } else if (decl.type === "list" && decl.of) {
1141
1217
  const value = Array.isArray(o.value) ? o.value : [];
1142
- const idOf = (item, i) => decl.id !== void 0 && isObject(item) && typeof item[decl.id] === "string" ? `id:${item[decl.id]}` : `i:${i}`;
1218
+ const idOf = (item, i) => decl.id !== void 0 && isObject2(item) && typeof item[decl.id] === "string" ? `id:${item[decl.id]}` : `i:${i}`;
1143
1219
  value.forEach((item, i) => {
1144
1220
  const set = (next) => commit(next.length > 0 ? next : void 0);
1145
1221
  const controls = editable() ? [
@@ -1153,7 +1229,7 @@ function structuredRow(initial) {
1153
1229
  }, i === value.length - 1),
1154
1230
  iconBtn("close", "Remove", () => set(value.filter((_, j) => j !== i)), false, true)
1155
1231
  ] : [];
1156
- const itemLabel = decl.id !== void 0 && isObject(item) && typeof item[decl.id] === "string" ? item[decl.id] : `${i + 1}`;
1232
+ const itemLabel = decl.id !== void 0 && isObject2(item) && typeof item[decl.id] === "string" ? item[decl.id] : `${i + 1}`;
1157
1233
  child(idOf(item, i), asDecl(decl.of, itemLabel), item, (v) => {
1158
1234
  const next = [...Array.isArray(opts.value) ? opts.value : []];
1159
1235
  next[i] = v === void 0 ? extensions.defaultOf(decl.of) : v;
@@ -1164,8 +1240,8 @@ function structuredRow(initial) {
1164
1240
  if (editable()) {
1165
1241
  adder.append(iconBtn("add", "Add", () => {
1166
1242
  const fresh = extensions.defaultOf(decl.of);
1167
- if (decl.id !== void 0 && isObject(fresh)) {
1168
- const taken = new Set(value.map((x) => isObject(x) ? x[decl.id] : void 0));
1243
+ if (decl.id !== void 0 && isObject2(fresh)) {
1244
+ const taken = new Set(value.map((x) => isObject2(x) ? x[decl.id] : void 0));
1169
1245
  let n = value.length + 1;
1170
1246
  while (taken.has(`item-${n}`)) n++;
1171
1247
  fresh[decl.id] = `item-${n}`;
@@ -1214,6 +1290,9 @@ function valueRows() {
1214
1290
  };
1215
1291
  }
1216
1292
 
1293
+ exports.extensionFold = extensionFold;
1294
+ exports.foldCaption = foldCaption;
1295
+ exports.isSet = isSet;
1217
1296
  exports.valueRow = valueRow;
1218
1297
  exports.valueRows = valueRows;
1219
1298
  //# sourceMappingURL=value-rows.cjs.map