@octaviaflow/core 3.1.0-beta.103 → 3.1.0-beta.105

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.
@@ -1 +1 @@
1
- {"version":3,"file":"ExpressionField.d.ts","sourceRoot":"","sources":["../../../src/components/ExpressionField/ExpressionField.tsx"],"names":[],"mappings":"AA2BA,OAAO,EAML,KAAK,aAAa,EAIlB,KAAK,SAAS,EACf,MAAM,OAAO,CAAC;AAUf,6EAA6E;AAC7E,MAAM,WAAW,gBAAgB;IAC/B,qEAAqE;IACrE,KAAK,EAAE,MAAM,CAAC;IACd,4DAA4D;IAC5D,IAAI,CAAC,EAAE,UAAU,GAAG,UAAU,CAAC;CAChC;AAED,uEAAuE;AACvE,MAAM,WAAW,aAAa;IAC5B,oEAAoE;IACpE,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,yDAAyD;IACzD,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;CACjB;AAED,MAAM,WAAW,oBAAoB;IACnC,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACjC,KAAK,CAAC,EAAE,SAAS,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,SAAS,CAAC;IACvB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,8DAA8D;IAC9D,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,aAAa,CAAC;IACtB;;;OAGG;IACH,YAAY,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,GAAG,SAAS,CAAC;IACrD;;;OAGG;IACH,WAAW,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,aAAa,GAAG,SAAS,CAAC;IAC1D;;;OAGG;IACH,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAMD,mEAAmE;AACnE,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAWzD;AAyBD;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,eAAe,EAAE,MAAM,GAAG,OAAO,CAiBpE;AAWD,wBAAgB,eAAe,CAAC,EAC9B,KAAK,EACL,QAAQ,EACR,KAAK,EACL,WAAW,EACX,UAAU,EACV,QAAgB,EAChB,IAAQ,EACR,EAAE,EACF,SAAS,EACT,KAAK,EACL,YAAY,EACZ,WAAW,EACX,cAAsB,EACtB,YAAY,EAAE,SAAS,GACxB,EAAE,oBAAoB,2CA+XtB;AA0HD,eAAe,eAAe,CAAC"}
1
+ {"version":3,"file":"ExpressionField.d.ts","sourceRoot":"","sources":["../../../src/components/ExpressionField/ExpressionField.tsx"],"names":[],"mappings":"AA2BA,OAAO,EAML,KAAK,aAAa,EAIlB,KAAK,SAAS,EACf,MAAM,OAAO,CAAC;AAaf,6EAA6E;AAC7E,MAAM,WAAW,gBAAgB;IAC/B,qEAAqE;IACrE,KAAK,EAAE,MAAM,CAAC;IACd,4DAA4D;IAC5D,IAAI,CAAC,EAAE,UAAU,GAAG,UAAU,CAAC;CAChC;AAED,uEAAuE;AACvE,MAAM,WAAW,aAAa;IAC5B,oEAAoE;IACpE,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,yDAAyD;IACzD,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;CACjB;AAED,MAAM,WAAW,oBAAoB;IACnC,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACjC,KAAK,CAAC,EAAE,SAAS,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,SAAS,CAAC;IACvB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,8DAA8D;IAC9D,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,aAAa,CAAC;IACtB;;;OAGG;IACH,YAAY,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,GAAG,SAAS,CAAC;IACrD;;;OAGG;IACH,WAAW,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,aAAa,GAAG,SAAS,CAAC;IAC1D;;;OAGG;IACH,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAMD,mEAAmE;AACnE,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAWzD;AAyBD;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,eAAe,EAAE,MAAM,GAAG,OAAO,CAiBpE;AAuBD,wBAAgB,eAAe,CAAC,EAC9B,KAAK,EACL,QAAQ,EACR,KAAK,EACL,WAAW,EACX,UAAU,EACV,QAAgB,EAChB,IAAQ,EACR,EAAE,EACF,SAAS,EACT,KAAK,EACL,YAAY,EACZ,WAAW,EACX,cAAsB,EACtB,YAAY,EAAE,SAAS,GACxB,EAAE,oBAAoB,2CAiZtB;AAuND,eAAe,eAAe,CAAC"}
@@ -32,4 +32,21 @@ export declare function formatCall(name: string, args: string[]): string;
32
32
  * not a call, for hosts whose tokens are their own short form.
