@wildwinter/expr-editor 0.8.0 → 0.10.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 +5 -0
- package/dist/index.cjs +19 -3
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +21 -0
- package/dist/index.d.ts +21 -0
- package/dist/index.js +19 -3
- package/dist/index.js.map +1 -1
- package/dist/styles.css +8 -0
- package/dist/styles.css.map +1 -1
- package/package.json +1 -1
package/dist/index.d.cts
CHANGED
|
@@ -214,6 +214,10 @@ interface EditCtx {
|
|
|
214
214
|
apply(next: ExprNode | null): void;
|
|
215
215
|
/** Open a popover anchored to `anchor`; `render(close)` builds the content. */
|
|
216
216
|
openPopover(anchor: HTMLElement, render: (close: () => void) => Node): void;
|
|
217
|
+
/** Opener for the property right-click menu; falls back to openPopover. The
|
|
218
|
+
* read-only preview sets this (a real popover) while leaving openPopover a
|
|
219
|
+
* no-op, so property pills get their menu but left-click editing stays inert. */
|
|
220
|
+
openMenu?(anchor: HTMLElement, render: (close: () => void) => Node): void;
|
|
217
221
|
/** Host-provided picker for a flow-node reference arg (e.g. `seen(...)` / `visits(...)`). When set,
|
|
218
222
|
* the node-ref arg renders as a pill that opens this instead of a free-text field; `onPick` receives
|
|
219
223
|
* the chosen node id. Absent in dialects / hosts that have no node catalogue. */
|
|
@@ -242,6 +246,11 @@ interface EditCtx {
|
|
|
242
246
|
label: string;
|
|
243
247
|
run: () => void;
|
|
244
248
|
}>;
|
|
249
|
+
/** Read-only presentation hint: render more compactly than the editable tree.
|
|
250
|
+
* Set by the preview (never the interactive editor). Currently collapses a
|
|
251
|
+
* flag-delta call (e.g. `check_flags(@p, +a, -b)`) to `@p: +a -b`, dropping
|
|
252
|
+
* the function name and parentheses. */
|
|
253
|
+
compact?: boolean;
|
|
245
254
|
}
|
|
246
255
|
|
|
247
256
|
interface ExpressionEditorOptions {
|
|
@@ -383,6 +392,18 @@ interface PreviewOptions {
|
|
|
383
392
|
scopeOrder?: string[];
|
|
384
393
|
/** Resolve a node id to a readable label for seen()/visits() node pills. */
|
|
385
394
|
nodeLabel?: (id: string) => string;
|
|
395
|
+
/** Host actions for a property pill (e.g. "Go to definition"). When set, the
|
|
396
|
+
* preview becomes right-click interactive on property pills (left-click still
|
|
397
|
+
* falls through to the host); otherwise the preview is fully non-interactive. */
|
|
398
|
+
propertyActions?(ref: {
|
|
399
|
+
scope: string;
|
|
400
|
+
name: string;
|
|
401
|
+
}): Array<{
|
|
402
|
+
label: string;
|
|
403
|
+
run: () => void;
|
|
404
|
+
}>;
|
|
405
|
+
/** Where the property menu mounts (default document.body). */
|
|
406
|
+
popoverContainer?: HTMLElement;
|
|
386
407
|
}
|
|
387
408
|
/** Read-only pill strip for a condition (name-form). Empty/unparseable is the caller's concern; a
|
|
388
409
|
* non-empty unparseable string falls back to its raw text. */
|
package/dist/index.d.ts
CHANGED
|
@@ -214,6 +214,10 @@ interface EditCtx {
|
|
|
214
214
|
apply(next: ExprNode | null): void;
|
|
215
215
|
/** Open a popover anchored to `anchor`; `render(close)` builds the content. */
|
|
216
216
|
openPopover(anchor: HTMLElement, render: (close: () => void) => Node): void;
|
|
217
|
+
/** Opener for the property right-click menu; falls back to openPopover. The
|
|
218
|
+
* read-only preview sets this (a real popover) while leaving openPopover a
|
|
219
|
+
* no-op, so property pills get their menu but left-click editing stays inert. */
|
|
220
|
+
openMenu?(anchor: HTMLElement, render: (close: () => void) => Node): void;
|
|
217
221
|
/** Host-provided picker for a flow-node reference arg (e.g. `seen(...)` / `visits(...)`). When set,
|
|
218
222
|
* the node-ref arg renders as a pill that opens this instead of a free-text field; `onPick` receives
|
|
219
223
|
* the chosen node id. Absent in dialects / hosts that have no node catalogue. */
|
|
@@ -242,6 +246,11 @@ interface EditCtx {
|
|
|
242
246
|
label: string;
|
|
243
247
|
run: () => void;
|
|
244
248
|
}>;
|
|
249
|
+
/** Read-only presentation hint: render more compactly than the editable tree.
|
|
250
|
+
* Set by the preview (never the interactive editor). Currently collapses a
|
|
251
|
+
* flag-delta call (e.g. `check_flags(@p, +a, -b)`) to `@p: +a -b`, dropping
|
|
252
|
+
* the function name and parentheses. */
|
|
253
|
+
compact?: boolean;
|
|
245
254
|
}
|
|
246
255
|
|
|
247
256
|
interface ExpressionEditorOptions {
|
|
@@ -383,6 +392,18 @@ interface PreviewOptions {
|
|
|
383
392
|
scopeOrder?: string[];
|
|
384
393
|
/** Resolve a node id to a readable label for seen()/visits() node pills. */
|
|
385
394
|
nodeLabel?: (id: string) => string;
|
|
395
|
+
/** Host actions for a property pill (e.g. "Go to definition"). When set, the
|
|
396
|
+
* preview becomes right-click interactive on property pills (left-click still
|
|
397
|
+
* falls through to the host); otherwise the preview is fully non-interactive. */
|
|
398
|
+
propertyActions?(ref: {
|
|
399
|
+
scope: string;
|
|
400
|
+
name: string;
|
|
401
|
+
}): Array<{
|
|
402
|
+
label: string;
|
|
403
|
+
run: () => void;
|
|
404
|
+
}>;
|
|
405
|
+
/** Where the property menu mounts (default document.body). */
|
|
406
|
+
popoverContainer?: HTMLElement;
|
|
386
407
|
}
|
|
387
408
|
/** Read-only pill strip for a condition (name-form). Empty/unparseable is the caller's concern; a
|
|
388
409
|
* non-empty unparseable string falls back to its raw text. */
|
package/dist/index.js
CHANGED
|
@@ -441,6 +441,13 @@ function renderNode(node, path, ctx, parentOp, side) {
|
|
|
441
441
|
case "flagdelta":
|
|
442
442
|
return pill(node.sign === "+" ? "flagpos" : "flagneg", `${node.sign}${node.name || "flag"}`, (b) => flagEditor(ctx, path, node, b), { issue, path });
|
|
443
443
|
case "call": {
|
|
444
|
+
if (ctx.compact && ctx.dialect.functions[node.name]?.flagDeltaArgs && node.args.length >= 2 && node.args[0].kind === "scopedvar" && node.args.slice(1).every((a) => a.kind === "flagdelta")) {
|
|
445
|
+
const row2 = el("span", "exed-call exed-call-flags");
|
|
446
|
+
row2.append(renderNode(node.args[0], [...path, "args", 0], ctx));
|
|
447
|
+
row2.append(el("span", "exed-flagsep", [":"]));
|
|
448
|
+
for (let i = 1; i < node.args.length; i++) row2.append(renderNode(node.args[i], [...path, "args", i], ctx));
|
|
449
|
+
return row2;
|
|
450
|
+
}
|
|
444
451
|
const row = el("span", "exed-call");
|
|
445
452
|
row.append(pill("func", node.name, (b) => callEditor(ctx, path, node, b), { issue }));
|
|
446
453
|
row.append(el("span", "exed-paren", ["("]));
|
|
@@ -490,9 +497,10 @@ function attachPropertyMenu(ctx, node, pillEl) {
|
|
|
490
497
|
if (!ctx.propertyActions) return;
|
|
491
498
|
const actions = ctx.propertyActions({ scope: node.scope, name: node.name });
|
|
492
499
|
if (!actions.length) return;
|
|
500
|
+
const open = ctx.openMenu ?? ctx.openPopover;
|
|
493
501
|
pillEl.addEventListener("contextmenu", (e) => {
|
|
494
502
|
e.preventDefault();
|
|
495
|
-
|
|
503
|
+
open(pillEl, (close) => {
|
|
496
504
|
const wrap = el("div", "exed-menu");
|
|
497
505
|
for (const a of actions) wrap.append(button("exed-opt", a.label, () => {
|
|
498
506
|
a.run();
|
|
@@ -1653,6 +1661,7 @@ function frozenCtx(src, o) {
|
|
|
1653
1661
|
catalogue: o.catalogue,
|
|
1654
1662
|
scopeOrder: o.scopeOrder ?? [],
|
|
1655
1663
|
functions: [],
|
|
1664
|
+
compact: true,
|
|
1656
1665
|
byPath: v.byPath,
|
|
1657
1666
|
getAst: () => v.ast,
|
|
1658
1667
|
apply: () => {
|
|
@@ -1662,7 +1671,13 @@ function frozenCtx(src, o) {
|
|
|
1662
1671
|
pickNode: () => {
|
|
1663
1672
|
},
|
|
1664
1673
|
// enables labelled node pills; never fires (preview is read-only)
|
|
1665
|
-
...o.nodeLabel ? { nodeLabel: o.nodeLabel } : {}
|
|
1674
|
+
...o.nodeLabel ? { nodeLabel: o.nodeLabel } : {},
|
|
1675
|
+
...o.propertyActions ? {
|
|
1676
|
+
propertyActions: o.propertyActions,
|
|
1677
|
+
openMenu: (anchor, render) => {
|
|
1678
|
+
openPopover(anchor, render, { container: o.popoverContainer });
|
|
1679
|
+
}
|
|
1680
|
+
} : {}
|
|
1666
1681
|
};
|
|
1667
1682
|
return { ctx, ast: v.ast };
|
|
1668
1683
|
}
|
|
@@ -1671,7 +1686,8 @@ function exprPills(src, o) {
|
|
|
1671
1686
|
return ast ? renderNode(ast, [], ctx) : el("span", "exed-preview-raw", [src]);
|
|
1672
1687
|
}
|
|
1673
1688
|
function renderConditionPreview(src, o) {
|
|
1674
|
-
|
|
1689
|
+
const cls = o.propertyActions ? "exed-preview exed-preview-interactive" : "exed-preview";
|
|
1690
|
+
return el("div", cls, [exprPills(src, o)]);
|
|
1675
1691
|
}
|
|
1676
1692
|
function renderEffectsPreview(effects, o) {
|
|
1677
1693
|
const wrap = el("div", "exed-preview exed-preview-effects");
|