@wildwinter/expr-editor 0.10.3 → 0.11.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.
- package/README.md +8 -0
- package/dist/index.cjs +34 -13
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +36 -4
- package/dist/index.d.ts +36 -4
- package/dist/index.js +30 -14
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -35,6 +35,14 @@ Notable options beyond the basics:
|
|
|
35
35
|
multi-step flow (e.g. tag → operator → threshold) with no editor changes.
|
|
36
36
|
Templates without a wizard insert-then-refine: the editor auto-opens the
|
|
37
37
|
first unfilled slot of the inserted clause.
|
|
38
|
+
- **Qualities** (the `quality` property type) need nothing from the host beyond a
|
|
39
|
+
catalogue entry carrying `stages` — the ladder, in order. The editor then offers
|
|
40
|
+
the property in a comparison clause, gives it the **ordering** operators (a
|
|
41
|
+
ladder exists for "at or past a stage"), lists its stages wherever a value is
|
|
42
|
+
picked, labels that list "stage", and seeds an outcome on it with
|
|
43
|
+
`advance(@ref)` — the form that keeps a story insertion-safe, because it names
|
|
44
|
+
no destination. A host still passing a ladder through `enumValues` keeps its
|
|
45
|
+
value picker, but not the ordering affordances.
|
|
38
46
|
- `onEditingChange(editing)` — fires as popover micro-editors open/close, so the
|
|
39
47
|
host can suppress its own validation display mid-edit.
|
|
40
48
|
- `messages: false` — hide the editor's internal validation list when the host
|
package/dist/index.cjs
CHANGED
|
@@ -222,6 +222,10 @@ var BINARY_LABEL = {
|
|
|
222
222
|
var UNARY_LABEL = { not: "NOT", neg: "\u2212" };
|
|
223
223
|
var COMPARISON_OPS = ["==", "!=", ">", ">=", "<", "<="];
|
|
224
224
|
var ARITHMETIC_OPS = ["+", "-", "*", "/"];
|
|
225
|
+
var COMPARABLE_TYPES = ["boolean", "number", "string", "enum", "quality"];
|
|
226
|
+
var comparisonOpsFor = (t) => t === "number" || t === "quality" ? COMPARISON_OPS : EQUALITY_OPS;
|
|
227
|
+
var EQUALITY_OPS = ["==", "!="];
|
|
228
|
+
var rhsTypesFor = (t) => t === "number" ? ["number"] : t === "boolean" ? ["boolean"] : t === "quality" ? ["quality"] : t === "enum" ? ["enum", "string"] : ["string", "enum"];
|
|
225
229
|
function opSwapGroup(op) {
|
|
226
230
|
if (COMPARISON_OPS.includes(op)) return COMPARISON_OPS;
|
|
227
231
|
if (ARITHMETIC_OPS.includes(op)) return ARITHMETIC_OPS;
|
|
@@ -251,6 +255,12 @@ function formatNumber(n) {
|
|
|
251
255
|
}
|
|
252
256
|
|
|
253
257
|
// src/schema.ts
|
|
258
|
+
var choicesOf = (e) => {
|
|
259
|
+
if (!e) return void 0;
|
|
260
|
+
if (e.type === "quality") return e.stages?.length ? e.stages : e.enumValues;
|
|
261
|
+
if (e.type === "enum") return e.enumValues;
|
|
262
|
+
return void 0;
|
|
263
|
+
};
|
|
254
264
|
var refOf = (e, defaultScope) => e.scope === defaultScope ? `@${e.name}` : `@${e.scope}.${e.name}`;
|
|
255
265
|
var displayName = (e, defaultScope) => e.scope === defaultScope ? e.name : `${e.scope}.${e.name}`;
|
|
256
266
|
function filterCatalogue(entries, filter = {}) {
|
|
@@ -554,8 +564,9 @@ function stringEditor(ctx, path, node, anchor) {
|
|
|
554
564
|
const peer = findEnumPeer(ctx.getAst(), path);
|
|
555
565
|
const enumEntry = peer ? lookup(ctx.catalogue, peer.scope, peer.name) : null;
|
|
556
566
|
const rootValueEnums = path.length === 0 && ctx.valueEnumValues?.length ? ctx.valueEnumValues : null;
|
|
557
|
-
const
|
|
558
|
-
const
|
|
567
|
+
const peerChoices = choicesOf(enumEntry);
|
|
568
|
+
const enumValues = peerChoices?.length ? peerChoices : rootValueEnums;
|
|
569
|
+
const enumHeadLabel = enumEntry ? `${displayName(enumEntry, ctx.defaultScope)} ${enumEntry.type === "quality" ? "stage" : "value"}` : "Value";
|
|
559
570
|
ctx.openPopover(anchor, (close) => {
|
|
560
571
|
if (enumValues?.length) {
|
|
561
572
|
const wrap = el("div", "exed-menu");
|
|
@@ -705,7 +716,6 @@ function propertyPicker(ctx, opts) {
|
|
|
705
716
|
}
|
|
706
717
|
|
|
707
718
|
// src/clausewizard.ts
|
|
708
|
-
var EQUALITY = ["==", "!="];
|
|
709
719
|
var OP_WORD = {
|
|
710
720
|
"==": "equals",
|
|
711
721
|
"!=": "not equal to",
|
|
@@ -719,8 +729,6 @@ var opButton = (o, onClick) => {
|
|
|
719
729
|
b.append(el("span", "exed-opt-name", [BINARY_LABEL[o]]), el("span", "exed-opt-purpose", [OP_WORD[o] ?? ""]));
|
|
720
730
|
return b;
|
|
721
731
|
};
|
|
722
|
-
var opsForType = (t) => t === "number" ? COMPARISON_OPS : EQUALITY;
|
|
723
|
-
var rhsTypesFor = (t) => t === "number" ? ["number"] : t === "boolean" ? ["boolean"] : t === "enum" ? ["enum", "string"] : ["string", "enum"];
|
|
724
732
|
function header(host, title, back, cancel) {
|
|
725
733
|
const h = el("div", "exed-vwiz-head");
|
|
726
734
|
if (back) h.append(button("exed-vwiz-back", "\u2190", back, "Back"));
|
|
@@ -751,8 +759,8 @@ function valueStep(host, w, lhs, op, back, cancel, commit) {
|
|
|
751
759
|
const row = el("div", "exed-field-row");
|
|
752
760
|
row.append(button("exed-opt", "true", () => done(boolLit(true))), button("exed-opt", "false", () => done(boolLit(false))));
|
|
753
761
|
body.append(row);
|
|
754
|
-
} else if (lhs
|
|
755
|
-
for (const v of lhs
|
|
762
|
+
} else if (choicesOf(lhs)?.length) {
|
|
763
|
+
for (const v of choicesOf(lhs)) body.append(button("exed-opt", v, () => done(strLit(v))));
|
|
756
764
|
} else if (lhs.type === "number") {
|
|
757
765
|
body.append(textField({ caption: "Number", placeholder: "e.g. 3", validate: (v) => v.trim() !== "" && Number.isFinite(Number(v)), onCommit: (v) => done(numLit(Number(v))) }));
|
|
758
766
|
} else {
|
|
@@ -774,8 +782,13 @@ function comparisonWizard(host, w, commit, cancel) {
|
|
|
774
782
|
const body = el("div", "exed-vwiz-body");
|
|
775
783
|
host.append(body);
|
|
776
784
|
body.append(propertyPicker(pickCtxOf(w), {
|
|
777
|
-
accept:
|
|
778
|
-
onPick: (e) => pickOp({
|
|
785
|
+
accept: COMPARABLE_TYPES,
|
|
786
|
+
onPick: (e) => pickOp({
|
|
787
|
+
ref: refDisplay(w, e),
|
|
788
|
+
type: e.type,
|
|
789
|
+
...e.enumValues ? { enumValues: e.enumValues } : {},
|
|
790
|
+
...e.stages ? { stages: e.stages } : {}
|
|
791
|
+
})
|
|
779
792
|
}));
|
|
780
793
|
};
|
|
781
794
|
const pickOp = (lhs) => {
|
|
@@ -783,7 +796,7 @@ function comparisonWizard(host, w, commit, cancel) {
|
|
|
783
796
|
header(host, el("span", void 0, ["Operator for ", mono(lhs.ref)]), pickLhs, cancel);
|
|
784
797
|
const body = el("div", "exed-vwiz-body");
|
|
785
798
|
host.append(body);
|
|
786
|
-
for (const o of
|
|
799
|
+
for (const o of comparisonOpsFor(lhs.type)) {
|
|
787
800
|
body.append(opButton(o, () => valueStep(host, w, lhs, o, () => pickOp(lhs), cancel, commit)));
|
|
788
801
|
}
|
|
789
802
|
};
|
|
@@ -1435,14 +1448,16 @@ function removeArgAt(list, i, argIdx) {
|
|
|
1435
1448
|
cur.args.splice(argIdx, 1);
|
|
1436
1449
|
return next;
|
|
1437
1450
|
}
|
|
1438
|
-
function seedValueSrc(type,
|
|
1451
|
+
function seedValueSrc(type, values, ref) {
|
|
1439
1452
|
switch (type) {
|
|
1440
1453
|
case "boolean":
|
|
1441
1454
|
return "true";
|
|
1442
1455
|
case "number":
|
|
1443
1456
|
return "0";
|
|
1444
1457
|
case "enum":
|
|
1445
|
-
return JSON.stringify(
|
|
1458
|
+
return JSON.stringify(values?.[0] ?? "");
|
|
1459
|
+
case "quality":
|
|
1460
|
+
return ref ? `advance(${ref})` : JSON.stringify(values?.[0] ?? "");
|
|
1446
1461
|
case "string":
|
|
1447
1462
|
return '""';
|
|
1448
1463
|
default:
|
|
@@ -1540,7 +1555,8 @@ function mountEffectsEditor(host, opts) {
|
|
|
1540
1555
|
const row = el("div", "exed-effect exed-effect-set");
|
|
1541
1556
|
const targetBtn = button("exed-pill exed-pill-prop", eff.target || "(pick property)", (e) => {
|
|
1542
1557
|
pickTarget(e.currentTarget, void 0, (entry) => {
|
|
1543
|
-
|
|
1558
|
+
const ref = refOf(entry, defaultScope);
|
|
1559
|
+
commit(updateAt(effects, i, { target: ref, value: seedValueSrc(entry.type, choicesOf(entry), ref) }));
|
|
1544
1560
|
});
|
|
1545
1561
|
}, "change the target property");
|
|
1546
1562
|
row.append(targetBtn, el("span", "exed-effect-eq", ["="]));
|
|
@@ -1716,7 +1732,9 @@ function renderEffectsPreview(effects, o) {
|
|
|
1716
1732
|
|
|
1717
1733
|
exports.ARITHMETIC_OPS = ARITHMETIC_OPS;
|
|
1718
1734
|
exports.BINARY_LABEL = BINARY_LABEL;
|
|
1735
|
+
exports.COMPARABLE_TYPES = COMPARABLE_TYPES;
|
|
1719
1736
|
exports.COMPARISON_OPS = COMPARISON_OPS;
|
|
1737
|
+
exports.EQUALITY_OPS = EQUALITY_OPS;
|
|
1720
1738
|
exports.UNARY_LABEL = UNARY_LABEL;
|
|
1721
1739
|
exports.addArg = addArg;
|
|
1722
1740
|
exports.addChildToContainer = addChildToContainer;
|
|
@@ -1727,6 +1745,8 @@ exports.binary = binary;
|
|
|
1727
1745
|
exports.boolLit = boolLit;
|
|
1728
1746
|
exports.buildSubGroupClause = buildSubGroupClause;
|
|
1729
1747
|
exports.callNode = callNode;
|
|
1748
|
+
exports.choicesOf = choicesOf;
|
|
1749
|
+
exports.comparisonOpsFor = comparisonOpsFor;
|
|
1730
1750
|
exports.deleteAt = deleteAt;
|
|
1731
1751
|
exports.displayName = displayName;
|
|
1732
1752
|
exports.filterCatalogue = filterCatalogue;
|
|
@@ -1759,6 +1779,7 @@ exports.removeArgAt = removeArgAt;
|
|
|
1759
1779
|
exports.removeAt = removeAt;
|
|
1760
1780
|
exports.renderConditionPreview = renderConditionPreview;
|
|
1761
1781
|
exports.renderEffectsPreview = renderEffectsPreview;
|
|
1782
|
+
exports.rhsTypesFor = rhsTypesFor;
|
|
1762
1783
|
exports.scopedVar = scopedVar;
|
|
1763
1784
|
exports.searchCatalogue = searchCatalogue;
|
|
1764
1785
|
exports.seedValueSrc = seedValueSrc;
|