@wildwinter/expr-editor 0.14.0 → 0.15.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/dist/index.cjs +66 -25
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +25 -2
- package/dist/index.d.ts +25 -2
- package/dist/index.js +65 -26
- package/dist/index.js.map +1 -1
- package/dist/styles.css +2 -1
- package/dist/styles.css.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -98,6 +98,7 @@ var normaliseRef = (ref, defaultScope) => {
|
|
|
98
98
|
const prefix = `@${defaultScope.toLowerCase()}.`;
|
|
99
99
|
return low.startsWith(prefix) ? `@${low.slice(prefix.length)}` : low;
|
|
100
100
|
};
|
|
101
|
+
var flagChangeSrc = (targetRef, sign, flag) => `set_flags(${targetRef}, ${sign}${flag})`;
|
|
101
102
|
function advancedRef(node, defaultScope) {
|
|
102
103
|
if (node.kind !== "call" || node.name !== "advance" || node.args.length !== 1) return null;
|
|
103
104
|
const arg = node.args[0];
|
|
@@ -296,6 +297,7 @@ var propertyTip = (e) => {
|
|
|
296
297
|
return lines.length ? lines.join("\n") : void 0;
|
|
297
298
|
};
|
|
298
299
|
var refOf = (e, defaultScope) => e.scope === defaultScope ? `@${e.name}` : `@${e.scope}.${e.name}`;
|
|
300
|
+
var targetRefOf = (e) => `@${e.scope}.${e.name}`;
|
|
299
301
|
var displayName = (e, defaultScope) => e.scope === defaultScope ? e.name : `${e.scope}.${e.name}`;
|
|
300
302
|
function filterCatalogue(entries, filter = {}) {
|
|
301
303
|
return entries.filter(
|
|
@@ -429,6 +431,14 @@ function textField(opts) {
|
|
|
429
431
|
setTimeout(() => input.focus(), 0);
|
|
430
432
|
return wrap;
|
|
431
433
|
}
|
|
434
|
+
function propertyMenuBody(actions, close) {
|
|
435
|
+
const wrap = el("div", "exed-menu");
|
|
436
|
+
for (const a of actions) wrap.append(button("exed-opt", a.label, () => {
|
|
437
|
+
a.run();
|
|
438
|
+
close();
|
|
439
|
+
}));
|
|
440
|
+
return wrap;
|
|
441
|
+
}
|
|
432
442
|
|
|
433
443
|
// src/flat.ts
|
|
434
444
|
var FLAG_FNS = /* @__PURE__ */ new Set(["check_flags", "set_flags"]);
|
|
@@ -547,14 +557,7 @@ function attachPropertyMenu(ctx, node, pillEl) {
|
|
|
547
557
|
const open = ctx.openMenu ?? ctx.openPopover;
|
|
548
558
|
pillEl.addEventListener("contextmenu", (e) => {
|
|
549
559
|
e.preventDefault();
|
|
550
|
-
open(pillEl, (close) =>
|
|
551
|
-
const wrap = el("div", "exed-menu");
|
|
552
|
-
for (const a of actions) wrap.append(button("exed-opt", a.label, () => {
|
|
553
|
-
a.run();
|
|
554
|
-
close();
|
|
555
|
-
}));
|
|
556
|
-
return wrap;
|
|
557
|
-
});
|
|
560
|
+
open(pillEl, (close) => propertyMenuBody(actions, close));
|
|
558
561
|
});
|
|
559
562
|
}
|
|
560
563
|
function isCompoundComparison(node, ctx) {
|
|
@@ -1083,7 +1086,7 @@ function seedClause(ctx) {
|
|
|
1083
1086
|
function clauseMenu(ctx, anchor, onPick) {
|
|
1084
1087
|
ctx.openPopover(anchor, (close) => {
|
|
1085
1088
|
const wrap = el("div", "exed-menu");
|
|
1086
|
-
wrap.append(el("div", "exed-menu-head", ["Add a
|
|
1089
|
+
wrap.append(el("div", "exed-menu-head", ["Add a condition"]));
|
|
1087
1090
|
const add = (label, hint, make, disabled = false) => {
|
|
1088
1091
|
const b = button(`exed-opt${disabled ? " disabled" : ""}`, "", () => {
|
|
1089
1092
|
if (disabled) return;
|
|
@@ -1382,7 +1385,8 @@ function valueWizard(opts) {
|
|
|
1382
1385
|
host.append(body);
|
|
1383
1386
|
const choices = opts.expectedChoices?.length ? opts.expectedChoices : opts.expectedEnumValues;
|
|
1384
1387
|
const isStage = opts.expectedType === "quality";
|
|
1385
|
-
|
|
1388
|
+
const flagsReady = opts.expectedType === "flags" && opts.expectedRef !== void 0;
|
|
1389
|
+
let kind = opts.expectedType === "number" ? "number" : opts.expectedType === "string" ? "text" : opts.expectedType === "boolean" ? "bool" : (opts.expectedType === "enum" || opts.expectedType === "quality") && choices?.length ? "enum" : flagsReady ? "flags" : "menu";
|
|
1386
1390
|
const draw = () => {
|
|
1387
1391
|
body.replaceChildren();
|
|
1388
1392
|
const other = () => button("exed-vwiz-other", "\u21A9 a different kind", () => {
|
|
@@ -1391,6 +1395,10 @@ function valueWizard(opts) {
|
|
|
1391
1395
|
});
|
|
1392
1396
|
switch (kind) {
|
|
1393
1397
|
case "menu":
|
|
1398
|
+
if (flagsReady) body.append(optBtn("Set or clear a flag\u2026", () => {
|
|
1399
|
+
kind = "flags";
|
|
1400
|
+
draw();
|
|
1401
|
+
}));
|
|
1394
1402
|
body.append(optBtn("A property\u2026", () => {
|
|
1395
1403
|
kind = "property";
|
|
1396
1404
|
draw();
|
|
@@ -1412,6 +1420,22 @@ function valueWizard(opts) {
|
|
|
1412
1420
|
draw();
|
|
1413
1421
|
}));
|
|
1414
1422
|
break;
|
|
1423
|
+
case "flags": {
|
|
1424
|
+
const flags = opts.expectedFlags ?? [];
|
|
1425
|
+
if (!flags.length) body.append(el("div", "exed-hint", ["This property declares no flag values yet."]));
|
|
1426
|
+
for (const sign of ["+", "-"]) {
|
|
1427
|
+
if (!flags.length) break;
|
|
1428
|
+
body.append(el("div", "exed-vwiz-note", [sign === "+" ? "Set a flag:" : "Clear a flag:"]));
|
|
1429
|
+
const row = el("div", "exed-field-row");
|
|
1430
|
+
for (const f of flags) row.append(optBtn(`${sign} ${f}`, () => opts.onCommit(flagChangeSrc(opts.expectedRef, sign, f))));
|
|
1431
|
+
body.append(row);
|
|
1432
|
+
}
|
|
1433
|
+
body.append(button("exed-vwiz-other", "\u21A9 a different kind (replaces every flag)", () => {
|
|
1434
|
+
kind = "menu";
|
|
1435
|
+
draw();
|
|
1436
|
+
}));
|
|
1437
|
+
break;
|
|
1438
|
+
}
|
|
1415
1439
|
case "property":
|
|
1416
1440
|
body.append(propertyPicker(pickCtx, { onPick: (e) => opts.onCommit(refOf(e, opts.defaultScope)) }));
|
|
1417
1441
|
body.append(other());
|
|
@@ -1450,6 +1474,10 @@ function isSelfAdvance(eff, defaultScope, dialect) {
|
|
|
1450
1474
|
return false;
|
|
1451
1475
|
}
|
|
1452
1476
|
}
|
|
1477
|
+
function entryForTarget(catalogue, target, defaultScope) {
|
|
1478
|
+
const want = normaliseRef(target, defaultScope);
|
|
1479
|
+
return catalogue.find((e) => normaliseRef(`@${e.scope}.${e.name}`, defaultScope) === want);
|
|
1480
|
+
}
|
|
1453
1481
|
var clone = (list) => list.map((e) => e.kind === "set" ? { ...e } : { ...e, args: [...e.args] });
|
|
1454
1482
|
var addSet = (list, target, value) => [...clone(list), { kind: "set", target, value }];
|
|
1455
1483
|
var addEmit = (list, event) => [...clone(list), { kind: "emit", event, args: [] }];
|
|
@@ -1538,6 +1566,11 @@ function mountEffectsEditor(host, opts) {
|
|
|
1538
1566
|
// choicesOf, never a raw field: a quality's ladder lives in `stages`, and reading `enumValues`
|
|
1539
1567
|
// here told the wizard the type and withheld the values.
|
|
1540
1568
|
...choicesOf(expected) ? { expectedChoices: choicesOf(expected) } : {},
|
|
1569
|
+
// The flags step needs the target itself: its declared flags, and the
|
|
1570
|
+
// qualified ref its set_flags(...) is written against. choicesOf stays
|
|
1571
|
+
// out of it deliberately - flags are not a pick-one list, and a pinned
|
|
1572
|
+
// test holds it to that.
|
|
1573
|
+
...expected?.type === "flags" ? { expectedRef: targetRefOf(expected), expectedFlags: expected.enumValues ?? [] } : {},
|
|
1541
1574
|
onCommit: (src) => {
|
|
1542
1575
|
onCommit(src);
|
|
1543
1576
|
close();
|
|
@@ -1545,7 +1578,7 @@ function mountEffectsEditor(host, opts) {
|
|
|
1545
1578
|
onCancel: close
|
|
1546
1579
|
}), { container: opts.popoverContainer });
|
|
1547
1580
|
};
|
|
1548
|
-
const targetType = (target) => opts.catalogue
|
|
1581
|
+
const targetType = (target) => entryForTarget(opts.catalogue, target, defaultScope)?.type;
|
|
1549
1582
|
const valueDisplay = (value, onChange, type, selfAdvanceRef) => {
|
|
1550
1583
|
const sub = el("div", "exed-effect-value");
|
|
1551
1584
|
const addTerm = type === "number" ? "arithmetic" : type === "boolean" ? "boolean" : void 0;
|
|
@@ -1612,10 +1645,10 @@ function mountEffectsEditor(host, opts) {
|
|
|
1612
1645
|
const row = el("div", "exed-effect exed-effect-set");
|
|
1613
1646
|
const targetBtn = button("exed-pill exed-pill-prop", eff.target || "(pick property)", (e) => {
|
|
1614
1647
|
pickTarget(e.currentTarget, void 0, (entry) => {
|
|
1615
|
-
commit(updateAt(effects, i, { target:
|
|
1648
|
+
commit(updateAt(effects, i, { target: targetRefOf(entry), value: initialValueFor(entry, defaultScope).src }));
|
|
1616
1649
|
});
|
|
1617
1650
|
}, "change the target property");
|
|
1618
|
-
const targetEntry = opts.catalogue
|
|
1651
|
+
const targetEntry = entryForTarget(opts.catalogue, eff.target, defaultScope);
|
|
1619
1652
|
const tip = propertyTip(targetEntry);
|
|
1620
1653
|
if (tip) targetBtn.title = tip;
|
|
1621
1654
|
if (targetEntry && opts.propertyActions) {
|
|
@@ -1623,14 +1656,7 @@ function mountEffectsEditor(host, opts) {
|
|
|
1623
1656
|
if (actions.length) targetBtn.addEventListener("contextmenu", (e) => {
|
|
1624
1657
|
e.preventDefault();
|
|
1625
1658
|
closePopover();
|
|
1626
|
-
popover = openPopover(targetBtn, (close) => {
|
|
1627
|
-
const wrap = el("div", "exed-menu");
|
|
1628
|
-
for (const a of actions) wrap.append(button("exed-opt", a.label, () => {
|
|
1629
|
-
a.run();
|
|
1630
|
-
close();
|
|
1631
|
-
}));
|
|
1632
|
-
return wrap;
|
|
1633
|
-
}, { container: opts.popoverContainer });
|
|
1659
|
+
popover = openPopover(targetBtn, (close) => propertyMenuBody(actions, close), { container: opts.popoverContainer });
|
|
1634
1660
|
});
|
|
1635
1661
|
}
|
|
1636
1662
|
const advances = isSelfAdvance(eff, defaultScope, opts.dialect);
|
|
@@ -1726,10 +1752,10 @@ function mountEffectsEditor(host, opts) {
|
|
|
1726
1752
|
pickTarget(anchor, void 0, (entry) => {
|
|
1727
1753
|
const { src, ask } = initialValueFor(entry, defaultScope);
|
|
1728
1754
|
if (!ask) {
|
|
1729
|
-
commit(addSet(effects,
|
|
1755
|
+
commit(addSet(effects, targetRefOf(entry), src));
|
|
1730
1756
|
return;
|
|
1731
1757
|
}
|
|
1732
|
-
openValueWizard(anchor, entry, (chosen) => commit(addSet(effects,
|
|
1758
|
+
openValueWizard(anchor, entry, (chosen) => commit(addSet(effects, targetRefOf(entry), chosen)));
|
|
1733
1759
|
});
|
|
1734
1760
|
}));
|
|
1735
1761
|
if (opts.allowEmit !== false) {
|
|
@@ -1796,13 +1822,26 @@ function renderConditionPreview(src, o) {
|
|
|
1796
1822
|
const cls = o.propertyActions ? "exed-preview exed-preview-interactive" : "exed-preview";
|
|
1797
1823
|
return el("div", cls, [exprPills(src, o)]);
|
|
1798
1824
|
}
|
|
1825
|
+
function targetPill(ref, o) {
|
|
1826
|
+
const pill2 = el("span", "exed-pill exed-pill-prop", [ref || "(property)"]);
|
|
1827
|
+
const entry = o.catalogue.find((e) => refOf(e, o.dialect.defaultScope) === ref);
|
|
1828
|
+
if (!entry) return pill2;
|
|
1829
|
+
const tip = propertyTip(entry);
|
|
1830
|
+
if (tip) pill2.title = tip;
|
|
1831
|
+
const actions = o.propertyActions?.({ scope: entry.scope, name: entry.name }) ?? [];
|
|
1832
|
+
if (actions.length) pill2.addEventListener("contextmenu", (e) => {
|
|
1833
|
+
e.preventDefault();
|
|
1834
|
+
openPopover(pill2, (close) => propertyMenuBody(actions, close), { container: o.popoverContainer });
|
|
1835
|
+
});
|
|
1836
|
+
return pill2;
|
|
1837
|
+
}
|
|
1799
1838
|
function renderEffectsPreview(effects, o) {
|
|
1800
|
-
const wrap = el("div",
|
|
1839
|
+
const wrap = el("div", `exed-preview exed-preview-effects${o.propertyActions ? " exed-preview-interactive" : ""}`);
|
|
1801
1840
|
for (const eff of effects) {
|
|
1802
1841
|
const row = el("div", "exed-preview-eff");
|
|
1803
1842
|
if (eff.kind === "set") {
|
|
1804
1843
|
const advances = isSelfAdvance(eff, o.dialect.defaultScope, o.dialect);
|
|
1805
|
-
row.append(
|
|
1844
|
+
row.append(targetPill(eff.target, o));
|
|
1806
1845
|
if (!advances) row.append(el("span", "exed-effect-eq", ["="]));
|
|
1807
1846
|
row.append(exprPills(eff.value, o, advances ? eff.target : void 0));
|
|
1808
1847
|
} else {
|
|
@@ -1845,6 +1884,7 @@ exports.filterCatalogue = filterCatalogue;
|
|
|
1845
1884
|
exports.findChoicePeer = findChoicePeer;
|
|
1846
1885
|
exports.findEnumPeer = findEnumPeer;
|
|
1847
1886
|
exports.firstEmptyLeafPath = firstEmptyLeafPath;
|
|
1887
|
+
exports.flagChangeSrc = flagChangeSrc;
|
|
1848
1888
|
exports.flagDelta = flagDelta;
|
|
1849
1889
|
exports.flipContainerOp = flipContainerOp;
|
|
1850
1890
|
exports.formatNumber = formatNumber;
|
|
@@ -1882,6 +1922,7 @@ exports.seedValueSrc = seedValueSrc;
|
|
|
1882
1922
|
exports.setArgAt = setArgAt;
|
|
1883
1923
|
exports.setNodeAt = setNodeAt;
|
|
1884
1924
|
exports.strLit = strLit;
|
|
1925
|
+
exports.targetRefOf = targetRefOf;
|
|
1885
1926
|
exports.toggleContainerNot = toggleContainerNot;
|
|
1886
1927
|
exports.toggleNotAt = toggleNotAt;
|
|
1887
1928
|
exports.updateAt = updateAt;
|