33
33
  */
34
34
  export declare function parseExpression(value: string, pillEveryToken?: boolean): Segment[];
35
+ /** The call at `path`, or the top-level call for an empty path. */
36
+ export declare function callAt(raw: string, path: number[]): {
37
+ name: string;
38
+ args: string[];
39
+ } | undefined;
40
+ /** The argument text at `path`, e.g. `[0]` → the first argument. */
41
+ export declare function argumentAt(raw: string, path: number[]): string | undefined;
42
+ /** A nested call is written bare; only the outermost one wears braces. */
43
+ export declare function formatNestedCall(name: string, args: string[]): string;
44
+ /**
45
+ * Replace the argument at `path`, rebuilding every call on the way back up.
46
+ * An empty path replaces the whole expression.
47
+ */
48
+ export declare function replaceArgument(raw: string, path: number[], next: string): string;
49
+ /** What kind of thing an argument is — the editor shows each differently. */
50
+ export type ArgumentKind = "reference" | "call" | "literal";
51
+ export declare function argumentKind(arg: string): ArgumentKind;
35
52
  //# sourceMappingURL=parseExpression.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"parseExpression.d.ts","sourceRoot":"","sources":["../../../src/components/ExpressionField/parseExpression.ts"],"names":[],"mappings":"AASA,4EAA4E;AAC5E,eAAO,MAAM,gBAAgB,uDAAuD,CAAC;AAGrF,MAAM,MAAM,OAAO,GACf;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,GAC7B;IAAE,IAAI,EAAE,KAAK,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,GAC5B;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,EAAE,CAAA;CAAE,CAAC;AA2ChE;;;GAGG;AACH,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,EAAE,CA2CzD;AAED,gFAAgF;AAChF,wBAAgB,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,EAAE,CAAA;CAAE,GAAG,SAAS,CAQnF;AAED,yEAAyE;AACzE,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,MAAM,CAE/D;AAED;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,EAAE,cAAc,UAAQ,GAAG,OAAO,EAAE,CA8BhF"}
1
+ {"version":3,"file":"parseExpression.d.ts","sourceRoot":"","sources":["../../../src/components/ExpressionField/parseExpression.ts"],"names":[],"mappings":"AASA,4EAA4E;AAC5E,eAAO,MAAM,gBAAgB,uDAAuD,CAAC;AAGrF,MAAM,MAAM,OAAO,GACf;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,GAC7B;IAAE,IAAI,EAAE,KAAK,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,GAC5B;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,EAAE,CAAA;CAAE,CAAC;AA2ChE;;;GAGG;AACH,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,EAAE,CA2CzD;AAED,gFAAgF;AAChF,wBAAgB,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,EAAE,CAAA;CAAE,GAAG,SAAS,CAQnF;AAED,yEAAyE;AACzE,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,MAAM,CAE/D;AAED;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,EAAE,cAAc,UAAQ,GAAG,OAAO,EAAE,CA8BhF;AAQD,mEAAmE;AACnE,wBAAgB,MAAM,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,EAAE,CAAA;CAAE,GAAG,SAAS,CAShG;AAED,oEAAoE;AACpE,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,MAAM,GAAG,SAAS,CAI1E;AAED,0EAA0E;AAC1E,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,MAAM,CAErE;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAYjF;AAED,6EAA6E;AAC7E,MAAM,MAAM,YAAY,GAAG,WAAW,GAAG,MAAM,GAAG,SAAS,CAAC;AAE5D,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,YAAY,CAQtD"}
package/dist/index.cjs CHANGED
@@ -41467,6 +41467,39 @@ function parseExpression(value, pillEveryToken = false) {
41467
41467
  pushText(tail.slice(last));
41468
41468
  return segments;
41469
41469
  }
