@wildwinter/expr-editor 0.13.1 → 0.14.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.cjs +50 -11
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +21 -1
- package/dist/index.d.ts +21 -1
- package/dist/index.js +50 -12
- 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.d.cts
CHANGED
|
@@ -169,6 +169,16 @@ declare const choicesOf: (e: {
|
|
|
169
169
|
enumValues?: string[];
|
|
170
170
|
stages?: string[];
|
|
171
171
|
} | null | undefined) => string[] | undefined;
|
|
172
|
+
/** What a property PILL says on rollover: the purpose, and for a quality its
|
|
173
|
+
* ladder (the one thing about a property whose order matters and which the
|
|
174
|
+
* use site cannot otherwise show). The picker already displays purposes; this
|
|
175
|
+
* is for the place an author actually meets a property, mid-expression.
|
|
176
|
+
* Pure, so hosts and tests share one answer; the pill wires it as its title. */
|
|
177
|
+
declare const propertyTip: (e: {
|
|
178
|
+
type: PropertyType;
|
|
179
|
+
purpose?: string;
|
|
180
|
+
stages?: string[];
|
|
181
|
+
} | null | undefined) => string | undefined;
|
|
172
182
|
interface Filter {
|
|
173
183
|
acceptTypes?: PropertyType[];
|
|
174
184
|
acceptScopes?: string[];
|
|
@@ -426,6 +436,16 @@ interface EffectsEditorOptions {
|
|
|
426
436
|
* inside a focus-trapping dialog so popovers do not dismiss it. Threaded to the
|
|
427
437
|
* target/event pickers here and to every inline value editor. */
|
|
428
438
|
popoverContainer?: HTMLElement;
|
|
439
|
+
/** Host actions for a property pill, shown on right-click (e.g. go to
|
|
440
|
+
* definition). Threaded to every inline value editor, and honoured by the
|
|
441
|
+
* set rows' own target pills (resolved via the catalogue). */
|
|
442
|
+
propertyActions?(ref: {
|
|
443
|
+
scope: string;
|
|
444
|
+
name: string;
|
|
445
|
+
}): Array<{
|
|
446
|
+
label: string;
|
|
447
|
+
run: () => void;
|
|
448
|
+
}>;
|
|
429
449
|
/** Emitted on every structural / value edit with the whole new list. */
|
|
430
450
|
onChange: (effects: EditorEffect[]) => void;
|
|
431
451
|
}
|
|
@@ -517,4 +537,4 @@ interface ValueWizardOptions {
|
|
|
517
537
|
/** Build the wizard UI into a fresh element (drive it via the host's popover). */
|
|
518
538
|
declare function valueWizard(opts: ValueWizardOptions): HTMLElement;
|
|
519
539
|
|
|
520
|
-
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, OP_WORD, type PreviewOptions, type TreeRow, UNARY_LABEL, type Validation, type ValueWizardOptions, type WizardSpec, type WizardStepSpec, type WizardValue, addArg, addChildToContainer, addEmit, addSet, advancedRef, astToTree, binary, boolLit, buildSubGroupClause, callNode, choicesOf, comparisonOpsFor, deleteAt, displayName, filterCatalogue, findChoicePeer, findEnumPeer, firstEmptyLeafPath, flagDelta, flipContainerOp, formatNumber, getNodeAt, groupByScope, initialValueFor, insertSiblingClauseAt, isComparisonOp, isPlaceholderForOp, isWrappedInNot, issuesAt, lookup, mountEffectsEditor, mountExpressionEditor, moveAt, moveChildInContainer, needsParens, normaliseRef, notNode, numLit, opSwapGroup, pathKey, placeholderForOp, redirectDeleteForPlaceholderSibling, refOf, removeArgAt, removeAt, renderConditionPreview, renderEffectsPreview, rhsTypesFor, scopedVar, searchCatalogue, seedValueSrc, setArgAt, setNodeAt, strLit, toggleContainerNot, toggleNotAt, updateAt, validateSource, valueWizard, wrapInNotAt };
|
|
540
|
+
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, OP_WORD, type PreviewOptions, type TreeRow, UNARY_LABEL, type Validation, type ValueWizardOptions, type WizardSpec, type WizardStepSpec, type WizardValue, addArg, addChildToContainer, addEmit, addSet, advancedRef, astToTree, binary, boolLit, buildSubGroupClause, callNode, choicesOf, comparisonOpsFor, deleteAt, displayName, filterCatalogue, findChoicePeer, findEnumPeer, firstEmptyLeafPath, flagDelta, flipContainerOp, formatNumber, getNodeAt, groupByScope, initialValueFor, insertSiblingClauseAt, isComparisonOp, isPlaceholderForOp, isWrappedInNot, issuesAt, lookup, mountEffectsEditor, mountExpressionEditor, moveAt, moveChildInContainer, needsParens, normaliseRef, notNode, numLit, opSwapGroup, pathKey, placeholderForOp, propertyTip, 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
|
@@ -169,6 +169,16 @@ declare const choicesOf: (e: {
|
|
|
169
169
|
enumValues?: string[];
|
|
170
170
|
stages?: string[];
|
|
171
171
|
} | null | undefined) => string[] | undefined;
|
|
172
|
+
/** What a property PILL says on rollover: the purpose, and for a quality its
|
|
173
|
+
* ladder (the one thing about a property whose order matters and which the
|
|
174
|
+
* use site cannot otherwise show). The picker already displays purposes; this
|
|
175
|
+
* is for the place an author actually meets a property, mid-expression.
|
|
176
|
+
* Pure, so hosts and tests share one answer; the pill wires it as its title. */
|
|
177
|
+
declare const propertyTip: (e: {
|
|
178
|
+
type: PropertyType;
|
|
179
|
+
purpose?: string;
|
|
180
|
+
stages?: string[];
|
|
181
|
+
} | null | undefined) => string | undefined;
|
|
172
182
|
interface Filter {
|
|
173
183
|
acceptTypes?: PropertyType[];
|
|
174
184
|
acceptScopes?: string[];
|
|
@@ -426,6 +436,16 @@ interface EffectsEditorOptions {
|
|
|
426
436
|
* inside a focus-trapping dialog so popovers do not dismiss it. Threaded to the
|
|
427
437
|
* target/event pickers here and to every inline value editor. */
|
|
428
438
|
popoverContainer?: HTMLElement;
|
|
439
|
+
/** Host actions for a property pill, shown on right-click (e.g. go to
|
|
440
|
+
* definition). Threaded to every inline value editor, and honoured by the
|
|
441
|
+
* set rows' own target pills (resolved via the catalogue). */
|
|
442
|
+
propertyActions?(ref: {
|
|
443
|
+
scope: string;
|
|
444
|
+
name: string;
|
|
445
|
+
}): Array<{
|
|
446
|
+
label: string;
|
|
447
|
+
run: () => void;
|
|
448
|
+
}>;
|
|
429
449
|
/** Emitted on every structural / value edit with the whole new list. */
|
|
430
450
|
onChange: (effects: EditorEffect[]) => void;
|
|
431
451
|
}
|
|
@@ -517,4 +537,4 @@ interface ValueWizardOptions {
|
|
|
517
537
|
/** Build the wizard UI into a fresh element (drive it via the host's popover). */
|
|
518
538
|
declare function valueWizard(opts: ValueWizardOptions): HTMLElement;
|
|
519
539
|
|
|
520
|
-
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, OP_WORD, type PreviewOptions, type TreeRow, UNARY_LABEL, type Validation, type ValueWizardOptions, type WizardSpec, type WizardStepSpec, type WizardValue, addArg, addChildToContainer, addEmit, addSet, advancedRef, astToTree, binary, boolLit, buildSubGroupClause, callNode, choicesOf, comparisonOpsFor, deleteAt, displayName, filterCatalogue, findChoicePeer, findEnumPeer, firstEmptyLeafPath, flagDelta, flipContainerOp, formatNumber, getNodeAt, groupByScope, initialValueFor, insertSiblingClauseAt, isComparisonOp, isPlaceholderForOp, isWrappedInNot, issuesAt, lookup, mountEffectsEditor, mountExpressionEditor, moveAt, moveChildInContainer, needsParens, normaliseRef, notNode, numLit, opSwapGroup, pathKey, placeholderForOp, redirectDeleteForPlaceholderSibling, refOf, removeArgAt, removeAt, renderConditionPreview, renderEffectsPreview, rhsTypesFor, scopedVar, searchCatalogue, seedValueSrc, setArgAt, setNodeAt, strLit, toggleContainerNot, toggleNotAt, updateAt, validateSource, valueWizard, wrapInNotAt };
|
|
540
|
+
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, OP_WORD, type PreviewOptions, type TreeRow, UNARY_LABEL, type Validation, type ValueWizardOptions, type WizardSpec, type WizardStepSpec, type WizardValue, addArg, addChildToContainer, addEmit, addSet, advancedRef, astToTree, binary, boolLit, buildSubGroupClause, callNode, choicesOf, comparisonOpsFor, deleteAt, displayName, filterCatalogue, findChoicePeer, findEnumPeer, firstEmptyLeafPath, flagDelta, flipContainerOp, formatNumber, getNodeAt, groupByScope, initialValueFor, insertSiblingClauseAt, isComparisonOp, isPlaceholderForOp, isWrappedInNot, issuesAt, lookup, mountEffectsEditor, mountExpressionEditor, moveAt, moveChildInContainer, needsParens, normaliseRef, notNode, numLit, opSwapGroup, pathKey, placeholderForOp, propertyTip, redirectDeleteForPlaceholderSibling, refOf, removeArgAt, removeAt, renderConditionPreview, renderEffectsPreview, rhsTypesFor, scopedVar, searchCatalogue, seedValueSrc, setArgAt, setNodeAt, strLit, toggleContainerNot, toggleNotAt, updateAt, validateSource, valueWizard, wrapInNotAt };
|
package/dist/index.js
CHANGED
|
@@ -286,6 +286,13 @@ var choicesOf = (e) => {
|
|
|
286
286
|
if (e.type === "enum") return e.enumValues;
|
|
287
287
|
return void 0;
|
|
288
288
|
};
|
|
289
|
+
var propertyTip = (e) => {
|
|
290
|
+
if (!e) return void 0;
|
|
291
|
+
const lines = [];
|
|
292
|
+
if (e.purpose) lines.push(e.purpose);
|
|
293
|
+
if (e.type === "quality" && e.stages?.length) lines.push(`Stages: ${e.stages.join(" \u2192 ")}`);
|
|
294
|
+
return lines.length ? lines.join("\n") : void 0;
|
|
295
|
+
};
|
|
289
296
|
var refOf = (e, defaultScope) => e.scope === defaultScope ? `@${e.name}` : `@${e.scope}.${e.name}`;
|
|
290
297
|
var displayName = (e, defaultScope) => e.scope === defaultScope ? e.name : `${e.scope}.${e.name}`;
|
|
291
298
|
function filterCatalogue(entries, filter = {}) {
|
|
@@ -420,6 +427,14 @@ function textField(opts) {
|
|
|
420
427
|
setTimeout(() => input.focus(), 0);
|
|
421
428
|
return wrap;
|
|
422
429
|
}
|
|
430
|
+
function propertyMenuBody(actions, close) {
|
|
431
|
+
const wrap = el("div", "exed-menu");
|
|
432
|
+
for (const a of actions) wrap.append(button("exed-opt", a.label, () => {
|
|
433
|
+
a.run();
|
|
434
|
+
close();
|
|
435
|
+
}));
|
|
436
|
+
return wrap;
|
|
437
|
+
}
|
|
423
438
|
|
|
424
439
|
// src/flat.ts
|
|
425
440
|
var FLAG_FNS = /* @__PURE__ */ new Set(["check_flags", "set_flags"]);
|
|
@@ -457,7 +472,12 @@ function renderNode(node, path, ctx, parentOp, side) {
|
|
|
457
472
|
case "scopedvar": {
|
|
458
473
|
const entry = lookup(ctx.catalogue, node.scope, node.name);
|
|
459
474
|
const label = displayName({ scope: node.scope, name: node.name }, ctx.defaultScope);
|
|
460
|
-
const varPill = pill(
|
|
475
|
+
const varPill = pill(
|
|
476
|
+
"var",
|
|
477
|
+
label,
|
|
478
|
+
(b) => variableEditor(ctx, path, node, b),
|
|
479
|
+
{ issue: issue ?? (entry ? void 0 : `Unknown property ${label}`), title: propertyTip(entry) }
|
|
480
|
+
);
|
|
461
481
|
attachPropertyMenu(ctx, node, varPill);
|
|
462
482
|
return varPill;
|
|
463
483
|
}
|
|
@@ -533,14 +553,7 @@ function attachPropertyMenu(ctx, node, pillEl) {
|
|
|
533
553
|
const open = ctx.openMenu ?? ctx.openPopover;
|
|
534
554
|
pillEl.addEventListener("contextmenu", (e) => {
|
|
535
555
|
e.preventDefault();
|
|
536
|
-
open(pillEl, (close) =>
|
|
537
|
-
const wrap = el("div", "exed-menu");
|
|
538
|
-
for (const a of actions) wrap.append(button("exed-opt", a.label, () => {
|
|
539
|
-
a.run();
|
|
540
|
-
close();
|
|
541
|
-
}));
|
|
542
|
-
return wrap;
|
|
543
|
-
});
|
|
556
|
+
open(pillEl, (close) => propertyMenuBody(actions, close));
|
|
544
557
|
});
|
|
545
558
|
}
|
|
546
559
|
function isCompoundComparison(node, ctx) {
|
|
@@ -1550,6 +1563,7 @@ function mountEffectsEditor(host, opts) {
|
|
|
1550
1563
|
valueField: true,
|
|
1551
1564
|
...addTerm ? { addTerm } : {},
|
|
1552
1565
|
...selfAdvanceRef ? { selfAdvanceRef } : {},
|
|
1566
|
+
...opts.propertyActions ? { propertyActions: opts.propertyActions } : {},
|
|
1553
1567
|
...opts.popoverContainer ? { popoverContainer: opts.popoverContainer } : {},
|
|
1554
1568
|
text: textMode,
|
|
1555
1569
|
onChange
|
|
@@ -1600,6 +1614,17 @@ function mountEffectsEditor(host, opts) {
|
|
|
1600
1614
|
commit(updateAt(effects, i, { target: refOf(entry, defaultScope), value: initialValueFor(entry, defaultScope).src }));
|
|
1601
1615
|
});
|
|
1602
1616
|
}, "change the target property");
|
|
1617
|
+
const targetEntry = opts.catalogue.find((e) => refOf(e, defaultScope) === eff.target);
|
|
1618
|
+
const tip = propertyTip(targetEntry);
|
|
1619
|
+
if (tip) targetBtn.title = tip;
|
|
1620
|
+
if (targetEntry && opts.propertyActions) {
|
|
1621
|
+
const actions = opts.propertyActions({ scope: targetEntry.scope, name: targetEntry.name });
|
|
1622
|
+
if (actions.length) targetBtn.addEventListener("contextmenu", (e) => {
|
|
1623
|
+
e.preventDefault();
|
|
1624
|
+
closePopover();
|
|
1625
|
+
popover = openPopover(targetBtn, (close) => propertyMenuBody(actions, close), { container: opts.popoverContainer });
|
|
1626
|
+
});
|
|
1627
|
+
}
|
|
1603
1628
|
const advances = isSelfAdvance(eff, defaultScope, opts.dialect);
|
|
1604
1629
|
row.append(targetBtn);
|
|
1605
1630
|
if (!advances) row.append(el("span", "exed-effect-eq", ["="]));
|
|
@@ -1763,13 +1788,26 @@ function renderConditionPreview(src, o) {
|
|
|
1763
1788
|
const cls = o.propertyActions ? "exed-preview exed-preview-interactive" : "exed-preview";
|
|
1764
1789
|
return el("div", cls, [exprPills(src, o)]);
|
|
1765
1790
|
}
|
|
1791
|
+
function targetPill(ref, o) {
|
|
1792
|
+
const pill2 = el("span", "exed-pill exed-pill-prop", [ref || "(property)"]);
|
|
1793
|
+
const entry = o.catalogue.find((e) => refOf(e, o.dialect.defaultScope) === ref);
|
|
1794
|
+
if (!entry) return pill2;
|
|
1795
|
+
const tip = propertyTip(entry);
|
|
1796
|
+
if (tip) pill2.title = tip;
|
|
1797
|
+
const actions = o.propertyActions?.({ scope: entry.scope, name: entry.name }) ?? [];
|
|
1798
|
+
if (actions.length) pill2.addEventListener("contextmenu", (e) => {
|
|
1799
|
+
e.preventDefault();
|
|
1800
|
+
openPopover(pill2, (close) => propertyMenuBody(actions, close), { container: o.popoverContainer });
|
|
1801
|
+
});
|
|
1802
|
+
return pill2;
|
|
1803
|
+
}
|
|
1766
1804
|
function renderEffectsPreview(effects, o) {
|
|
1767
|
-
const wrap = el("div",
|
|
1805
|
+
const wrap = el("div", `exed-preview exed-preview-effects${o.propertyActions ? " exed-preview-interactive" : ""}`);
|
|
1768
1806
|
for (const eff of effects) {
|
|
1769
1807
|
const row = el("div", "exed-preview-eff");
|
|
1770
1808
|
if (eff.kind === "set") {
|
|
1771
1809
|
const advances = isSelfAdvance(eff, o.dialect.defaultScope, o.dialect);
|
|
1772
|
-
row.append(
|
|
1810
|
+
row.append(targetPill(eff.target, o));
|
|
1773
1811
|
if (!advances) row.append(el("span", "exed-effect-eq", ["="]));
|
|
1774
1812
|
row.append(exprPills(eff.value, o, advances ? eff.target : void 0));
|
|
1775
1813
|
} else {
|
|
@@ -1787,6 +1825,6 @@ function renderEffectsPreview(effects, o) {
|
|
|
1787
1825
|
return wrap;
|
|
1788
1826
|
}
|
|
1789
1827
|
|
|
1790
|
-
export { ARITHMETIC_OPS, BINARY_LABEL, COMPARABLE_TYPES, COMPARISON_OPS, EQUALITY_OPS, OP_WORD, UNARY_LABEL, addArg, addChildToContainer, addEmit, addSet, advancedRef, astToTree, binary, boolLit, buildSubGroupClause, callNode, choicesOf, comparisonOpsFor, deleteAt, displayName, filterCatalogue, findChoicePeer, findEnumPeer, firstEmptyLeafPath, flagDelta, flipContainerOp, formatNumber, getNodeAt, groupByScope, initialValueFor, insertSiblingClauseAt, isComparisonOp, isPlaceholderForOp, isWrappedInNot, issuesAt, lookup, mountEffectsEditor, mountExpressionEditor, moveAt, moveChildInContainer, needsParens, normaliseRef, notNode, numLit, opSwapGroup, pathKey, placeholderForOp, redirectDeleteForPlaceholderSibling, refOf, removeArgAt, removeAt, renderConditionPreview, renderEffectsPreview, rhsTypesFor, scopedVar, searchCatalogue, seedValueSrc, setArgAt, setNodeAt, strLit, toggleContainerNot, toggleNotAt, updateAt, validateSource, valueWizard, wrapInNotAt };
|
|
1828
|
+
export { ARITHMETIC_OPS, BINARY_LABEL, COMPARABLE_TYPES, COMPARISON_OPS, EQUALITY_OPS, OP_WORD, UNARY_LABEL, addArg, addChildToContainer, addEmit, addSet, advancedRef, astToTree, binary, boolLit, buildSubGroupClause, callNode, choicesOf, comparisonOpsFor, deleteAt, displayName, filterCatalogue, findChoicePeer, findEnumPeer, firstEmptyLeafPath, flagDelta, flipContainerOp, formatNumber, getNodeAt, groupByScope, initialValueFor, insertSiblingClauseAt, isComparisonOp, isPlaceholderForOp, isWrappedInNot, issuesAt, lookup, mountEffectsEditor, mountExpressionEditor, moveAt, moveChildInContainer, needsParens, normaliseRef, notNode, numLit, opSwapGroup, pathKey, placeholderForOp, propertyTip, redirectDeleteForPlaceholderSibling, refOf, removeArgAt, removeAt, renderConditionPreview, renderEffectsPreview, rhsTypesFor, scopedVar, searchCatalogue, seedValueSrc, setArgAt, setNodeAt, strLit, toggleContainerNot, toggleNotAt, updateAt, validateSource, valueWizard, wrapInNotAt };
|
|
1791
1829
|
//# sourceMappingURL=index.js.map
|
|
1792
1830
|
//# sourceMappingURL=index.js.map
|