@octaviaflow/core 3.1.0-beta.108 → 3.1.0-beta.109

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.js CHANGED
@@ -34446,6 +34446,7 @@ import {
34446
34446
  useRef as useRef50,
34447
34447
  useState as useState71
34448
34448
  } from "react";
34449
+ import { createPortal as createPortal19 } from "react-dom";
34449
34450
  import { AddIcon as AddIcon6, CloseIcon as CloseIcon20 } from "@octaviaflow/icons";
34450
34451
 
34451
34452
  // src/components/ExpressionField/parseExpression.ts
@@ -34666,6 +34667,16 @@ function insideCallArguments(textBeforeCaret) {
34666
34667
  }
34667
34668
  return depth > 0;
34668
34669
  }
34670
+ function anchorRect(el) {
34671
+ const box = el.getBoundingClientRect();
34672
+ const width = Math.max(300, box.width);
34673
+ return {
34674
+ top: box.bottom + 4,
34675
+ // Keep it on screen when the chip sits near the right edge.
34676
+ left: Math.max(8, Math.min(box.left, window.innerWidth - width - 8)),
34677
+ width
34678
+ };
34679
+ }
34669
34680
  function argSummary(arg, nameOf, depth = 2) {
34670
34681
  const trimmed = arg.trim();
34671
34682
  const call = parseCall(trimmed);
@@ -34854,17 +34865,7 @@ function ExpressionField({
34854
34865
  const openEditor = useCallback50((chip) => {
34855
34866
  const raw = chip.getAttribute("data-value") ?? "";
34856
34867
  if (!parseCall(raw)) return;
34857
- const box = chip.getBoundingClientRect();
34858
- const host = fieldRef.current?.getBoundingClientRect();
34859
- setEditing({
34860
- el: chip,
34861
- raw,
34862
- rect: {
34863
- top: box.bottom - (host?.top ?? 0) + 4,
34864
- left: Math.max(0, box.left - (host?.left ?? 0)),
34865
- width: Math.max(300, box.width)
34866
- }
34867
- });
34868
+ setEditing({ el: chip, raw, rect: anchorRect(chip) });
34868
34869
  }, []);
34869
34870
  const applyEditor = useCallback50(
34870
34871
  (raw) => {
@@ -35090,158 +35091,173 @@ function CallEditor({
35090
35091
  setDraft((d) => replaceArgument(d, [...path, index], bare));
35091
35092
  if (kind === "function" || parseCall(bare)) setPath((pth) => [...pth, index]);
35092
35093
  };
35093
- return /* @__PURE__ */ jsxs141(
35094
- "div",
35095
- {
35096
- ref: panelRef,
35097
- className: "ods-expression-field__editor",
35098
- style: { top: rect.top, left: rect.left, width: rect.width },
35099
- role: "dialog",
35100
- "aria-label": `Edit ${crumbs[0]?.label ?? "function"}`,
35101
- children: [
35102
- /* @__PURE__ */ jsxs141("div", { className: "ods-expression-field__editor-head", children: [
35103
- /* @__PURE__ */ jsx147(
35104
- Breadcrumb,
35094
+ const [pos, setPos] = useState71(rect);
35095
+ useEffect56(() => {
35096
+ const follow = () => setPos(anchorRect(anchor));
35097
+ window.addEventListener("scroll", follow, true);
35098
+ window.addEventListener("resize", follow);
35099
+ return () => {
35100
+ window.removeEventListener("scroll", follow, true);
35101
+ window.removeEventListener("resize", follow);
35102
+ };
35103
+ }, [anchor]);
35104
+ if (typeof document === "undefined") return null;
35105
+ return createPortal19(
35106
+ /* @__PURE__ */ jsxs141(
35107
+ "div",
35108
+ {
35109
+ ref: panelRef,
35110
+ "data-ods-floating": "",
35111
+ className: "ods-expression-field__editor",
35112
+ style: { top: pos.top, left: pos.left, width: pos.width },
35113
+ role: "dialog",
35114
+ "aria-label": `Edit ${crumbs[0]?.label ?? "function"}`,
35115
+ children: [
35116
+ /* @__PURE__ */ jsxs141("div", { className: "ods-expression-field__editor-head", children: [
35117
+ /* @__PURE__ */ jsx147(
35118
+ Breadcrumb,
35119
+ {
35120
+ className: "ods-expression-field__editor-crumbs",
35121
+ items: crumbs.map((crumb) => ({
35122
+ label: crumb.label,
35123
+ onClick: () => setPath(crumb.path)
35124
+ }))
35125
+ }
35126
+ ),
35127
+ /* @__PURE__ */ jsx147(Button, { variant: "ghost", size: "sm", onClick: () => setRawMode((r) => !r), children: rawMode ? "Back to fields" : "Edit as text" })
35128
+ ] }),
35129
+ rawMode ? /* @__PURE__ */ jsx147(
35130
+ "textarea",
35105
35131
  {
35106
- className: "ods-expression-field__editor-crumbs",
35107
- items: crumbs.map((crumb) => ({
35108
- label: crumb.label,
35109
- onClick: () => setPath(crumb.path)
35110
- }))
35132
+ className: "ods-expression-field__editor-raw",
35133
+ value: draft,
35134
+ rows: 3,
35135
+ "aria-label": "Expression",
35136
+ onChange: (e) => setDraft(e.target.value)
35111
35137
  }
35112
- ),
35113
- /* @__PURE__ */ jsx147(Button, { variant: "ghost", size: "sm", onClick: () => setRawMode((r) => !r), children: rawMode ? "Back to fields" : "Edit as text" })
35114
- ] }),
35115
- rawMode ? /* @__PURE__ */ jsx147(
35116
- "textarea",
35117
- {
35118
- className: "ods-expression-field__editor-raw",
35119
- value: draft,
35120
- rows: 3,
35121
- "aria-label": "Expression",
35122
- onChange: (e) => setDraft(e.target.value)
35123
- }
35124
- ) : /* @__PURE__ */ jsxs141("div", { className: "ods-expression-field__editor-rows", children: [
35125
- args.map((arg, index) => {
35126
- const kind = argumentKind(arg);
35127
- const rowLabel = names[index] ?? `argument ${index + 1}`;
35128
- const nested = kind === "call" ? parseCall(arg) : void 0;
35129
- return (
35130
- // eslint-disable-next-line react/no-array-index-key
35131
- /* @__PURE__ */ jsxs141("div", { className: "ods-expression-field__editor-row", children: [
35132
- /* @__PURE__ */ jsxs141("span", { className: "ods-expression-field__editor-row-head", children: [
35133
- /* @__PURE__ */ jsx147("span", { className: "ods-expression-field__editor-row-name", id: `arg-${index}-label`, children: rowLabel }),
35134
- /* @__PURE__ */ jsx147(
35135
- Button,
35136
- {
35137
- variant: "icon",
35138
- size: "sm",
35139
- "aria-label": `Remove ${rowLabel}`,
35140
- title: "Remove this argument",
35141
- onClick: () => removeArg(index),
35142
- children: /* @__PURE__ */ jsx147(CloseIcon20, { size: "sm" })
35143
- }
35144
- )
35145
- ] }),
35146
- nested ? /* @__PURE__ */ jsxs141(
35147
- "div",
35148
- {
35149
- className: "ods-expression-field__editor-nested",
35150
- onDragOver: (e) => {
35151
- if (e.dataTransfer.types.includes("application/x-fx-insert")) e.preventDefault();
35152
- },
35153
- onDrop: dropInto(index),
35154
- children: [
35155
- /* @__PURE__ */ jsx147("code", { children: argSummary(arg, nameOf) }),
35156
- /* @__PURE__ */ jsxs141("span", { children: [
35157
- /* @__PURE__ */ jsx147(Button, { variant: "secondary", size: "sm", onClick: () => setPath([...path, index]), children: "Open" }),
35158
- /* @__PURE__ */ jsx147(
35159
- Button,
35160
- {
35161
- variant: "ghost",
35162
- size: "sm",
35163
- "aria-label": `Clear ${rowLabel}`,
35164
- onClick: () => setArg(index, ""),
35165
- children: "Clear"
35166
- }
35167
- )
35168
- ] })
35169
- ]
35170
- }
35171
- ) : kind === "reference" ? (
35172
- // A reference is a value from somewhere else — named, never
35173
- // its raw `ods://…` path, here as much as in the field.
35174
- /* @__PURE__ */ jsxs141(
35138
+ ) : /* @__PURE__ */ jsxs141("div", { className: "ods-expression-field__editor-rows", children: [
35139
+ args.map((arg, index) => {
35140
+ const kind = argumentKind(arg);
35141
+ const rowLabel = names[index] ?? `argument ${index + 1}`;
35142
+ const nested = kind === "call" ? parseCall(arg) : void 0;
35143
+ return (
35144
+ // eslint-disable-next-line react/no-array-index-key
35145
+ /* @__PURE__ */ jsxs141("div", { className: "ods-expression-field__editor-row", children: [
35146
+ /* @__PURE__ */ jsxs141("span", { className: "ods-expression-field__editor-row-head", children: [
35147
+ /* @__PURE__ */ jsx147("span", { className: "ods-expression-field__editor-row-name", id: `arg-${index}-label`, children: rowLabel }),
35148
+ /* @__PURE__ */ jsx147(
35149
+ Button,
35150
+ {
35151
+ variant: "icon",
35152
+ size: "sm",
35153
+ "aria-label": `Remove ${rowLabel}`,
35154
+ title: "Remove this argument",
35155
+ onClick: () => removeArg(index),
35156
+ children: /* @__PURE__ */ jsx147(CloseIcon20, { size: "sm" })
35157
+ }
35158
+ )
35159
+ ] }),
35160
+ nested ? /* @__PURE__ */ jsxs141(
35175
35161
  "div",
35176
35162
  {
35177
- className: "ods-expression-field__editor-ref",
35163
+ className: "ods-expression-field__editor-nested",
35178
35164
  onDragOver: (e) => {
35179
35165
  if (e.dataTransfer.types.includes("application/x-fx-insert")) e.preventDefault();
35180
35166
  },
35181
35167
  onDrop: dropInto(index),
35182
35168
  children: [
35183
- /* @__PURE__ */ jsx147(
35184
- "span",
35185
- {
35186
- className: "ods-expression-field__pill",
35187
- title: arg,
35188
- "aria-labelledby": `arg-${index}-label`,
35189
- children: labelFor(arg.startsWith("ods://") ? `{{${arg}}}` : arg)
35190
- }
35191
- ),
35192
- /* @__PURE__ */ jsx147(
35193
- Button,
35194
- {
35195
- variant: "ghost",
35196
- size: "sm",
35197
- "aria-label": `Clear ${rowLabel}`,
35198
- onClick: () => setArg(index, ""),
35199
- children: "Clear"
35200
- }
35201
- )
35169
+ /* @__PURE__ */ jsx147("code", { children: argSummary(arg, nameOf) }),
35170
+ /* @__PURE__ */ jsxs141("span", { children: [
35171
+ /* @__PURE__ */ jsx147(Button, { variant: "secondary", size: "sm", onClick: () => setPath([...path, index]), children: "Open" }),
35172
+ /* @__PURE__ */ jsx147(
35173
+ Button,
35174
+ {
35175
+ variant: "ghost",
35176
+ size: "sm",
35177
+ "aria-label": `Clear ${rowLabel}`,
35178
+ onClick: () => setArg(index, ""),
35179
+ children: "Clear"
35180
+ }
35181
+ )
35182
+ ] })
35202
35183
  ]
35203
35184
  }
35185
+ ) : kind === "reference" ? (
35186
+ // A reference is a value from somewhere else — named, never
35187
+ // its raw `ods://…` path, here as much as in the field.
35188
+ /* @__PURE__ */ jsxs141(
35189
+ "div",
35190
+ {
35191
+ className: "ods-expression-field__editor-ref",
35192
+ onDragOver: (e) => {
35193
+ if (e.dataTransfer.types.includes("application/x-fx-insert")) e.preventDefault();
35194
+ },
35195
+ onDrop: dropInto(index),
35196
+ children: [
35197
+ /* @__PURE__ */ jsx147(
35198
+ "span",
35199
+ {
35200
+ className: "ods-expression-field__pill",
35201
+ title: arg,
35202
+ "aria-labelledby": `arg-${index}-label`,
35203
+ children: labelFor(arg.startsWith("ods://") ? `{{${arg}}}` : arg)
35204
+ }
35205
+ ),
35206
+ /* @__PURE__ */ jsx147(
35207
+ Button,
35208
+ {
35209
+ variant: "ghost",
35210
+ size: "sm",
35211
+ "aria-label": `Clear ${rowLabel}`,
35212
+ onClick: () => setArg(index, ""),
35213
+ children: "Clear"
35214
+ }
35215
+ )
35216
+ ]
35217
+ }
35218
+ )
35219
+ ) : /* @__PURE__ */ jsx147(
35220
+ "input",
35221
+ {
35222
+ "aria-labelledby": `arg-${index}-label`,
35223
+ value: arg,
35224
+ placeholder: 'a value, "text", or drag one in',
35225
+ "data-kind": kind,
35226
+ onChange: (e) => setArg(index, e.target.value),
35227
+ onDragOver: (e) => {
35228
+ if (e.dataTransfer.types.includes("application/x-fx-insert")) e.preventDefault();
35229
+ },
35230
+ onDrop: dropInto(index)
35231
+ }
35204
35232
  )
35205
- ) : /* @__PURE__ */ jsx147(
35206
- "input",
35207
- {
35208
- "aria-labelledby": `arg-${index}-label`,
35209
- value: arg,
35210
- placeholder: 'a value, "text", or drag one in',
35211
- "data-kind": kind,
35212
- onChange: (e) => setArg(index, e.target.value),
35213
- onDragOver: (e) => {
35214
- if (e.dataTransfer.types.includes("application/x-fx-insert")) e.preventDefault();
35215
- },
35216
- onDrop: dropInto(index)
35217
- }
35218
- )
35219
- ] }, index)
35220
- );
35221
- }),
35222
- /* @__PURE__ */ jsx147(
35223
- Button,
35224
- {
35225
- variant: "ghost",
35226
- size: "sm",
35227
- fullWidth: true,
35228
- leftIcon: /* @__PURE__ */ jsx147(AddIcon6, { size: "sm" }),
35229
- onClick: () => setDraft((d) => {
35230
- const at = callAt(d, path);
35231
- if (!at) return d;
35232
- const next = [...at.args, '""'];
35233
- return path.length === 0 ? formatCall(at.name, next) : replaceArgument(d, path, `${at.name}(${next.join(", ")})`);
35234
- }),
35235
- children: "Add argument"
35236
- }
35237
- )
35238
- ] }),
35239
- /* @__PURE__ */ jsxs141("div", { className: "ods-expression-field__editor-foot", children: [
35240
- /* @__PURE__ */ jsx147(Button, { variant: "secondary", size: "sm", onClick: onCancel, children: "Cancel" }),
35241
- /* @__PURE__ */ jsx147(Button, { variant: "primary", size: "sm", onClick: () => onApply(draft), children: "Apply" })
35242
- ] })
35243
- ]
35244
- }
35233
+ ] }, index)
35234
+ );
35235
+ }),
35236
+ /* @__PURE__ */ jsx147(
35237
+ Button,
35238
+ {
35239
+ variant: "ghost",
35240
+ size: "sm",
35241
+ fullWidth: true,
35242
+ leftIcon: /* @__PURE__ */ jsx147(AddIcon6, { size: "sm" }),
35243
+ onClick: () => setDraft((d) => {
35244
+ const at = callAt(d, path);
35245
+ if (!at) return d;
35246
+ const next = [...at.args, '""'];
35247
+ return path.length === 0 ? formatCall(at.name, next) : replaceArgument(d, path, `${at.name}(${next.join(", ")})`);
35248
+ }),
35249
+ children: "Add argument"
35250
+ }
35251
+ )
35252
+ ] }),
35253
+ /* @__PURE__ */ jsxs141("div", { className: "ods-expression-field__editor-foot", children: [
35254
+ /* @__PURE__ */ jsx147(Button, { variant: "secondary", size: "sm", onClick: onCancel, children: "Cancel" }),
35255
+ /* @__PURE__ */ jsx147(Button, { variant: "primary", size: "sm", onClick: () => onApply(draft), children: "Apply" })
35256
+ ] })
35257
+ ]
35258
+ }
35259
+ ),
35260
+ document.body
35245
35261
  );
35246
35262
  }
35247
35263