41470
+ function callAt(raw, path) {
41471
+ let current = parseCall(raw);
41472
+ for (const index of path) {
41473
+ if (!current) return void 0;
41474
+ const arg = current.args[index];
41475
+ if (arg === void 0) return void 0;
41476
+ current = parseCall(arg);
41477
+ }
41478
+ return current;
41479
+ }
41480
+ function formatNestedCall(name, args) {
41481
+ return `${name}(${args.filter((a) => a.trim() !== "").join(", ")})`;
41482
+ }
41483
+ function replaceArgument(raw, path, next) {
41484
+ if (path.length === 0) return next;
41485
+ const [index, ...rest] = path;
41486
+ const call = parseCall(raw);
41487
+ if (!call || index === void 0 || index > call.args.length) return raw;
41488
+ const args = [...call.args];
41489
+ if (args[index] === void 0) args[index] = "";
41490
+ args[index] = rest.length === 0 ? next : replaceArgument(args[index], rest, next);
41491
+ const wrapped = raw.trim().startsWith("{{");
41492
+ return wrapped ? formatCall(call.name, args) : formatNestedCall(call.name, args);
41493
+ }
41494
+ function argumentKind(arg) {
41495
+ const trimmed = arg.trim();
41496
+ if (!trimmed) return "literal";
41497
+ if (parseCall(trimmed)) return "call";
41498
+ if (trimmed.startsWith("{{") || trimmed.startsWith("ods://") || trimmed.startsWith("${")) {
41499
+ return "reference";
41500
+ }
41501
+ return "literal";
41502
+ }
41470
41503
 
41471
41504
  // src/components/ExpressionField/ExpressionField.tsx
41472
41505
  var import_jsx_runtime174 = require("react/jsx-runtime");
@@ -41525,8 +41558,14 @@ function insideCallArguments(textBeforeCaret) {
41525
41558
  }
41526
41559
  return depth > 0;
41527
41560
  }
