@wildwinter/app-shell 0.51.0 → 0.52.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. */
@@ -109,4 +117,4 @@ interface FieldRows {
109
117
  /** A cache of field rows for a host that redraws its whole view on every change. */
110
118
  declare function fieldRows(): FieldRows;
111
119
 
112
- export { type FieldDeclLike, type FieldRowHandle, type FieldRowOptions, type FieldRows, type FieldValue, type RungStripOptions, type ValueDeclLike, defaultLabel, fallbackText, fieldRow, fieldRowFocus, fieldRows, fieldValueProblem, rungStrip, stageGateNote };
120
+ 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. */
@@ -109,4 +117,4 @@ interface FieldRows {
109
117
  /** A cache of field rows for a host that redraws its whole view on every change. */
110
118
  declare function fieldRows(): FieldRows;
111
119
 
112
- export { type FieldDeclLike, type FieldRowHandle, type FieldRowOptions, type FieldRows, type FieldValue, type RungStripOptions, type ValueDeclLike, defaultLabel, fallbackText, fieldRow, fieldRowFocus, fieldRows, fieldValueProblem, rungStrip, stageGateNote };
120
+ 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-4QDD6GF3.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,6 +556,9 @@ function fieldRow(initial) {
538
556
  purpose.id = `${caption.id}-p`;
539
557
  problem.id = `${caption.id}-m`;
540
558
  const sayProblem = () => {
559
+ const help = valueHelpText(opts.decl, opts.value);
560
+ valueHelp.textContent = help;
561
+ valueHelp.hidden = help === "";
541
562
  const words = [typing || fieldValueProblem(opts.decl, opts.value), opts.problem ?? ""].filter((w) => w !== "");
542
563
  problem.textContent = words.join(" ");
543
564
  problem.hidden = 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) {
@@ -882,7 +906,10 @@ function referenceRow(initial) {
882
906
  };
883
907
  add("", "default (none)");
884
908
  for (const n of nodes) add(n.id, n.label);
885
- if (held !== "" && !nodes.some((n) => n.id === held)) add(held, `${held} (gone)`);
909
+ if (held !== "" && !nodes.some((n) => n.id === held)) {
910
+ const name = o.adapter.label?.(o.decl.to ?? "", held);
911
+ add(held, name ?? `${held} (gone)`);
912
+ }
886
913
  sel.value = held;
887
914
  sel.disabled = o.onCommit === void 0 || o.disabled === true;
888
915
  help.textContent = o.decl.help ?? o.decl.purpose ?? "";
@@ -970,14 +997,15 @@ function structuredRow(initial) {
970
997
  } else if (decl.type === "map" && decl.of) {
971
998
  const value = isObject(o.value) ? o.value : {};
972
999
  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;
1000
+ const keyKind = decl.key?.to ?? "";
1001
+ const keyLabel = (k) => (o.adapter && keyNodes !== void 0 ? nodeLabel(o.adapter, keyKind, k) : void 0) ?? k;
974
1002
  for (const k of Object.keys(value)) {
975
1003
  const remove = editable() ? [iconBtn("close", `Remove ${keyLabel(k)}`, () => {
976
1004
  const next = { ...isObject(opts.value) ? opts.value : {} };
977
1005
  delete next[k];
978
1006
  commit(Object.keys(next).length > 0 ? next : void 0);
979
1007
  })] : [];
980
- const gone = keyNodes !== void 0 && !keyNodes.some((n) => n.id === k) ? `${keyLabel(k)} is not here any more.` : void 0;
1008
+ const gone = keyNodes !== void 0 && o.adapter && nodeLabel(o.adapter, keyKind, k) === void 0 ? `${k} is not here any more.` : void 0;
981
1009
  child(`k:${k}`, asDecl(decl.of, k), value[k], (v) => {
982
1010
  const next = { ...isObject(opts.value) ? opts.value : {} };
983
1011
  next[k] = v === void 0 ? extensions.defaultOf(decl.of) : v;