@wildwinter/expr-editor 0.11.0 → 0.12.1

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.
package/dist/index.d.cts CHANGED
@@ -407,6 +407,23 @@ declare function updateAt(list: EditorEffect[], i: number, patch: Partial<Editor
407
407
  declare function setArgAt(list: EditorEffect[], i: number, argIdx: number, value: string): EditorEffect[];
408
408
  declare function addArg(list: EditorEffect[], i: number, value?: string): EditorEffect[];
409
409
  declare function removeArgAt(list: EditorEffect[], i: number, argIdx: number): EditorEffect[];
410
+ /**
411
+ * What a freshly targeted property's value should be, and whether the guided value wizard still has a
412
+ * question worth asking.
413
+ *
414
+ * BOTH paths that target a property go through this - "+ set property" (add) and re-picking an
415
+ * existing effect's target - because when they answered separately they drifted: 0.11.0 seeded a
416
+ * quality with `advance(...)` on re-pick while the add path opened a wizard that did not know what a
417
+ * quality was, so the same job offered two different affordances depending on how you arrived.
418
+ *
419
+ * `ask: false` means the type has a canonical outcome and the wizard would be ceremony: a QUALITY
420
+ * moves to its next stage, which is the insertion-safe form the type exists for, and an author who
421
+ * meant a specific stage clicks the pill.
422
+ */
423
+ declare function initialValueFor(entry: CatalogueEntry, defaultScope: string): {
424
+ src: string;
425
+ ask: boolean;
426
+ };
410
427
  /** A sensible starting value-expression for a freshly targeted property. Literals
411
428
  * are seeded so the value editor opens on an editable pill, never the empty state.
412
429
  *
@@ -450,6 +467,11 @@ interface ValueWizardOptions {
450
467
  defaultScope: string;
451
468
  /** When known (a `set` target's declared type), the picker leads straight to that input. */
452
469
  expectedType?: PropertyType;
470
+ /** The target's closed set of values, when it has one: an enum's values, or a QUALITY's stages in
471
+ * ladder order. Callers should fill this with `choicesOf(entry)` rather than reading a single
472
+ * field, so a quality is never handed a wizard that knows its type but not its ladder. */
473
+ expectedChoices?: string[];
474
+ /** @deprecated Use `expectedChoices`. Kept so a 0.11.x caller keeps working. */
453
475
  expectedEnumValues?: string[];
454
476
  /** Receives the chosen value as name-form source. */
455
477
  onCommit: (src: string) => void;
@@ -459,4 +481,4 @@ interface ValueWizardOptions {
459
481
  /** Build the wizard UI into a fresh element (drive it via the host's popover). */
460
482
  declare function valueWizard(opts: ValueWizardOptions): HTMLElement;
461
483
 
462
- export { ARITHMETIC_OPS, BINARY_LABEL, COMPARABLE_TYPES, COMPARISON_OPS, type CatalogueEntry, EQUALITY_OPS, type EditCtx, type EditorEffect, type EffectsEditorHandle, type EffectsEditorOptions, type ExpressionEditorHandle, type ExpressionEditorOptions, type Filter, type FunctionTemplateSpec, type PreviewOptions, type TreeRow, UNARY_LABEL, type Validation, type ValueWizardOptions, type WizardSpec, type WizardStepSpec, type WizardValue, addArg, addChildToContainer, addEmit, addSet, astToTree, binary, boolLit, buildSubGroupClause, callNode, choicesOf, comparisonOpsFor, deleteAt, displayName, filterCatalogue, findEnumPeer, firstEmptyLeafPath, flagDelta, flipContainerOp, formatNumber, getNodeAt, groupByScope, insertSiblingClauseAt, isComparisonOp, isPlaceholderForOp, isWrappedInNot, issuesAt, lookup, mountEffectsEditor, mountExpressionEditor, moveAt, moveChildInContainer, needsParens, notNode, numLit, opSwapGroup, pathKey, placeholderForOp, redirectDeleteForPlaceholderSibling, refOf, removeArgAt, removeAt, renderConditionPreview, renderEffectsPreview, rhsTypesFor, scopedVar, searchCatalogue, seedValueSrc, setArgAt, setNodeAt, strLit, toggleContainerNot, toggleNotAt, updateAt, validateSource, valueWizard, wrapInNotAt };
484
+ export { ARITHMETIC_OPS, BINARY_LABEL, COMPARABLE_TYPES, COMPARISON_OPS, type CatalogueEntry, EQUALITY_OPS, type EditCtx, type EditorEffect, type EffectsEditorHandle, type EffectsEditorOptions, type ExpressionEditorHandle, type ExpressionEditorOptions, type Filter, type FunctionTemplateSpec, type PreviewOptions, type TreeRow, UNARY_LABEL, type Validation, type ValueWizardOptions, type WizardSpec, type WizardStepSpec, type WizardValue, addArg, addChildToContainer, addEmit, addSet, astToTree, binary, boolLit, buildSubGroupClause, callNode, choicesOf, comparisonOpsFor, deleteAt, displayName, filterCatalogue, findEnumPeer, firstEmptyLeafPath, flagDelta, flipContainerOp, formatNumber, getNodeAt, groupByScope, initialValueFor, insertSiblingClauseAt, isComparisonOp, isPlaceholderForOp, isWrappedInNot, issuesAt, lookup, mountEffectsEditor, mountExpressionEditor, moveAt, moveChildInContainer, needsParens, notNode, numLit, opSwapGroup, pathKey, placeholderForOp, redirectDeleteForPlaceholderSibling, refOf, removeArgAt, removeAt, renderConditionPreview, renderEffectsPreview, rhsTypesFor, scopedVar, searchCatalogue, seedValueSrc, setArgAt, setNodeAt, strLit, toggleContainerNot, toggleNotAt, updateAt, validateSource, valueWizard, wrapInNotAt };
package/dist/index.d.ts CHANGED
@@ -407,6 +407,23 @@ declare function updateAt(list: EditorEffect[], i: number, patch: Partial<Editor
407
407
  declare function setArgAt(list: EditorEffect[], i: number, argIdx: number, value: string): EditorEffect[];
408
408
  declare function addArg(list: EditorEffect[], i: number, value?: string): EditorEffect[];
409
409
  declare function removeArgAt(list: EditorEffect[], i: number, argIdx: number): EditorEffect[];
410
+ /**
411
+ * What a freshly targeted property's value should be, and whether the guided value wizard still has a
412
+ * question worth asking.
413
+ *
414
+ * BOTH paths that target a property go through this - "+ set property" (add) and re-picking an
415
+ * existing effect's target - because when they answered separately they drifted: 0.11.0 seeded a
416
+ * quality with `advance(...)` on re-pick while the add path opened a wizard that did not know what a
417
+ * quality was, so the same job offered two different affordances depending on how you arrived.
418
+ *
419
+ * `ask: false` means the type has a canonical outcome and the wizard would be ceremony: a QUALITY
420
+ * moves to its next stage, which is the insertion-safe form the type exists for, and an author who
421
+ * meant a specific stage clicks the pill.
422
+ */
423
+ declare function initialValueFor(entry: CatalogueEntry, defaultScope: string): {
424
+ src: string;
425
+ ask: boolean;
426
+ };
410
427
  /** A sensible starting value-expression for a freshly targeted property. Literals
411
428
  * are seeded so the value editor opens on an editable pill, never the empty state.
412
429
  *
@@ -450,6 +467,11 @@ interface ValueWizardOptions {
450
467
  defaultScope: string;
451
468
  /** When known (a `set` target's declared type), the picker leads straight to that input. */
452
469
  expectedType?: PropertyType;
470
+ /** The target's closed set of values, when it has one: an enum's values, or a QUALITY's stages in
471
+ * ladder order. Callers should fill this with `choicesOf(entry)` rather than reading a single
472
+ * field, so a quality is never handed a wizard that knows its type but not its ladder. */
473
+ expectedChoices?: string[];
474
+ /** @deprecated Use `expectedChoices`. Kept so a 0.11.x caller keeps working. */
453
475
  expectedEnumValues?: string[];
454
476
  /** Receives the chosen value as name-form source. */
455
477
  onCommit: (src: string) => void;
@@ -459,4 +481,4 @@ interface ValueWizardOptions {
459
481
  /** Build the wizard UI into a fresh element (drive it via the host's popover). */
460
482
  declare function valueWizard(opts: ValueWizardOptions): HTMLElement;
461
483
 
462
- export { ARITHMETIC_OPS, BINARY_LABEL, COMPARABLE_TYPES, COMPARISON_OPS, type CatalogueEntry, EQUALITY_OPS, type EditCtx, type EditorEffect, type EffectsEditorHandle, type EffectsEditorOptions, type ExpressionEditorHandle, type ExpressionEditorOptions, type Filter, type FunctionTemplateSpec, type PreviewOptions, type TreeRow, UNARY_LABEL, type Validation, type ValueWizardOptions, type WizardSpec, type WizardStepSpec, type WizardValue, addArg, addChildToContainer, addEmit, addSet, astToTree, binary, boolLit, buildSubGroupClause, callNode, choicesOf, comparisonOpsFor, deleteAt, displayName, filterCatalogue, findEnumPeer, firstEmptyLeafPath, flagDelta, flipContainerOp, formatNumber, getNodeAt, groupByScope, insertSiblingClauseAt, isComparisonOp, isPlaceholderForOp, isWrappedInNot, issuesAt, lookup, mountEffectsEditor, mountExpressionEditor, moveAt, moveChildInContainer, needsParens, notNode, numLit, opSwapGroup, pathKey, placeholderForOp, redirectDeleteForPlaceholderSibling, refOf, removeArgAt, removeAt, renderConditionPreview, renderEffectsPreview, rhsTypesFor, scopedVar, searchCatalogue, seedValueSrc, setArgAt, setNodeAt, strLit, toggleContainerNot, toggleNotAt, updateAt, validateSource, valueWizard, wrapInNotAt };
484
+ export { ARITHMETIC_OPS, BINARY_LABEL, COMPARABLE_TYPES, COMPARISON_OPS, type CatalogueEntry, EQUALITY_OPS, type EditCtx, type EditorEffect, type EffectsEditorHandle, type EffectsEditorOptions, type ExpressionEditorHandle, type ExpressionEditorOptions, type Filter, type FunctionTemplateSpec, type PreviewOptions, type TreeRow, UNARY_LABEL, type Validation, type ValueWizardOptions, type WizardSpec, type WizardStepSpec, type WizardValue, addArg, addChildToContainer, addEmit, addSet, astToTree, binary, boolLit, buildSubGroupClause, callNode, choicesOf, comparisonOpsFor, deleteAt, displayName, filterCatalogue, findEnumPeer, firstEmptyLeafPath, flagDelta, flipContainerOp, formatNumber, getNodeAt, groupByScope, initialValueFor, insertSiblingClauseAt, isComparisonOp, isPlaceholderForOp, isWrappedInNot, issuesAt, lookup, mountEffectsEditor, mountExpressionEditor, moveAt, moveChildInContainer, needsParens, notNode, numLit, opSwapGroup, pathKey, placeholderForOp, redirectDeleteForPlaceholderSibling, refOf, removeArgAt, removeAt, renderConditionPreview, renderEffectsPreview, rhsTypesFor, scopedVar, searchCatalogue, seedValueSrc, setArgAt, setNodeAt, strLit, toggleContainerNot, toggleNotAt, updateAt, validateSource, valueWizard, wrapInNotAt };
package/dist/index.js CHANGED
@@ -1348,7 +1348,9 @@ function valueWizard(opts) {
1348
1348
  host.append(head("Pick a value"));
1349
1349
  const body = el("div", "exed-vwiz-body");
1350
1350
  host.append(body);
1351
- let kind = opts.expectedType === "number" ? "number" : opts.expectedType === "string" ? "text" : opts.expectedType === "boolean" ? "bool" : opts.expectedType === "enum" && opts.expectedEnumValues?.length ? "enum" : "menu";
1351
+ const choices = opts.expectedChoices?.length ? opts.expectedChoices : opts.expectedEnumValues;
1352
+ const isStage = opts.expectedType === "quality";
1353
+ let kind = opts.expectedType === "number" ? "number" : opts.expectedType === "string" ? "text" : opts.expectedType === "boolean" ? "bool" : (opts.expectedType === "enum" || opts.expectedType === "quality") && choices?.length ? "enum" : "menu";
1352
1354
  const draw = () => {
1353
1355
  body.replaceChildren();
1354
1356
  const other = () => button("exed-vwiz-other", "\u21A9 a different kind", () => {
@@ -1373,7 +1375,7 @@ function valueWizard(opts) {
1373
1375
  kind = "bool";
1374
1376
  draw();
1375
1377
  }));
1376
- if (opts.expectedEnumValues?.length) body.append(optBtn("A listed value", () => {
1378
+ if (choices?.length) body.append(optBtn(isStage ? "A stage" : "A listed value", () => {
1377
1379
  kind = "enum";
1378
1380
  draw();
1379
1381
  }));
@@ -1397,7 +1399,8 @@ function valueWizard(opts) {
1397
1399
  break;
1398
1400
  }
1399
1401
  case "enum":
1400
- for (const v of opts.expectedEnumValues ?? []) body.append(optBtn(v, () => opts.onCommit(enumSrc(v))));
1402
+ body.append(el("div", "exed-vwiz-note", [isStage ? "Stages, in ladder order:" : ""]));
1403
+ for (const v of choices ?? []) body.append(optBtn(v, () => opts.onCommit(enumSrc(v))));
1401
1404
  body.append(other());
1402
1405
  break;
1403
1406
  }
@@ -1446,6 +1449,13 @@ function removeArgAt(list, i, argIdx) {
1446
1449
  cur.args.splice(argIdx, 1);
1447
1450
  return next;
1448
1451
  }
1452
+ function initialValueFor(entry, defaultScope) {
1453
+ const ref = refOf(entry, defaultScope);
1454
+ return {
1455
+ src: seedValueSrc(entry.type, choicesOf(entry), ref),
1456
+ ask: entry.type !== "quality"
1457
+ };
1458
+ }
1449
1459
  function seedValueSrc(type, values, ref) {
1450
1460
  switch (type) {
1451
1461
  case "boolean":
@@ -1485,7 +1495,9 @@ function mountEffectsEditor(host, opts) {
1485
1495
  scopeOrder: opts.scopeOrder ?? [],
1486
1496
  defaultScope,
1487
1497
  ...expected?.type ? { expectedType: expected.type } : {},
1488
- ...expected?.enumValues ? { expectedEnumValues: expected.enumValues } : {},
1498
+ // choicesOf, never a raw field: a quality's ladder lives in `stages`, and reading `enumValues`
1499
+ // here told the wizard the type and withheld the values.
1500
+ ...choicesOf(expected) ? { expectedChoices: choicesOf(expected) } : {},
1489
1501
  onCommit: (src) => {
1490
1502
  onCommit(src);
1491
1503
  close();
@@ -1553,8 +1565,7 @@ function mountEffectsEditor(host, opts) {
1553
1565
  const row = el("div", "exed-effect exed-effect-set");
1554
1566
  const targetBtn = button("exed-pill exed-pill-prop", eff.target || "(pick property)", (e) => {
1555
1567
  pickTarget(e.currentTarget, void 0, (entry) => {
1556
- const ref = refOf(entry, defaultScope);
1557
- commit(updateAt(effects, i, { target: ref, value: seedValueSrc(entry.type, choicesOf(entry), ref) }));
1568
+ commit(updateAt(effects, i, { target: refOf(entry, defaultScope), value: initialValueFor(entry, defaultScope).src }));
1558
1569
  });
1559
1570
  }, "change the target property");
1560
1571
  row.append(targetBtn, el("span", "exed-effect-eq", ["="]));
@@ -1640,7 +1651,14 @@ function mountEffectsEditor(host, opts) {
1640
1651
  const bar = el("div", "exed-effect-addbar");
1641
1652
  bar.append(button("exed-eff-add", "+ set property", (e) => {
1642
1653
  const anchor = e.currentTarget;
1643
- pickTarget(anchor, void 0, (entry) => openValueWizard(anchor, entry, (src) => commit(addSet(effects, refOf(entry, defaultScope), src))));
1654
+ pickTarget(anchor, void 0, (entry) => {
1655
+ const { src, ask } = initialValueFor(entry, defaultScope);
1656
+ if (!ask) {
1657
+ commit(addSet(effects, refOf(entry, defaultScope), src));
1658
+ return;
1659
+ }
1660
+ openValueWizard(anchor, entry, (chosen) => commit(addSet(effects, refOf(entry, defaultScope), chosen)));
1661
+ });
1644
1662
  }));
1645
1663
  if (opts.allowEmit !== false) {
1646
1664
  bar.append(button("exed-eff-add", "+ emit event", (e) => editEvent(e.currentTarget, "", (name) => commit(addEmit(effects, name)))));
@@ -1728,6 +1746,6 @@ function renderEffectsPreview(effects, o) {
1728
1746
  return wrap;
1729
1747
  }
1730
1748
 
1731
- export { ARITHMETIC_OPS, BINARY_LABEL, COMPARABLE_TYPES, COMPARISON_OPS, EQUALITY_OPS, UNARY_LABEL, addArg, addChildToContainer, addEmit, addSet, astToTree, binary, boolLit, buildSubGroupClause, callNode, choicesOf, comparisonOpsFor, deleteAt, displayName, filterCatalogue, findEnumPeer, firstEmptyLeafPath, flagDelta, flipContainerOp, formatNumber, getNodeAt, groupByScope, insertSiblingClauseAt, isComparisonOp, isPlaceholderForOp, isWrappedInNot, issuesAt, lookup, mountEffectsEditor, mountExpressionEditor, moveAt, moveChildInContainer, needsParens, notNode, numLit, opSwapGroup, pathKey, placeholderForOp, redirectDeleteForPlaceholderSibling, refOf, removeArgAt, removeAt, renderConditionPreview, renderEffectsPreview, rhsTypesFor, scopedVar, searchCatalogue, seedValueSrc, setArgAt, setNodeAt, strLit, toggleContainerNot, toggleNotAt, updateAt, validateSource, valueWizard, wrapInNotAt };
1749
+ export { ARITHMETIC_OPS, BINARY_LABEL, COMPARABLE_TYPES, COMPARISON_OPS, EQUALITY_OPS, UNARY_LABEL, addArg, addChildToContainer, addEmit, addSet, astToTree, binary, boolLit, buildSubGroupClause, callNode, choicesOf, comparisonOpsFor, deleteAt, displayName, filterCatalogue, findEnumPeer, firstEmptyLeafPath, flagDelta, flipContainerOp, formatNumber, getNodeAt, groupByScope, initialValueFor, insertSiblingClauseAt, isComparisonOp, isPlaceholderForOp, isWrappedInNot, issuesAt, lookup, mountEffectsEditor, mountExpressionEditor, moveAt, moveChildInContainer, needsParens, notNode, numLit, opSwapGroup, pathKey, placeholderForOp, redirectDeleteForPlaceholderSibling, refOf, removeArgAt, removeAt, renderConditionPreview, renderEffectsPreview, rhsTypesFor, scopedVar, searchCatalogue, seedValueSrc, setArgAt, setNodeAt, strLit, toggleContainerNot, toggleNotAt, updateAt, validateSource, valueWizard, wrapInNotAt };
1732
1750
  //# sourceMappingURL=index.js.map
1733
1751
  //# sourceMappingURL=index.js.map