41528
- function argSummary(arg) {
41561
+ function argSummary(arg, nameOf, depth = 2) {
41529
41562
  const trimmed = arg.trim();
41563
+ const call = parseCall(trimmed);
41564
+ if (call) {
41565
+ if (depth <= 0) return `${nameOf(call.name)}(\u2026)`;
41566
+ const inner = call.args.map((a) => argSummary(a, nameOf, depth - 1)).filter(Boolean).join(", ");
41567
+ return `${nameOf(call.name)}(${inner})`;
41568
+ }
41530
41569
  if (trimmed.startsWith("{{") || trimmed.startsWith("ods://") || trimmed.startsWith("${")) {
41531
41570
  return shortReferenceLabel(trimmed.startsWith("ods://") ? `{{${trimmed}}}` : trimmed);
41532
41571
  }
@@ -41564,7 +41603,7 @@ function ExpressionField({
41564
41603
  );
41565
41604
  const chipText = (0, import_react188.useCallback)(
41566
41605
  (name, args) => {
41567
- const summary = args.map(argSummary).filter(Boolean).join(", ");
41606
+ const summary = args.map((a) => argSummary(a, callLabel)).filter(Boolean).join(", ");
41568
41607
  return `${callLabel(name)}(${summary})`;
41569
41608
  },
41570
41609
  [callLabel]
@@ -41583,8 +41622,18 @@ function ExpressionField({
41583
41622
  } else {
41584
41623
  el.className = CHIP;
41585
41624
  el.setAttribute("data-call", segment.name);
41586
- el.textContent = chipText(segment.name, segment.args);
41587
41625
  el.title = segment.raw;
41626
+ const text = document.createElement("span");
41627
+ text.className = "ods-expression-field__chip-text";
41628
+ text.textContent = chipText(segment.name, segment.args);
41629
+ el.appendChild(text);
41630
+ const open = document.createElement("span");
41631
+ open.className = "ods-expression-field__chip-open";
41632
+ open.setAttribute("data-open", "true");
41633
+ open.setAttribute("role", "button");
41634
+ open.setAttribute("aria-label", "Edit arguments");
41635
+ open.textContent = "\u2304";
41636
+ el.appendChild(open);
41588
41637
  }
41589
41638
  return el;
41590
41639
  },
@@ -41690,27 +41739,28 @@ function ExpressionField({
41690
41739
  }, []);
41691
41740
  const openEditor = (0, import_react188.useCallback)((chip) => {
41692
41741
  const raw = chip.getAttribute("data-value") ?? "";
41693
- const parsed = parseCall(raw);
41694
- if (!parsed) return;
41742
+ if (!parseCall(raw)) return;
41695
41743
  const box = chip.getBoundingClientRect();
41696
41744
  const host = fieldRef.current?.getBoundingClientRect();
41697
41745
  setEditing({
41698
41746
  el: chip,
41699
- name: parsed.name,
41700
- args: parsed.args.length ? parsed.args : [""],
41747
+ raw,
41701
41748
  rect: {
41702
41749
  top: box.bottom - (host?.top ?? 0) + 4,
41703
41750
  left: Math.max(0, box.left - (host?.left ?? 0)),
41704
- width: Math.max(260, box.width)
41751
+ width: Math.max(300, box.width)
41705
41752
  }
41706
41753
  });
41707
41754
  }, []);
41708
41755
  const applyEditor = (0, import_react188.useCallback)(
41709
- (args) => {
41756
+ (raw) => {
41710
41757
  if (!editing) return;
41711
- const raw = formatCall(editing.name, args);
41758
+ const call = parseCall(raw);
41759
+ if (!call) return;
41712
41760
  editing.el.setAttribute("data-value", raw);
41713
- editing.el.textContent = chipText(editing.name, args);
41761
+ const text = editing.el.querySelector(".ods-expression-field__chip-text");
41762
+ if (text) text.textContent = chipText(call.name, call.args);
41763
+ else editing.el.textContent = chipText(call.name, call.args);
41714
41764
  editing.el.title = raw;
41715
41765
  setEditing(null);
41716
41766
  commit();
@@ -41720,12 +41770,13 @@ function ExpressionField({
41720
41770
  );
41721
41771
  const handleClick = (0, import_react188.useCallback)(
41722
41772
  (e) => {
41723
- const target = e.target.closest(`.${PILL}, .${CHIP}`);
41773
+ const node = e.target;
41774
+ const target = node.closest(`.${PILL}, .${CHIP}`);
41724
41775
  if (!target) return;
41725
- selectToken(target);
41726
- if (!disabled && target.classList.contains(CHIP) && e.detail >= 2) {
41727
- openEditor(target);
41728
- }
41776
+ const chipEl = target;
41777
+ const wantsEditor = chipEl.classList.contains(CHIP) && (!!node.closest("[data-open]") || e.detail >= 2);
41778
+ selectToken(chipEl);
41779
+ if (!disabled && wantsEditor) openEditor(chipEl);
41729
41780
  },
41730
41781
  [disabled, openEditor, selectToken]
41731
41782
  );
@@ -41844,11 +41895,11 @@ function ExpressionField({
41844
41895
  editing && /* @__PURE__ */ (0, import_jsx_runtime174.jsx)(
41845
41896
  CallEditor,
41846
41897
  {
41847
- name: editing.name,
41848
- label: callLabel(editing.name),
41849
- initialArgs: editing.args,
41850
- signature: resolveCall?.(editing.name),
41898
+ raw: editing.raw,
41851
41899
  rect: editing.rect,
41900
+ nameOf: callLabel,
41901
+ labelFor,
41902
+ resolveCall,
41852
41903
  onCancel: () => setEditing(null),
41853
41904
  onApply: applyEditor
41854
41905
  }
@@ -41858,36 +41909,44 @@ function ExpressionField({
41858
41909
  ] });
41859
41910
  }
41860
41911
  function CallEditor({
41861
- name,
41862
- label,
41863
- initialArgs,
41864
- signature,
41912
+ raw,
41865
41913
  rect,
41914
+ nameOf,
41915
+ labelFor,
41916
+ resolveCall,
41866
41917
  onApply,
41867
41918
  onCancel
41868
41919
  }) {
41869
- const names = signature?.args ?? [];
41870
- const [args, setArgs] = (0, import_react188.useState)(() => {
41871
- const seeded = [...initialArgs];
41872
- while (seeded.length < names.length) seeded.push("");
41873
- return seeded.length ? seeded : [""];
41874
- });
41875
- const [raw, setRaw] = (0, import_react188.useState)(null);
41920
+ const [draft, setDraft] = (0, import_react188.useState)(raw);
41921
+ const [path, setPath] = (0, import_react188.useState)([]);
41922
+ const [rawMode, setRawMode] = (0, import_react188.useState)(false);
41876
41923
  const panelRef = (0, import_react188.useRef)(null);
41877
41924
  (0, import_react188.useEffect)(() => {
41878
- panelRef.current?.querySelector("input")?.focus();
41879
41925
  const onKey = (e) => {
41880
41926
  if (e.key === "Escape") onCancel();
41881
41927
  };
41882
41928
  document.addEventListener("keydown", onKey);
41883
41929
  return () => document.removeEventListener("keydown", onKey);
41884
41930
  }, [onCancel]);
41885
- const setArg = (idx, next) => setArgs((prev) => prev.map((a, i) => i === idx ? next : a));
41886
- const dropInto = (idx) => (e) => {
41887
- const ref = e.dataTransfer.getData("application/x-fx-insert");
41888
- if (!ref) return;
41931
+ const current = callAt(draft, path);
41932
+ const signature = current ? resolveCall?.(current.name) : void 0;
41933
+ const names = signature?.args ?? [];
41934
+ const args = current ? current.args.length ? current.args : [""] : [];
41935
+ const crumbs = [];
41936
+ for (let i = 0; i <= path.length; i++) {
41937
+ const at = callAt(draft, path.slice(0, i));
41938
+ if (at) crumbs.push({ label: nameOf(at.name), path: path.slice(0, i) });
41939
+ }
41940
+ const setArg = (index, next) => setDraft((d) => replaceArgument(d, [...path, index], next));
41941
+ const dropInto = (index) => (e) => {
41942
+ const dropped = e.dataTransfer.getData("application/x-fx-insert");
41943
+ if (!dropped) return;
41889
41944
  e.preventDefault();
41890
- setArg(idx, ref);
41945
+ e.stopPropagation();
41946
+ const kind = e.dataTransfer.getData("application/x-fx-type");
41947
+ const bare = dropped.startsWith("{{") && dropped.endsWith("}}") ? dropped.slice(2, -2).trim() : dropped;
41948
+ setDraft((d) => replaceArgument(d, [...path, index], bare));
41949
+ if (kind === "function" || parseCall(bare)) setPath((pth) => [...pth, index]);
41891
41950
  };
41892
41951
  return /* @__PURE__ */ (0, import_jsx_runtime174.jsxs)(
41893
41952
  "div",
@@ -41896,49 +41955,122 @@ function CallEditor({
41896
41955
  className: "ods-expression-field__editor",
41897
41956
  style: { top: rect.top, left: rect.left, width: rect.width },
41898
41957
  role: "dialog",
41899
- "aria-label": `Edit ${label}`,
41958
+ "aria-label": `Edit ${crumbs[0]?.label ?? "function"}`,
41900
41959
  children: [
41901
41960
  /* @__PURE__ */ (0, import_jsx_runtime174.jsxs)("div", { className: "ods-expression-field__editor-head", children: [
41902
- /* @__PURE__ */ (0, import_jsx_runtime174.jsx)("code", { children: label }),
41903
- /* @__PURE__ */ (0, import_jsx_runtime174.jsx)("button", { type: "button", className: "ods-expression-field__editor-link", onClick: () => setRaw(raw === null ? formatCall(name, args) : null), children: raw === null ? "Edit as text" : "Back to fields" })
41904
- ] }),
41905
- raw === null ? /* @__PURE__ */ (0, import_jsx_runtime174.jsxs)("div", { className: "ods-expression-field__editor-rows", children: [
41906
- args.map((arg, idx) => (
41907
- // eslint-disable-next-line react/no-array-index-key
41908
- /* @__PURE__ */ (0, import_jsx_runtime174.jsxs)("label", { className: "ods-expression-field__editor-row", children: [
41909
- /* @__PURE__ */ (0, import_jsx_runtime174.jsx)("span", { children: names[idx] ?? `argument ${idx + 1}` }),
41910
- /* @__PURE__ */ (0, import_jsx_runtime174.jsx)(
41911
- "input",
41912
- {
41913
- value: arg,
41914
- placeholder: "value, or drag one in",
41915
- onChange: (e) => setArg(idx, e.target.value),
41916
- onDragOver: (e) => {
41917
- if (e.dataTransfer.types.includes("application/x-fx-insert")) e.preventDefault();
41918
- },
41919
- onDrop: dropInto(idx)
41920
- }
41921
- )
41922
- ] }, idx)
41923
- )),
41961
+ /* @__PURE__ */ (0, import_jsx_runtime174.jsx)("nav", { className: "ods-expression-field__editor-crumbs", "aria-label": "Nested functions", children: crumbs.map((crumb, i) => /* @__PURE__ */ (0, import_jsx_runtime174.jsxs)("span", { children: [
41962
+ i > 0 && /* @__PURE__ */ (0, import_jsx_runtime174.jsx)("span", { "aria-hidden": "true", children: " \u203A " }),
41963
+ /* @__PURE__ */ (0, import_jsx_runtime174.jsx)(
41964
+ "button",
41965
+ {
41966
+ type: "button",
41967
+ disabled: i === crumbs.length - 1,
41968
+ onClick: () => setPath(crumb.path),
41969
+ children: crumb.label
41970
+ }
41971
+ )
41972
+ ] }, crumb.path.join(".") || "root")) }),
41924
41973
  /* @__PURE__ */ (0, import_jsx_runtime174.jsx)(
41925
41974
  "button",
41926
41975
  {
41927
41976
  type: "button",
41928
41977
  className: "ods-expression-field__editor-link",
41929
- onClick: () => setArgs((prev) => [...prev, ""]),
41930
- children: "+ argument"
41978
+ onClick: () => setRawMode((r) => !r),
41979
+ children: rawMode ? "Back to fields" : "Edit as text"
41931
41980
  }
41932
41981
  )
41933
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime174.jsx)(
41982
+ ] }),
41983
+ rawMode ? /* @__PURE__ */ (0, import_jsx_runtime174.jsx)(
41934
41984
  "textarea",
41935
41985
  {
41936
41986
  className: "ods-expression-field__editor-raw",
41937
- value: raw,
41987
+ value: draft,
41938
41988
  rows: 3,
41939
- onChange: (e) => setRaw(e.target.value)
41989
+ "aria-label": "Expression",
41990
+ onChange: (e) => setDraft(e.target.value)
41940
41991
  }
41941
- ),
41992
+ ) : /* @__PURE__ */ (0, import_jsx_runtime174.jsxs)("div", { className: "ods-expression-field__editor-rows", children: [
41993
+ args.map((arg, index) => {
41994
+ const kind = argumentKind(arg);
41995
+ const rowLabel = names[index] ?? `argument ${index + 1}`;
41996
+ const nested = kind === "call" ? parseCall(arg) : void 0;
41997
+ return (
41998
+ // eslint-disable-next-line react/no-array-index-key
41999
+ /* @__PURE__ */ (0, import_jsx_runtime174.jsxs)("div", { className: "ods-expression-field__editor-row", children: [
42000
+ /* @__PURE__ */ (0, import_jsx_runtime174.jsx)("span", { id: `arg-${index}-label`, children: rowLabel }),
42001
+ nested ? /* @__PURE__ */ (0, import_jsx_runtime174.jsxs)(
42002
+ "div",
42003
+ {
42004
+ className: "ods-expression-field__editor-nested",
42005
+ onDragOver: (e) => {
42006
+ if (e.dataTransfer.types.includes("application/x-fx-insert")) e.preventDefault();
42007
+ },
42008
+ onDrop: dropInto(index),
42009
+ children: [
42010
+ /* @__PURE__ */ (0, import_jsx_runtime174.jsx)("code", { children: argSummary(arg, nameOf) }),
42011
+ /* @__PURE__ */ (0, import_jsx_runtime174.jsxs)("span", { children: [
42012
+ /* @__PURE__ */ (0, import_jsx_runtime174.jsx)("button", { type: "button", onClick: () => setPath([...path, index]), children: "Open" }),
42013
+ /* @__PURE__ */ (0, import_jsx_runtime174.jsx)("button", { type: "button", onClick: () => setArg(index, ""), "aria-label": `Clear ${rowLabel}`, children: "Clear" })
42014
+ ] })
42015
+ ]
42016
+ }
42017
+ ) : kind === "reference" ? (
42018
+ // A reference is a value from somewhere else — named, never
42019
+ // its raw `ods://…` path, here as much as in the field.
42020
+ /* @__PURE__ */ (0, import_jsx_runtime174.jsxs)(
42021
+ "div",
42022
+ {
42023
+ className: "ods-expression-field__editor-ref",
42024
+ onDragOver: (e) => {
42025
+ if (e.dataTransfer.types.includes("application/x-fx-insert")) e.preventDefault();
42026
+ },
42027
+ onDrop: dropInto(index),
42028
+ children: [
42029
+ /* @__PURE__ */ (0, import_jsx_runtime174.jsx)(
42030
+ "span",
42031
+ {
42032
+ className: "ods-expression-field__pill",
42033
+ title: arg,
42034
+ "aria-labelledby": `arg-${index}-label`,
42035
+ children: labelFor(arg.startsWith("ods://") ? `{{${arg}}}` : arg)
42036
+ }
42037
+ ),
42038
+ /* @__PURE__ */ (0, import_jsx_runtime174.jsx)("button", { type: "button", onClick: () => setArg(index, ""), "aria-label": `Clear ${rowLabel}`, children: "Clear" })
42039
+ ]
42040
+ }
42041
+ )
42042
+ ) : /* @__PURE__ */ (0, import_jsx_runtime174.jsx)(
42043
+ "input",
42044
+ {
42045
+ "aria-labelledby": `arg-${index}-label`,
42046
+ value: arg,
42047
+ placeholder: 'a value, "text", or drag one in',
42048
+ "data-kind": kind,
42049
+ onChange: (e) => setArg(index, e.target.value),
42050
+ onDragOver: (e) => {
42051
+ if (e.dataTransfer.types.includes("application/x-fx-insert")) e.preventDefault();
42052
+ },
42053
+ onDrop: dropInto(index)
42054
+ }
42055
+ )
42056
+ ] }, index)
42057
+ );
42058
+ }),
42059
+ /* @__PURE__ */ (0, import_jsx_runtime174.jsx)(
42060
+ "button",
42061
+ {
42062
+ type: "button",
42063
+ className: "ods-expression-field__editor-link",
42064
+ onClick: () => setDraft((d) => {
42065
+ const at = callAt(d, path);
42066
+ if (!at) return d;
42067
+ const next = [...at.args, '""'];
42068
+ return path.length === 0 ? formatCall(at.name, next) : replaceArgument(d, path, `${at.name}(${next.join(", ")})`);
42069
+ }),
42070
+ children: "+ argument"
42071
+ }
42072
+ )
42073
+ ] }),
41942
42074
  /* @__PURE__ */ (0, import_jsx_runtime174.jsxs)("div", { className: "ods-expression-field__editor-foot", children: [
41943
42075
  /* @__PURE__ */ (0, import_jsx_runtime174.jsx)("button", { type: "button", onClick: onCancel, children: "Cancel" }),
41944
42076
  /* @__PURE__ */ (0, import_jsx_runtime174.jsx)(
@@ -41946,11 +42078,7 @@ function CallEditor({
41946
42078
  {
41947
42079
  type: "button",
41948
42080
  className: "ods-expression-field__editor-primary",
41949
- onClick: () => {
41950
- if (raw === null) return onApply(args);
41951
- const parsed = parseCall(raw);
41952
- onApply(parsed ? parsed.args : splitArguments(raw));
41953
- },
42081
+ onClick: () => onApply(draft),
41954
42082
  children: "Apply"
41955
42083
  }
41956
42084
  )