@wildwinter/app-shell 0.51.0 → 0.53.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.
@@ -55,7 +55,15 @@ interface FieldDeclLike extends ValueDeclLike {
55
55
  name: string;
56
56
  /** What the field is for, shown under the control. */
57
57
  purpose?: string;
58
+ /** A sentence about each value (an enum's values, the flags, a quality's stages), as an extension's manifest
59
+ * gives them: the chosen value's is shown under the control, and each chosen flag's. */
60
+ valueHelp?: Readonly<Record<string, string>>;
58
61
  }
62
+ /**
63
+ * The help for what `decl` holds: the chosen enum value's or stage's (the one it falls back to, when unset), or
64
+ * each chosen flag's, "name: sentence" a line each. Empty when the declaration describes none of them.
65
+ */
66
+ declare function valueHelpText(decl: FieldDeclLike, value: unknown): string;
59
67
  interface FieldRowOptions {
60
68
  decl: FieldDeclLike;
61
69
  /** The node's own value, typed (a flags value is a string list), or undefined where the node sets none. */
@@ -66,6 +74,9 @@ interface FieldRowOptions {
66
74
  disabled?: boolean;
67
75
  /** A message of the app's own about this value (a check the row cannot make), shown under the control. */
68
76
  problem?: string;
77
+ /** The app's own sentence INSTEAD of the row's (a renamed stage said better than "not one of the stages").
78
+ * Given, it is the whole message; `problem` is ignored. */
79
+ replaceProblem?: string;
69
80
  /** The caption; default the field's name. */
70
81
  label?: string | Node;
71
82
  /** Added to the row and its caption, so a row sits in its app's layout. */
@@ -109,4 +120,4 @@ interface FieldRows {
109
120
  /** A cache of field rows for a host that redraws its whole view on every change. */
110
121
  declare function fieldRows(): FieldRows;
111
122
 
112
- export { type FieldDeclLike, type FieldRowHandle, type FieldRowOptions, type FieldRows, type FieldValue, type RungStripOptions, type ValueDeclLike, defaultLabel, fallbackText, fieldRow, fieldRowFocus, fieldRows, fieldValueProblem, rungStrip, stageGateNote };
123
+ export { type FieldDeclLike, type FieldRowHandle, type FieldRowOptions, type FieldRows, type FieldValue, type RungStripOptions, type ValueDeclLike, defaultLabel, fallbackText, fieldRow, fieldRowFocus, fieldRows, fieldValueProblem, rungStrip, stageGateNote, valueHelpText };
@@ -55,7 +55,15 @@ interface FieldDeclLike extends ValueDeclLike {
55
55
  name: string;
56
56
  /** What the field is for, shown under the control. */
57
57
  purpose?: string;
58
+ /** A sentence about each value (an enum's values, the flags, a quality's stages), as an extension's manifest
59
+ * gives them: the chosen value's is shown under the control, and each chosen flag's. */
60
+ valueHelp?: Readonly<Record<string, string>>;
58
61
  }
62
+ /**
63
+ * The help for what `decl` holds: the chosen enum value's or stage's (the one it falls back to, when unset), or
64
+ * each chosen flag's, "name: sentence" a line each. Empty when the declaration describes none of them.
65
+ */
66
+ declare function valueHelpText(decl: FieldDeclLike, value: unknown): string;
59
67
  interface FieldRowOptions {
60
68
  decl: FieldDeclLike;
61
69
  /** The node's own value, typed (a flags value is a string list), or undefined where the node sets none. */
@@ -66,6 +74,9 @@ interface FieldRowOptions {
66
74
  disabled?: boolean;
67
75
  /** A message of the app's own about this value (a check the row cannot make), shown under the control. */
68
76
  problem?: string;
77
+ /** The app's own sentence INSTEAD of the row's (a renamed stage said better than "not one of the stages").
78
+ * Given, it is the whole message; `problem` is ignored. */
79
+ replaceProblem?: string;
69
80
  /** The caption; default the field's name. */
70
81
  label?: string | Node;
71
82
  /** Added to the row and its caption, so a row sits in its app's layout. */
@@ -109,4 +120,4 @@ interface FieldRows {
109
120
  /** A cache of field rows for a host that redraws its whole view on every change. */
110
121
  declare function fieldRows(): FieldRows;
111
122
 
112
- export { type FieldDeclLike, type FieldRowHandle, type FieldRowOptions, type FieldRows, type FieldValue, type RungStripOptions, type ValueDeclLike, defaultLabel, fallbackText, fieldRow, fieldRowFocus, fieldRows, fieldValueProblem, rungStrip, stageGateNote };
123
+ export { type FieldDeclLike, type FieldRowHandle, type FieldRowOptions, type FieldRows, type FieldValue, type RungStripOptions, type ValueDeclLike, defaultLabel, fallbackText, fieldRow, fieldRowFocus, fieldRows, fieldValueProblem, rungStrip, stageGateNote, valueHelpText };
@@ -1,4 +1,4 @@
1
- export { defaultLabel, fallbackText, fieldRow, fieldRowFocus, fieldRows, fieldValueProblem, rungStrip, stageGateNote } from './chunk-ELEDQRZ7.js';
1
+ export { defaultLabel, fallbackText, fieldRow, fieldRowFocus, fieldRows, fieldValueProblem, rungStrip, stageGateNote, valueHelpText } from './chunk-XJM733E6.js';
2
2
  import './chunk-W4WC4FO5.js';
3
3
  //# sourceMappingURL=value-control.js.map
4
4
  //# sourceMappingURL=value-control.js.map
@@ -478,6 +478,23 @@ function rungStrip(opts) {
478
478
  }
479
479
  return strip;
480
480
  }
481
+ function valueHelpText(decl, value) {
482
+ const help = decl.valueHelp;
483
+ if (help === void 0) return "";
484
+ const said = (v) => Object.prototype.hasOwnProperty.call(help, v) ? help[v] : void 0;
485
+ if (decl.type === "enum" || decl.type === "quality") {
486
+ const held = typeof value === "string" && value !== "" ? value : typeof decl.default === "string" && decl.default !== "" ? decl.default : decl.type === "enum" ? decl.values?.[0] : decl.stages?.[0];
487
+ return held === void 0 ? "" : said(held) ?? "";
488
+ }
489
+ if (decl.type === "flags") {
490
+ const held = Array.isArray(value) ? value.map(String) : Array.isArray(decl.default) ? decl.default.map(String) : [];
491
+ return held.flatMap((v) => {
492
+ const h = said(v);
493
+ return h === void 0 ? [] : [`${v}: ${h}`];
494
+ }).join("\n");
495
+ }
496
+ return "";
497
+ }
481
498
  var fallbackFlags = (decl) => Array.isArray(decl.default) ? decl.default.filter((v) => typeof v === "string") : [];
482
499
  function fieldValueProblem(decl, value) {
483
500
  if (value === void 0 || value === null || value === "") return "";
@@ -518,6 +535,7 @@ function fieldRow(initial) {
518
535
  caption.id = `shell-fr-${Math.random().toString(36).slice(2, 9)}`;
519
536
  const body = el("div", "shell-fieldrow-body");
520
537
  const purpose = el("p", "shell-fieldrow-purpose");
538
+ const valueHelp = el("p", "shell-fieldrow-purpose shell-fieldrow-valuehelp");
521
539
  const problem = el("p", "shell-fieldrow-problem");
522
540
  problem.setAttribute("role", "status");
523
541
  row.append(caption, body);
@@ -538,7 +556,10 @@ function fieldRow(initial) {
538
556
  purpose.id = `${caption.id}-p`;
539
557
  problem.id = `${caption.id}-m`;
540
558
  const sayProblem = () => {
541
- const words = [typing || fieldValueProblem(opts.decl, opts.value), opts.problem ?? ""].filter((w) => w !== "");
559
+ const help = valueHelpText(opts.decl, opts.value);
560
+ valueHelp.textContent = help;
561
+ valueHelp.hidden = help === "";
562
+ const words = opts.replaceProblem !== void 0 ? [opts.replaceProblem].filter((w) => w !== "") : [typing || fieldValueProblem(opts.decl, opts.value), opts.problem ?? ""].filter((w) => w !== "");
542
563
  problem.textContent = words.join(" ");
543
564
  problem.hidden = words.length === 0;
544
565
  row.classList.toggle("has-problem", words.length > 0);
@@ -727,7 +748,7 @@ function fieldRow(initial) {
727
748
  purpose.textContent = decl.purpose ?? "";
728
749
  if (decl.purpose) body.append(purpose);
729
750
  else purpose.remove();
730
- body.append(problem);
751
+ body.append(valueHelp, problem);
731
752
  sayProblem();
732
753
  };
733
754
  draw(initial);
@@ -807,13 +828,16 @@ var fieldRowFocus = {
807
828
  };
808
829
 
809
830
  // src/value-rows.ts
831
+ function nodeLabel(adapter, kind, id) {
832
+ return adapter.nodes(kind).find((n) => n.id === id)?.label ?? adapter.label?.(kind, id);
833
+ }
810
834
  var SCALARS = /* @__PURE__ */ new Set(["text", "multiline", "number", "boolean", "enum", "flags", "quality", "string"]);
811
835
  var isObject = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
812
836
  var nameOf = (decl) => decl.label ?? decl.name;
813
837
  var asDecl = (d, name) => ({ ...d, name: d.name ?? name });
814
838
  function ownProblems(decl, value, adapter) {
815
839
  if (value === void 0) return "";
816
- const exists = adapter ? (kind, id) => adapter.nodes(kind).some((n) => n.id === id) : void 0;
840
+ const exists = adapter ? (kind, id) => nodeLabel(adapter, kind, id) !== void 0 : void 0;
817
841
  return extensions.valueProblems(decl, value, exists ? { exists } : {}).filter((p) => p.path === "" && p.severity === "error" && p.code !== "not-a-value" && p.code !== "not-a-stage").map((p) => `${p.message.replace(/^the value/, "The value")}.`).join(" ");
818
842
  }
819
843
  function valueRow(initial) {
@@ -832,6 +856,7 @@ function scalarRow(initial) {
832
856
  ...o.onCommit ? { onCommit: (v) => o.onCommit(v) } : {},
833
857
  ...o.disabled !== void 0 ? { disabled: o.disabled } : {},
834
858
  ...problem !== "" ? { problem } : {},
859
+ ...o.replaceProblem !== void 0 ? { replaceProblem: o.replaceProblem } : {},
835
860
  label: o.label ?? nameOf(o.decl),
836
861
  ...o.className !== void 0 ? { className: o.className } : {},
837
862
  ...o.labelClassName !== void 0 ? { labelClassName: o.labelClassName } : {},
@@ -882,12 +907,15 @@ function referenceRow(initial) {
882
907
  };
883
908
  add("", "default (none)");
884
909
  for (const n of nodes) add(n.id, n.label);
885
- if (held !== "" && !nodes.some((n) => n.id === held)) add(held, `${held} (gone)`);
910
+ if (held !== "" && !nodes.some((n) => n.id === held)) {
911
+ const name = o.adapter.label?.(o.decl.to ?? "", held);
912
+ add(held, name ?? `${held} (gone)`);
913
+ }
886
914
  sel.value = held;
887
915
  sel.disabled = o.onCommit === void 0 || o.disabled === true;
888
916
  help.textContent = o.decl.help ?? o.decl.purpose ?? "";
889
917
  help.hidden = help.textContent === "";
890
- const words = [ownProblems(o.decl, o.value, o.adapter), o.problem ?? ""].filter((w) => w !== "").join(" ");
918
+ const words = o.replaceProblem ?? [ownProblems(o.decl, o.value, o.adapter), o.problem ?? ""].filter((w) => w !== "").join(" ");
891
919
  problem.textContent = words;
892
920
  problem.hidden = words === "";
893
921
  row.classList.toggle("has-problem", words !== "");
@@ -970,14 +998,15 @@ function structuredRow(initial) {
970
998
  } else if (decl.type === "map" && decl.of) {
971
999
  const value = isObject(o.value) ? o.value : {};
972
1000
  const keyNodes = decl.key?.type === "reference" && o.adapter ? o.adapter.nodes(decl.key.to ?? "") : void 0;
973
- const keyLabel = (k) => keyNodes?.find((n) => n.id === k)?.label ?? k;
1001
+ const keyKind = decl.key?.to ?? "";
1002
+ const keyLabel = (k) => (o.adapter && keyNodes !== void 0 ? nodeLabel(o.adapter, keyKind, k) : void 0) ?? k;
974
1003
  for (const k of Object.keys(value)) {
975
1004
  const remove = editable() ? [iconBtn("close", `Remove ${keyLabel(k)}`, () => {
976
1005
  const next = { ...isObject(opts.value) ? opts.value : {} };
977
1006
  delete next[k];
978
1007
  commit(Object.keys(next).length > 0 ? next : void 0);
979
1008
  })] : [];
980
- const gone = keyNodes !== void 0 && !keyNodes.some((n) => n.id === k) ? `${keyLabel(k)} is not here any more.` : void 0;
1009
+ const gone = keyNodes !== void 0 && o.adapter && nodeLabel(o.adapter, keyKind, k) === void 0 ? `${k} is not here any more.` : void 0;
981
1010
  child(`k:${k}`, asDecl(decl.of, k), value[k], (v) => {
982
1011
  const next = { ...isObject(opts.value) ? opts.value : {} };
983
1012
  next[k] = v === void 0 ? extensions.defaultOf(decl.of) : v;
@@ -1063,7 +1092,7 @@ function structuredRow(initial) {
1063
1092
  if (decl.type !== "record" && editable()) body.append(adder);
1064
1093
  help.textContent = decl.help ?? decl.purpose ?? "";
1065
1094
  if (help.textContent !== "") body.append(help);
1066
- const words = [ownProblems(decl, o.value, o.adapter), o.problem ?? ""].filter((w) => w !== "").join(" ");
1095
+ const words = o.replaceProblem ?? [ownProblems(decl, o.value, o.adapter), o.problem ?? ""].filter((w) => w !== "").join(" ");
1067
1096
  problem.textContent = words;
1068
1097
  problem.hidden = words === "";
1069
1098
  body.append(problem);