@wildwinter/expr-editor 0.7.0 → 0.9.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 +13 -0
- package/dist/index.cjs +77 -19
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +38 -0
- package/dist/index.d.ts +38 -0
- package/dist/index.js +77 -19
- package/dist/index.js.map +1 -1
- package/dist/styles.css +4 -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. */
|
|
@@ -232,6 +236,16 @@ interface EditCtx {
|
|
|
232
236
|
* (an enum-typed outcome target). Lets the string editor show an enum picker
|
|
233
237
|
* even without a comparison peer. No effect on non-root literals. */
|
|
234
238
|
valueEnumValues?: string[];
|
|
239
|
+
/** Host actions for a property pill (e.g. "Go to definition"). When set,
|
|
240
|
+
* right-clicking a property pill opens a menu of these actions. The host
|
|
241
|
+
* resolves what each does (navigation etc.); empty array = no menu. */
|
|
242
|
+
propertyActions?(ref: {
|
|
243
|
+
scope: string;
|
|
244
|
+
name: string;
|
|
245
|
+
}): Array<{
|
|
246
|
+
label: string;
|
|
247
|
+
run: () => void;
|
|
248
|
+
}>;
|
|
235
249
|
}
|
|
236
250
|
|
|
237
251
|
interface ExpressionEditorOptions {
|
|
@@ -286,6 +300,18 @@ interface ExpressionEditorOptions {
|
|
|
286
300
|
target: string;
|
|
287
301
|
flags: string[];
|
|
288
302
|
};
|
|
303
|
+
/** Placeholder for the raw-text textarea (defaults to a generic example).
|
|
304
|
+
* Value cells pass a value-flavoured hint (e.g. "autumn or @count + 1"). */
|
|
305
|
+
rawPlaceholder?: string;
|
|
306
|
+
/** Host actions for a property pill, shown on right-click (e.g. go to
|
|
307
|
+
* definition). Receives the property ref; returns the menu items. */
|
|
308
|
+
propertyActions?(ref: {
|
|
309
|
+
scope: string;
|
|
310
|
+
name: string;
|
|
311
|
+
}): Array<{
|
|
312
|
+
label: string;
|
|
313
|
+
run: () => void;
|
|
314
|
+
}>;
|
|
289
315
|
/** Emitted on every edit (name-form; "" when cleared). */
|
|
290
316
|
onChange: (src: string) => void;
|
|
291
317
|
/** Notified when the author starts (true) / stops (false) editing inside a popover
|
|
@@ -361,6 +387,18 @@ interface PreviewOptions {
|
|
|
361
387
|
scopeOrder?: string[];
|
|
362
388
|
/** Resolve a node id to a readable label for seen()/visits() node pills. */
|
|
363
389
|
nodeLabel?: (id: string) => string;
|
|
390
|
+
/** Host actions for a property pill (e.g. "Go to definition"). When set, the
|
|
391
|
+
* preview becomes right-click interactive on property pills (left-click still
|
|
392
|
+
* falls through to the host); otherwise the preview is fully non-interactive. */
|
|
393
|
+
propertyActions?(ref: {
|
|
394
|
+
scope: string;
|
|
395
|
+
name: string;
|
|
396
|
+
}): Array<{
|
|
397
|
+
label: string;
|
|
398
|
+
run: () => void;
|
|
399
|
+
}>;
|
|
400
|
+
/** Where the property menu mounts (default document.body). */
|
|
401
|
+
popoverContainer?: HTMLElement;
|
|
364
402
|
}
|
|
365
403
|
/** Read-only pill strip for a condition (name-form). Empty/unparseable is the caller's concern; a
|
|
366
404
|
* 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. */
|
|
@@ -232,6 +236,16 @@ interface EditCtx {
|
|
|
232
236
|
* (an enum-typed outcome target). Lets the string editor show an enum picker
|
|
233
237
|
* even without a comparison peer. No effect on non-root literals. */
|
|
234
238
|
valueEnumValues?: string[];
|
|
239
|
+
/** Host actions for a property pill (e.g. "Go to definition"). When set,
|
|
240
|
+
* right-clicking a property pill opens a menu of these actions. The host
|
|
241
|
+
* resolves what each does (navigation etc.); empty array = no menu. */
|
|
242
|
+
propertyActions?(ref: {
|
|
243
|
+
scope: string;
|
|
244
|
+
name: string;
|
|
245
|
+
}): Array<{
|
|
246
|
+
label: string;
|
|
247
|
+
run: () => void;
|
|
248
|
+
}>;
|
|
235
249
|
}
|
|
236
250
|
|
|
237
251
|
interface ExpressionEditorOptions {
|
|
@@ -286,6 +300,18 @@ interface ExpressionEditorOptions {
|
|
|
286
300
|
target: string;
|
|
287
301
|
flags: string[];
|
|
288
302
|
};
|
|
303
|
+
/** Placeholder for the raw-text textarea (defaults to a generic example).
|
|
304
|
+
* Value cells pass a value-flavoured hint (e.g. "autumn or @count + 1"). */
|
|
305
|
+
rawPlaceholder?: string;
|
|
306
|
+
/** Host actions for a property pill, shown on right-click (e.g. go to
|
|
307
|
+
* definition). Receives the property ref; returns the menu items. */
|
|
308
|
+
propertyActions?(ref: {
|
|
309
|
+
scope: string;
|
|
310
|
+
name: string;
|
|
311
|
+
}): Array<{
|
|
312
|
+
label: string;
|
|
313
|
+
run: () => void;
|
|
314
|
+
}>;
|
|
289
315
|
/** Emitted on every edit (name-form; "" when cleared). */
|
|
290
316
|
onChange: (src: string) => void;
|
|
291
317
|
/** Notified when the author starts (true) / stops (false) editing inside a popover
|
|
@@ -361,6 +387,18 @@ interface PreviewOptions {
|
|
|
361
387
|
scopeOrder?: string[];
|
|
362
388
|
/** Resolve a node id to a readable label for seen()/visits() node pills. */
|
|
363
389
|
nodeLabel?: (id: string) => string;
|
|
390
|
+
/** Host actions for a property pill (e.g. "Go to definition"). When set, the
|
|
391
|
+
* preview becomes right-click interactive on property pills (left-click still
|
|
392
|
+
* falls through to the host); otherwise the preview is fully non-interactive. */
|
|
393
|
+
propertyActions?(ref: {
|
|
394
|
+
scope: string;
|
|
395
|
+
name: string;
|
|
396
|
+
}): Array<{
|
|
397
|
+
label: string;
|
|
398
|
+
run: () => void;
|
|
399
|
+
}>;
|
|
400
|
+
/** Where the property menu mounts (default document.body). */
|
|
401
|
+
popoverContainer?: HTMLElement;
|
|
364
402
|
}
|
|
365
403
|
/** Read-only pill strip for a condition (name-form). Empty/unparseable is the caller's concern; a
|
|
366
404
|
* non-empty unparseable string falls back to its raw text. */
|
package/dist/index.js
CHANGED
|
@@ -303,10 +303,11 @@ function el(tag, cls, children) {
|
|
|
303
303
|
}
|
|
304
304
|
return node;
|
|
305
305
|
}
|
|
306
|
-
function button(cls, label, onClick, title) {
|
|
306
|
+
function button(cls, label, onClick, title, aria) {
|
|
307
307
|
const b = el("button", cls, [label]);
|
|
308
308
|
b.type = "button";
|
|
309
309
|
if (title) b.title = title;
|
|
310
|
+
if (aria) b.setAttribute("aria-label", aria);
|
|
310
311
|
b.addEventListener("click", onClick);
|
|
311
312
|
return b;
|
|
312
313
|
}
|
|
@@ -387,10 +388,25 @@ function textField(opts) {
|
|
|
387
388
|
var FLAG_FNS = /* @__PURE__ */ new Set(["check_flags", "set_flags"]);
|
|
388
389
|
var TAG_ARG0_FNS = /* @__PURE__ */ new Set(["seen", "patter_seen", "visits", "patter_visits"]);
|
|
389
390
|
function pill(kind, label, onClick, opts = {}) {
|
|
390
|
-
const b = button(`exed-pill exed-pill-${kind}${opts.issue ? " exed-pill-err" : ""}`, label, () => onClick(b), opts.issue ?? opts.title);
|
|
391
|
+
const b = button(`exed-pill exed-pill-${kind}${opts.issue ? " exed-pill-err" : ""}`, label, () => onClick(b), opts.issue ?? opts.title, opts.aria);
|
|
392
|
+
b.setAttribute("aria-haspopup", "dialog");
|
|
391
393
|
if (opts.path) b.dataset["exedPath"] = opts.path.join("/");
|
|
392
394
|
return b;
|
|
393
395
|
}
|
|
396
|
+
var OP_ARIA = {
|
|
397
|
+
"==": "equals",
|
|
398
|
+
"!=": "not equal to",
|
|
399
|
+
">": "greater than",
|
|
400
|
+
">=": "at least",
|
|
401
|
+
"<": "less than",
|
|
402
|
+
"<=": "at most",
|
|
403
|
+
"and": "and",
|
|
404
|
+
"or": "or",
|
|
405
|
+
"+": "plus",
|
|
406
|
+
"-": "minus",
|
|
407
|
+
"*": "times",
|
|
408
|
+
"/": "divided by"
|
|
409
|
+
};
|
|
394
410
|
var issueText = (ctx, path) => {
|
|
395
411
|
const list = issuesAt(ctx.byPath, path);
|
|
396
412
|
return list.length ? list.map((i) => i.message).join("; ") : void 0;
|
|
@@ -418,7 +434,9 @@ function renderNode(node, path, ctx, parentOp, side) {
|
|
|
418
434
|
case "scopedvar": {
|
|
419
435
|
const entry = lookup(ctx.catalogue, node.scope, node.name);
|
|
420
436
|
const label = displayName({ scope: node.scope, name: node.name }, ctx.defaultScope);
|
|
421
|
-
|
|
437
|
+
const varPill = pill("var", label, (b) => variableEditor(ctx, path, node, b), { issue: issue ?? (entry ? void 0 : `Unknown property ${label}`) });
|
|
438
|
+
attachPropertyMenu(ctx, node, varPill);
|
|
439
|
+
return varPill;
|
|
422
440
|
}
|
|
423
441
|
case "flagdelta":
|
|
424
442
|
return pill(node.sign === "+" ? "flagpos" : "flagneg", `${node.sign}${node.name || "flag"}`, (b) => flagEditor(ctx, path, node, b), { issue, path });
|
|
@@ -435,7 +453,7 @@ function renderNode(node, path, ctx, parentOp, side) {
|
|
|
435
453
|
}
|
|
436
454
|
case "unary": {
|
|
437
455
|
const row = el("span", "exed-unary");
|
|
438
|
-
row.append(pill("op", UNARY_LABEL[node.op], () => ctx.apply(deleteOrUnwrapNot(ctx, path, node)), { title: "remove" }));
|
|
456
|
+
row.append(pill("op", UNARY_LABEL[node.op], () => ctx.apply(deleteOrUnwrapNot(ctx, path, node)), { title: "remove", aria: `${OP_ARIA[node.op] ?? node.op} (click to remove)` }));
|
|
439
457
|
row.append(renderNode(node.operand, [...path, "operand"], ctx));
|
|
440
458
|
return row;
|
|
441
459
|
}
|
|
@@ -447,7 +465,7 @@ function renderNode(node, path, ctx, parentOp, side) {
|
|
|
447
465
|
const swap = opSwapGroup(node.op);
|
|
448
466
|
const opPill = pill("op", BINARY_LABEL[node.op], (b) => {
|
|
449
467
|
if (swap) operatorEditor(ctx, path, node.op, swap, b);
|
|
450
|
-
}, { title: swap ? "swap operator" : void 0 });
|
|
468
|
+
}, { title: swap ? "swap operator" : void 0, aria: OP_ARIA[node.op] ?? node.op });
|
|
451
469
|
if (!swap) opPill.classList.add("exed-op-structural");
|
|
452
470
|
row.append(opPill);
|
|
453
471
|
row.append(renderNode(node.right, [...path, "right"], ctx, node.op, "right"));
|
|
@@ -468,6 +486,36 @@ var deleteOrUnwrapNot = (ctx, path, node) => (
|
|
|
468
486
|
// clicking the NOT pill strips it (keeps the operand)
|
|
469
487
|
setNodeAt(ctx.getAst(), path, node.operand)
|
|
470
488
|
);
|
|
489
|
+
function attachPropertyMenu(ctx, node, pillEl) {
|
|
490
|
+
if (!ctx.propertyActions) return;
|
|
491
|
+
const actions = ctx.propertyActions({ scope: node.scope, name: node.name });
|
|
492
|
+
if (!actions.length) return;
|
|
493
|
+
const open = ctx.openMenu ?? ctx.openPopover;
|
|
494
|
+
pillEl.addEventListener("contextmenu", (e) => {
|
|
495
|
+
e.preventDefault();
|
|
496
|
+
open(pillEl, (close) => {
|
|
497
|
+
const wrap = el("div", "exed-menu");
|
|
498
|
+
for (const a of actions) wrap.append(button("exed-opt", a.label, () => {
|
|
499
|
+
a.run();
|
|
500
|
+
close();
|
|
501
|
+
}));
|
|
502
|
+
return wrap;
|
|
503
|
+
});
|
|
504
|
+
});
|
|
505
|
+
}
|
|
506
|
+
function isCompoundComparison(node, ctx) {
|
|
507
|
+
if (node.kind !== "binary" || !isComparisonOp(node.op)) return false;
|
|
508
|
+
const numCall = (n) => n.kind === "call" && ctx.dialect.functions[n.name]?.returnType === "number";
|
|
509
|
+
const isNum = (n) => n.kind === "number";
|
|
510
|
+
return numCall(node.left) && isNum(node.right) || numCall(node.right) && isNum(node.left);
|
|
511
|
+
}
|
|
512
|
+
function effectiveDeletePath(ctx, path) {
|
|
513
|
+
const last = path[path.length - 1];
|
|
514
|
+
if (last !== "left" && last !== "right") return path;
|
|
515
|
+
const parentPath = path.slice(0, -1);
|
|
516
|
+
const parent = getNodeAt(ctx.getAst(), parentPath);
|
|
517
|
+
return parent && isCompoundComparison(parent, ctx) ? parentPath : path;
|
|
518
|
+
}
|
|
471
519
|
function boolEditor(ctx, path, value, anchor) {
|
|
472
520
|
ctx.openPopover(anchor, (close) => {
|
|
473
521
|
const wrap = el("div", "exed-menu");
|
|
@@ -579,7 +627,7 @@ function flagEditor(ctx, path, node, anchor) {
|
|
|
579
627
|
return wrap;
|
|
580
628
|
});
|
|
581
629
|
}
|
|
582
|
-
var canDelete = (ctx, path) => !(ctx.requireNonEmpty && path.length === 0);
|
|
630
|
+
var canDelete = (ctx, path) => !(ctx.requireNonEmpty && effectiveDeletePath(ctx, path).length === 0);
|
|
583
631
|
function callEditor(ctx, path, node, anchor) {
|
|
584
632
|
ctx.openPopover(anchor, (close) => {
|
|
585
633
|
const wrap = el("div", "exed-menu");
|
|
@@ -593,7 +641,7 @@ function callEditor(ctx, path, node, anchor) {
|
|
|
593
641
|
}
|
|
594
642
|
if (canDelete(ctx, path)) {
|
|
595
643
|
wrap.append(button("exed-opt danger", "Delete", () => {
|
|
596
|
-
ctx.apply(deleteAt(ctx.getAst(), path));
|
|
644
|
+
ctx.apply(deleteAt(ctx.getAst(), effectiveDeletePath(ctx, path)));
|
|
597
645
|
close();
|
|
598
646
|
}));
|
|
599
647
|
}
|
|
@@ -608,7 +656,7 @@ function variableEditor(ctx, path, node, anchor) {
|
|
|
608
656
|
close();
|
|
609
657
|
},
|
|
610
658
|
...canDelete(ctx, path) ? { footer: button("exed-opt danger", "Delete", () => {
|
|
611
|
-
ctx.apply(deleteAt(ctx.getAst(), path));
|
|
659
|
+
ctx.apply(deleteAt(ctx.getAst(), effectiveDeletePath(ctx, path)));
|
|
612
660
|
close();
|
|
613
661
|
}) } : {}
|
|
614
662
|
}));
|
|
@@ -878,15 +926,17 @@ function renderRow(ctx, row, env) {
|
|
|
878
926
|
if (row.kind === "container") return renderContainer(ctx, row, env);
|
|
879
927
|
return renderLeaf(ctx, row, env);
|
|
880
928
|
}
|
|
881
|
-
function notToggle(ctx, path) {
|
|
882
|
-
|
|
929
|
+
function notToggle(ctx, path, pressed) {
|
|
930
|
+
const b = button("exed-rowbtn", "NOT", () => ctx.apply(toggleContainerNot(ctx.getAst(), path)), "toggle NOT", pressed ? "remove NOT" : "apply NOT");
|
|
931
|
+
b.setAttribute("aria-pressed", String(pressed));
|
|
932
|
+
return b;
|
|
883
933
|
}
|
|
884
934
|
function rowActions(ctx, row, env) {
|
|
885
935
|
const acts = el("div", "exed-rowacts");
|
|
886
|
-
acts.append(notToggle(ctx, row.path));
|
|
936
|
+
acts.append(notToggle(ctx, row.path, row.negated));
|
|
887
937
|
if (env.chainPath && env.count != null && env.index != null) {
|
|
888
|
-
if (env.index > 0) acts.append(button("exed-rowbtn", "\u2191", () => ctx.apply(moveChildInContainer(ctx.getAst(), env.chainPath, env.index, env.index - 1)), "move up"));
|
|
889
|
-
if (env.index < env.count - 1) acts.append(button("exed-rowbtn", "\u2193", () => ctx.apply(moveChildInContainer(ctx.getAst(), env.chainPath, env.index, env.index + 1)), "move down"));
|
|
938
|
+
if (env.index > 0) acts.append(button("exed-rowbtn", "\u2191", () => ctx.apply(moveChildInContainer(ctx.getAst(), env.chainPath, env.index, env.index - 1)), "move up", "move up"));
|
|
939
|
+
if (env.index < env.count - 1) acts.append(button("exed-rowbtn", "\u2193", () => ctx.apply(moveChildInContainer(ctx.getAst(), env.chainPath, env.index, env.index + 1)), "move down", "move down"));
|
|
890
940
|
}
|
|
891
941
|
acts.append(button("exed-rowbtn danger", "\u2715", () => {
|
|
892
942
|
if (env.root) {
|
|
@@ -895,7 +945,7 @@ function rowActions(ctx, row, env) {
|
|
|
895
945
|
}
|
|
896
946
|
const target = redirectDeleteForPlaceholderSibling(ctx.getAst(), row.path);
|
|
897
947
|
ctx.apply(deleteAt(ctx.getAst(), target));
|
|
898
|
-
}, "delete"));
|
|
948
|
+
}, "delete", "delete this condition"));
|
|
899
949
|
return acts;
|
|
900
950
|
}
|
|
901
951
|
function renderLeaf(ctx, row, env) {
|
|
@@ -923,8 +973,8 @@ function renderContainer(ctx, row, env) {
|
|
|
923
973
|
head.append(el("span", "exed-grouplabel", [label]));
|
|
924
974
|
}
|
|
925
975
|
const headActs = el("div", "exed-rowacts");
|
|
926
|
-
headActs.append(notToggle(ctx, row.path));
|
|
927
|
-
if (!env.root) headActs.append(button("exed-rowbtn danger", "\u2715", () => ctx.apply(deleteAt(ctx.getAst(), row.path)), "delete group"));
|
|
976
|
+
headActs.append(notToggle(ctx, row.path, row.negated));
|
|
977
|
+
if (!env.root) headActs.append(button("exed-rowbtn danger", "\u2715", () => ctx.apply(deleteAt(ctx.getAst(), row.path)), "delete group", "delete this group"));
|
|
928
978
|
head.append(headActs);
|
|
929
979
|
box.append(head);
|
|
930
980
|
const body = el("div", "exed-groupbody");
|
|
@@ -1077,6 +1127,7 @@ function mountExpressionEditor(host, opts) {
|
|
|
1077
1127
|
},
|
|
1078
1128
|
...opts.requireNonEmpty ? { requireNonEmpty: true } : {},
|
|
1079
1129
|
...opts.valueEnumValues ? { valueEnumValues: opts.valueEnumValues } : {},
|
|
1130
|
+
...opts.propertyActions ? { propertyActions: opts.propertyActions } : {},
|
|
1080
1131
|
...opts.pickNode ? { pickNode: opts.pickNode } : {},
|
|
1081
1132
|
...opts.nodeLabel ? { nodeLabel: opts.nodeLabel } : {}
|
|
1082
1133
|
};
|
|
@@ -1113,7 +1164,7 @@ function mountExpressionEditor(host, opts) {
|
|
|
1113
1164
|
function rawArea() {
|
|
1114
1165
|
const ta = el("textarea", "exed-raw");
|
|
1115
1166
|
ta.value = src;
|
|
1116
|
-
ta.placeholder = "@gold > 0 and @met_anna";
|
|
1167
|
+
ta.placeholder = opts.rawPlaceholder ?? "@gold > 0 and @met_anna";
|
|
1117
1168
|
ta.rows = 2;
|
|
1118
1169
|
ta.addEventListener("input", () => {
|
|
1119
1170
|
src = ta.value;
|
|
@@ -1612,7 +1663,13 @@ function frozenCtx(src, o) {
|
|
|
1612
1663
|
pickNode: () => {
|
|
1613
1664
|
},
|
|
1614
1665
|
// enables labelled node pills; never fires (preview is read-only)
|
|
1615
|
-
...o.nodeLabel ? { nodeLabel: o.nodeLabel } : {}
|
|
1666
|
+
...o.nodeLabel ? { nodeLabel: o.nodeLabel } : {},
|
|
1667
|
+
...o.propertyActions ? {
|
|
1668
|
+
propertyActions: o.propertyActions,
|
|
1669
|
+
openMenu: (anchor, render) => {
|
|
1670
|
+
openPopover(anchor, render, { container: o.popoverContainer });
|
|
1671
|
+
}
|
|
1672
|
+
} : {}
|
|
1616
1673
|
};
|
|
1617
1674
|
return { ctx, ast: v.ast };
|
|
1618
1675
|
}
|
|
@@ -1621,7 +1678,8 @@ function exprPills(src, o) {
|
|
|
1621
1678
|
return ast ? renderNode(ast, [], ctx) : el("span", "exed-preview-raw", [src]);
|
|
1622
1679
|
}
|
|
1623
1680
|
function renderConditionPreview(src, o) {
|
|
1624
|
-
|
|
1681
|
+
const cls = o.propertyActions ? "exed-preview exed-preview-interactive" : "exed-preview";
|
|
1682
|
+
return el("div", cls, [exprPills(src, o)]);
|
|
1625
1683
|
}
|
|
1626
1684
|
function renderEffectsPreview(effects, o) {
|
|
1627
1685
|
const wrap = el("div", "exed-preview exed-preview-effects");
|