@wildwinter/expr-editor 0.4.0 → 0.5.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 CHANGED
@@ -50,6 +50,11 @@ Notable options beyond the basics:
50
50
  outcome-style value cell: `valueEnumValues` offers a target's enum values on
51
51
  the root literal, and `valueField` makes an empty value render one editable
52
52
  "set a value…" pill instead of the condition clause-menu empty state.
53
+ - `flagValue: { target }` — flat compact editor for a `set_flags(@target, …)`
54
+ value whose target is implied by context: renders only the flag-delta pills
55
+ plus an "+ flag" chip, hiding the function name and target arg, and seeds the
56
+ call on the first flag add. Pair with `requireNonEmpty` so the last flag
57
+ can't be removed.
53
58
  - `setText(on)` — the host's raw-text toggle (`</>`); unparseable input falls
54
59
  back to raw text automatically.
55
60
 
package/dist/index.cjs CHANGED
@@ -541,7 +541,9 @@ function flagEditor(ctx, path, node, anchor) {
541
541
  const call = getNodeAt(ctx.getAst(), callPath);
542
542
  const flagsVar = call?.kind === "call" ? call.args[0] : void 0;
543
543
  const entry = flagsVar?.kind === "scopedvar" ? lookup(ctx.catalogue, flagsVar.scope, flagsVar.name) : null;
544
+ const flagCount = call?.kind === "call" ? call.args.filter((a) => a.kind === "flagdelta").length : 0;
544
545
  const used = call?.kind === "call" ? call.args.filter((a, i) => a.kind === "flagdelta" && i !== path[path.length - 1]).map((a) => a.name) : [];
546
+ const canRemove = !(ctx.requireNonEmpty && flagCount <= 1);
545
547
  ctx.openPopover(anchor, (close) => {
546
548
  const wrap = el("div", "exed-menu");
547
549
  wrap.append(el("div", "exed-menu-head", ["Flag set?"]));
@@ -566,6 +568,12 @@ function flagEditor(ctx, path, node, anchor) {
566
568
  close();
567
569
  } }));
568
570
  }
571
+ if (canRemove) {
572
+ wrap.append(button("exed-opt danger", "Remove flag", () => {
573
+ ctx.apply(deleteAt(ctx.getAst(), path));
574
+ close();
575
+ }));
576
+ }
569
577
  return wrap;
570
578
  });
571
579
  }
@@ -1075,8 +1083,12 @@ function mountExpressionEditor(host, opts) {
1075
1083
  closePopover();
1076
1084
  host.replaceChildren();
1077
1085
  const v = validateSource(src, opts.schema, opts.dialect);
1078
- if (raw || v.unparseable) {
1086
+ const flagCompact = !!opts.flagValue && (opts.mode ?? "tree") === "flat";
1087
+ const astIsFlagCall = v.ast?.kind === "call" && (v.ast.name === "set_flags" || v.ast.name === "check_flags");
1088
+ if (raw || v.unparseable || flagCompact && !!v.ast && !astIsFlagCall) {
1079
1089
  host.append(rawArea());
1090
+ } else if (flagCompact) {
1091
+ host.append(flagValueBody(astIsFlagCall ? v.ast : null));
1080
1092
  } else if (!src.trim() || !v.ast) {
1081
1093
  host.append(opts.valueField ? valueEmptyState() : emptyState());
1082
1094
  } else {
@@ -1126,6 +1138,36 @@ function mountExpressionEditor(host, opts) {
1126
1138
  const ctx = buildCtx(strLit(""));
1127
1139
  return el("div", "exed-flat", [renderNode(strLit(""), [], ctx)]);
1128
1140
  }
1141
+ function parseRef(ref) {
1142
+ const bare = ref.replace(/^@/, "");
1143
+ const dot = bare.indexOf(".");
1144
+ return dot >= 0 ? scopedVar(bare.slice(0, dot), bare.slice(dot + 1)) : scopedVar(defaultScope, bare);
1145
+ }
1146
+ function flagValueBody(call) {
1147
+ const wrap = el("div", "exed-flat exed-flagvalue");
1148
+ if (call) {
1149
+ const ctx = buildCtx(call);
1150
+ call.args.forEach((arg, i) => {
1151
+ if (arg.kind === "flagdelta") wrap.append(renderNode(arg, ["args", i], ctx));
1152
+ });
1153
+ wrap.append(addFlagChip(call));
1154
+ } else {
1155
+ wrap.append(addFlagChip(null));
1156
+ }
1157
+ return wrap;
1158
+ }
1159
+ function addFlagChip(call) {
1160
+ return button("exed-add exed-addflag", "+ flag", () => {
1161
+ if (call) {
1162
+ pendingFocus = ["args", call.args.length];
1163
+ emit(toSrc({ ...call, args: [...call.args, flagDelta("+", "")] }));
1164
+ } else {
1165
+ const seeded = callNode("set_flags", [parseRef(opts.flagValue.target), flagDelta("+", "")]);
1166
+ pendingFocus = ["args", 1];
1167
+ emit(toSrc(seeded));
1168
+ }
1169
+ }, "add a flag");
1170
+ }
1129
1171
  function addTermControl(ctx) {
1130
1172
  const boolean = opts.addTerm === "boolean";
1131
1173
  const ops = boolean ? ["and", "or"] : ARITHMETIC_OPS;