@particle-academy/fancy-flow 0.41.0 → 0.43.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/dist/{ConfigFieldRenderer-4xK9hzvd.d.cts → ConfigFieldRenderer-BHQDZer6.d.ts} +10 -2
- package/dist/{ConfigFieldRenderer-D2TejNY1.d.ts → ConfigFieldRenderer-LotNHeG8.d.cts} +10 -2
- package/dist/{chunk-UX65ML3J.js → chunk-55KQS3LK.js} +25 -2
- package/dist/chunk-55KQS3LK.js.map +1 -0
- package/dist/{chunk-WOO4B7M5.js → chunk-T3VQX3XB.js} +3 -3
- package/dist/{chunk-WOO4B7M5.js.map → chunk-T3VQX3XB.js.map} +1 -1
- package/dist/engine.d.cts +3 -3
- package/dist/engine.d.ts +3 -3
- package/dist/fields/react-fancy.d.cts +3 -3
- package/dist/fields/react-fancy.d.ts +3 -3
- package/dist/index.cjs +351 -22
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +126 -7
- package/dist/index.d.ts +126 -7
- package/dist/index.js +318 -22
- package/dist/index.js.map +1 -1
- package/dist/registry/index.d.cts +3 -3
- package/dist/registry/index.d.ts +3 -3
- package/dist/{registry-BNyT66SS.d.cts → registry-C9KMVpn7.d.cts} +1 -1
- package/dist/{registry-CS7kjMto.d.ts → registry-FGCBprcn.d.ts} +1 -1
- package/dist/registry.cjs +23 -0
- package/dist/registry.cjs.map +1 -1
- package/dist/registry.js +1 -1
- package/dist/screens.js +3 -3
- package/dist/styles.css +96 -0
- package/dist/styles.css.map +1 -1
- package/dist/{types-cAdD1Og2.d.cts → types-B78Rm69S.d.cts} +81 -2
- package/dist/{types-Cf75IbxY.d.ts → types-JViq8reb.d.ts} +81 -2
- package/dist/ux.d.cts +1 -1
- package/dist/ux.d.ts +1 -1
- package/package.json +2 -1
- package/dist/chunk-UX65ML3J.js.map +0 -1
package/dist/index.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { removeNodes, removeEdges, cloneSubgraph, alignNodes, distributeNodes, reconnectEdge, assignToLane, removeFromLane, duplicateNode, setEdgeLabel, FlowCanvas } from './chunk-
|
|
2
|
-
export { ActionNode, DecisionNode, FlowCanvas, FlowViewer, NodeShell, OutputNode, SubgraphNode, TriggerNode, alignNodes, cloneSubgraph, defaultNodeTypes, distributeNodes, reconnectEdge } from './chunk-
|
|
1
|
+
import { removeNodes, removeEdges, cloneSubgraph, alignNodes, distributeNodes, reconnectEdge, assignToLane, removeFromLane, duplicateNode, setEdgeLabel, FlowCanvas } from './chunk-T3VQX3XB.js';
|
|
2
|
+
export { ActionNode, DecisionNode, FlowCanvas, FlowViewer, NodeShell, OutputNode, SubgraphNode, TriggerNode, alignNodes, cloneSubgraph, defaultNodeTypes, distributeNodes, reconnectEdge } from './chunk-T3VQX3XB.js';
|
|
3
3
|
import { useFlowState, useFlowRun, useFlowHistory, applyOutputsToNodes, applyStatusesToNodes } from './chunk-A6RFLGWV.js';
|
|
4
4
|
export { applyOutputsToNodes, applyStatusesToNodes, createHistory, useFlowHistory, useFlowRun, useFlowState } from './chunk-A6RFLGWV.js';
|
|
5
5
|
export { runCohort } from './chunk-QZTGV3ZL.js';
|
|
6
|
-
import { buildNodeTypes, FlowEditorProvider, registerBuiltinKinds } from './chunk-
|
|
7
|
-
export { ANY_PORT_TYPE, BUILTIN_KINDS, LaneNode, NoteNode, RegistryNode, buildNodeTypes, createConnectionValidator, defaultPortCompatibility, registerBuiltinKinds, useFlowEditor, useFlowEditorOptional } from './chunk-
|
|
6
|
+
import { buildNodeTypes, FlowEditorProvider, registerBuiltinKinds } from './chunk-55KQS3LK.js';
|
|
7
|
+
export { ANY_PORT_TYPE, BUILTIN_KINDS, LaneNode, NoteNode, RegistryNode, buildNodeTypes, createConnectionValidator, defaultPortCompatibility, registerBuiltinKinds, useFlowEditor, useFlowEditorOptional } from './chunk-55KQS3LK.js';
|
|
8
8
|
import { ReactFlowProvider, useReactFlow, addEdge, applyEdgeChanges, applyNodeChanges, Position, Handle } from './chunk-OWENS2H5.js';
|
|
9
9
|
export { LEGACY_PAUSE_PREFIXES, PAUSE_PREFIX, decodePause, encodePause, isPause, pauseForHuman } from './chunk-UEOE6B52.js';
|
|
10
10
|
import './chunk-USL4FMFU.js';
|
|
@@ -109,6 +109,230 @@ function paletteDropHandlers(onDrop) {
|
|
|
109
109
|
}
|
|
110
110
|
};
|
|
111
111
|
}
|
|
112
|
+
|
|
113
|
+
// src/expressions/variables.ts
|
|
114
|
+
var ROOT = "$json";
|
|
115
|
+
function expr(path) {
|
|
116
|
+
return `{{ ${path} }}`;
|
|
117
|
+
}
|
|
118
|
+
function outputFieldsFor(node) {
|
|
119
|
+
const kindName = node.data?.kind ?? node.type;
|
|
120
|
+
if (!kindName) return [];
|
|
121
|
+
const kind = getNodeKind(kindName);
|
|
122
|
+
const shape = kind?.outputShape;
|
|
123
|
+
if (!shape) return [];
|
|
124
|
+
if (typeof shape === "function") {
|
|
125
|
+
try {
|
|
126
|
+
const config = node.data?.config ?? {};
|
|
127
|
+
return shape(config) ?? [];
|
|
128
|
+
} catch {
|
|
129
|
+
return [];
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
return shape;
|
|
133
|
+
}
|
|
134
|
+
function baseVariables() {
|
|
135
|
+
return [
|
|
136
|
+
{ expression: expr(ROOT), path: ROOT, type: "unknown", description: "The whole incoming value." }
|
|
137
|
+
];
|
|
138
|
+
}
|
|
139
|
+
function availableVariables(graph, nodeId) {
|
|
140
|
+
const out = baseVariables();
|
|
141
|
+
const seen = /* @__PURE__ */ new Set([ROOT]);
|
|
142
|
+
const byId = new Map(graph.nodes.map((n) => [n.id, n]));
|
|
143
|
+
const upstreamIds = graph.edges.filter((e) => e.target === nodeId).map((e) => e.source);
|
|
144
|
+
for (const id of upstreamIds) {
|
|
145
|
+
if (id === nodeId) continue;
|
|
146
|
+
const upstream = byId.get(id);
|
|
147
|
+
if (!upstream) continue;
|
|
148
|
+
const kindName = upstream.data?.kind ?? upstream.type;
|
|
149
|
+
const label = upstream.data?.label ?? (kindName ? getNodeKind(kindName)?.label : void 0);
|
|
150
|
+
for (const field of outputFieldsFor(upstream)) {
|
|
151
|
+
const path = `${ROOT}.${field.path}`;
|
|
152
|
+
if (seen.has(path)) continue;
|
|
153
|
+
seen.add(path);
|
|
154
|
+
out.push({
|
|
155
|
+
expression: expr(path),
|
|
156
|
+
path,
|
|
157
|
+
type: field.type,
|
|
158
|
+
description: field.description,
|
|
159
|
+
source: label
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
return out;
|
|
164
|
+
}
|
|
165
|
+
function describeExpressionGrammar() {
|
|
166
|
+
return {
|
|
167
|
+
forms: [
|
|
168
|
+
{ syntax: "{{ $json }}", meaning: "The whole value arriving on this node's input." },
|
|
169
|
+
{ syntax: "{{ $json.field }}", meaning: "One key of that value. Dot-paths nest: $json.user.email." },
|
|
170
|
+
{ syntax: "{{ $input.field }}", meaning: "An alias for $json \u2014 the same value, either spelling." },
|
|
171
|
+
{ syntax: "{{ in }}", meaning: "The input by its context key, rather than through the alias." }
|
|
172
|
+
],
|
|
173
|
+
note: "Dot-paths only \u2014 no arithmetic, comparisons or function calls; anything else resolves to nothing. A field that is exactly one expression keeps the resolved value's type; mixed text interpolates as a string. fancy-flow's own runFlow does not interpolate: it hands config to your executor verbatim, and the fancy-flow-php runtime is what resolves these."
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
function findTrigger(text2, caret) {
|
|
177
|
+
const before = text2.slice(0, caret);
|
|
178
|
+
const open = before.lastIndexOf("{{");
|
|
179
|
+
if (open === -1) return null;
|
|
180
|
+
if (before.indexOf("}}", open) !== -1) return null;
|
|
181
|
+
return { open, query: before.slice(open + 2).trim() };
|
|
182
|
+
}
|
|
183
|
+
function filterVariables(vars, query) {
|
|
184
|
+
const q = query.trim().toLowerCase();
|
|
185
|
+
if (q === "") return vars;
|
|
186
|
+
return vars.filter((v) => v.path.toLowerCase().includes(q));
|
|
187
|
+
}
|
|
188
|
+
function applyCompletion(text2, caret, trigger, variable) {
|
|
189
|
+
const head = text2.slice(0, trigger.open);
|
|
190
|
+
const tail = text2.slice(caret);
|
|
191
|
+
return { value: `${head}${variable.expression}${tail}`, caret: head.length + variable.expression.length };
|
|
192
|
+
}
|
|
193
|
+
function ExpressionField({
|
|
194
|
+
value,
|
|
195
|
+
onChange,
|
|
196
|
+
placeholder,
|
|
197
|
+
rows = 2,
|
|
198
|
+
handle,
|
|
199
|
+
graph,
|
|
200
|
+
nodeId
|
|
201
|
+
}) {
|
|
202
|
+
const ref = useRef(null);
|
|
203
|
+
const [trigger, setTrigger] = useState(null);
|
|
204
|
+
const [active, setActive] = useState(0);
|
|
205
|
+
const [showHelp, setShowHelp] = useState(false);
|
|
206
|
+
const variables = useMemo(
|
|
207
|
+
() => graph && nodeId ? availableVariables(graph, nodeId) : baseVariables(),
|
|
208
|
+
[graph, nodeId]
|
|
209
|
+
);
|
|
210
|
+
const matches = useMemo(
|
|
211
|
+
() => trigger ? filterVariables(variables, trigger.query) : [],
|
|
212
|
+
[trigger, variables]
|
|
213
|
+
);
|
|
214
|
+
const help = useMemo(() => describeExpressionGrammar(), []);
|
|
215
|
+
const open = trigger !== null && matches.length > 0;
|
|
216
|
+
const sync = (el) => {
|
|
217
|
+
const next = findTrigger(el.value, el.selectionStart ?? el.value.length);
|
|
218
|
+
setTrigger(next);
|
|
219
|
+
setActive(0);
|
|
220
|
+
};
|
|
221
|
+
const choose = (variable) => {
|
|
222
|
+
const el = ref.current;
|
|
223
|
+
if (!el || !trigger) return;
|
|
224
|
+
const { value: next, caret } = applyCompletion(
|
|
225
|
+
el.value,
|
|
226
|
+
el.selectionStart ?? el.value.length,
|
|
227
|
+
trigger,
|
|
228
|
+
variable
|
|
229
|
+
);
|
|
230
|
+
onChange(next);
|
|
231
|
+
setTrigger(null);
|
|
232
|
+
requestAnimationFrame(() => {
|
|
233
|
+
el.focus();
|
|
234
|
+
el.setSelectionRange(caret, caret);
|
|
235
|
+
});
|
|
236
|
+
};
|
|
237
|
+
const onKeyDown = (e) => {
|
|
238
|
+
if (!open) return;
|
|
239
|
+
if (e.key === "ArrowDown") {
|
|
240
|
+
e.preventDefault();
|
|
241
|
+
setActive((i) => (i + 1) % matches.length);
|
|
242
|
+
} else if (e.key === "ArrowUp") {
|
|
243
|
+
e.preventDefault();
|
|
244
|
+
setActive((i) => (i - 1 + matches.length) % matches.length);
|
|
245
|
+
} else if (e.key === "Enter" || e.key === "Tab") {
|
|
246
|
+
e.preventDefault();
|
|
247
|
+
choose(matches[active] ?? matches[0]);
|
|
248
|
+
} else if (e.key === "Escape") {
|
|
249
|
+
e.preventDefault();
|
|
250
|
+
setTrigger(null);
|
|
251
|
+
}
|
|
252
|
+
};
|
|
253
|
+
return /* @__PURE__ */ jsxs("div", { className: "ff-expression", "data-ff-expression": handle["data-ff-field"], children: [
|
|
254
|
+
/* @__PURE__ */ jsx(
|
|
255
|
+
"textarea",
|
|
256
|
+
{
|
|
257
|
+
...handle,
|
|
258
|
+
ref,
|
|
259
|
+
className: "ff-panel__input ff-panel__input--expression",
|
|
260
|
+
rows,
|
|
261
|
+
value: value ?? "",
|
|
262
|
+
placeholder: placeholder ?? "{{ $json.field }}",
|
|
263
|
+
spellCheck: false,
|
|
264
|
+
role: "combobox",
|
|
265
|
+
"aria-expanded": open,
|
|
266
|
+
"aria-autocomplete": "list",
|
|
267
|
+
"aria-controls": open ? `${handle.id ?? handle["data-ff-field"]}-vars` : void 0,
|
|
268
|
+
onChange: (e) => {
|
|
269
|
+
onChange(e.target.value);
|
|
270
|
+
sync(e.target);
|
|
271
|
+
},
|
|
272
|
+
onKeyDown,
|
|
273
|
+
onClick: (e) => sync(e.currentTarget),
|
|
274
|
+
onBlur: () => {
|
|
275
|
+
window.setTimeout(() => setTrigger(null), 120);
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
),
|
|
279
|
+
/* @__PURE__ */ jsxs("div", { className: "ff-expression__bar", children: [
|
|
280
|
+
/* @__PURE__ */ jsxs(
|
|
281
|
+
"button",
|
|
282
|
+
{
|
|
283
|
+
type: "button",
|
|
284
|
+
className: "ff-expression__helpbtn",
|
|
285
|
+
"aria-expanded": showHelp,
|
|
286
|
+
onClick: () => setShowHelp((s) => !s),
|
|
287
|
+
children: [
|
|
288
|
+
"{{ }}",
|
|
289
|
+
" reference"
|
|
290
|
+
]
|
|
291
|
+
}
|
|
292
|
+
),
|
|
293
|
+
variables.length > 1 && /* @__PURE__ */ jsxs("span", { className: "ff-expression__hint", children: [
|
|
294
|
+
"type ",
|
|
295
|
+
/* @__PURE__ */ jsx("code", { children: "{{" }),
|
|
296
|
+
" for ",
|
|
297
|
+
variables.length,
|
|
298
|
+
" variables"
|
|
299
|
+
] })
|
|
300
|
+
] }),
|
|
301
|
+
open && /* @__PURE__ */ jsx(
|
|
302
|
+
"ul",
|
|
303
|
+
{
|
|
304
|
+
className: "ff-expression__menu",
|
|
305
|
+
id: `${handle.id ?? handle["data-ff-field"]}-vars`,
|
|
306
|
+
role: "listbox",
|
|
307
|
+
"data-ff-expression-menu": handle["data-ff-field"],
|
|
308
|
+
children: matches.map((v, i) => /* @__PURE__ */ jsx("li", { role: "option", "aria-selected": i === active, children: /* @__PURE__ */ jsxs(
|
|
309
|
+
"button",
|
|
310
|
+
{
|
|
311
|
+
type: "button",
|
|
312
|
+
className: `ff-expression__option${i === active ? " is-active" : ""}`,
|
|
313
|
+
"data-ff-expression-option": v.path,
|
|
314
|
+
onMouseDown: (e) => {
|
|
315
|
+
e.preventDefault();
|
|
316
|
+
choose(v);
|
|
317
|
+
},
|
|
318
|
+
children: [
|
|
319
|
+
/* @__PURE__ */ jsx("code", { className: "ff-expression__path", children: v.path }),
|
|
320
|
+
v.source && /* @__PURE__ */ jsx("span", { className: "ff-expression__source", children: v.source }),
|
|
321
|
+
v.description && /* @__PURE__ */ jsx("span", { className: "ff-expression__desc", children: v.description })
|
|
322
|
+
]
|
|
323
|
+
}
|
|
324
|
+
) }, v.expression))
|
|
325
|
+
}
|
|
326
|
+
),
|
|
327
|
+
showHelp && /* @__PURE__ */ jsxs("div", { className: "ff-expression__help", role: "note", "data-ff-expression-help": true, children: [
|
|
328
|
+
/* @__PURE__ */ jsx("dl", { children: help.forms.map((f) => /* @__PURE__ */ jsxs("div", { children: [
|
|
329
|
+
/* @__PURE__ */ jsx("dt", { children: /* @__PURE__ */ jsx("code", { children: f.syntax }) }),
|
|
330
|
+
/* @__PURE__ */ jsx("dd", { children: f.meaning })
|
|
331
|
+
] }, f.syntax)) }),
|
|
332
|
+
/* @__PURE__ */ jsx("p", { className: "ff-expression__note", children: help.note })
|
|
333
|
+
] })
|
|
334
|
+
] });
|
|
335
|
+
}
|
|
112
336
|
function ConfigFieldRenderer({
|
|
113
337
|
field,
|
|
114
338
|
value,
|
|
@@ -116,7 +340,9 @@ function ConfigFieldRenderer({
|
|
|
116
340
|
id,
|
|
117
341
|
renderCredentialField,
|
|
118
342
|
renderDocumentField,
|
|
119
|
-
fieldRenderers
|
|
343
|
+
fieldRenderers,
|
|
344
|
+
graph,
|
|
345
|
+
nodeId
|
|
120
346
|
}) {
|
|
121
347
|
const handle = { id, "data-ff-field": field.key };
|
|
122
348
|
const custom = fieldRenderers?.[field.type];
|
|
@@ -198,15 +424,14 @@ function ConfigFieldRenderer({
|
|
|
198
424
|
return /* @__PURE__ */ jsx(JsonField, { value, onChange, rows: field.rows, handle });
|
|
199
425
|
case "expression":
|
|
200
426
|
return /* @__PURE__ */ jsx(
|
|
201
|
-
|
|
427
|
+
ExpressionField,
|
|
202
428
|
{
|
|
203
|
-
|
|
204
|
-
className: "ff-panel__input ff-panel__input--expression",
|
|
205
|
-
rows: 2,
|
|
429
|
+
handle,
|
|
206
430
|
value: value ?? "",
|
|
431
|
+
onChange,
|
|
207
432
|
placeholder: field.example ?? "{{ $json.field }}",
|
|
208
|
-
|
|
209
|
-
|
|
433
|
+
graph,
|
|
434
|
+
nodeId
|
|
210
435
|
}
|
|
211
436
|
);
|
|
212
437
|
case "credential":
|
|
@@ -233,7 +458,9 @@ function ConfigFieldRenderer({
|
|
|
233
458
|
onChange,
|
|
234
459
|
renderCredentialField,
|
|
235
460
|
renderDocumentField,
|
|
236
|
-
fieldRenderers
|
|
461
|
+
fieldRenderers,
|
|
462
|
+
graph,
|
|
463
|
+
nodeId
|
|
237
464
|
}
|
|
238
465
|
);
|
|
239
466
|
case "keyvalue":
|
|
@@ -286,6 +513,8 @@ function RepeaterField({
|
|
|
286
513
|
field,
|
|
287
514
|
value,
|
|
288
515
|
onChange,
|
|
516
|
+
graph,
|
|
517
|
+
nodeId,
|
|
289
518
|
renderCredentialField,
|
|
290
519
|
renderDocumentField,
|
|
291
520
|
fieldRenderers
|
|
@@ -366,6 +595,8 @@ function RepeaterField({
|
|
|
366
595
|
/* @__PURE__ */ jsx(
|
|
367
596
|
ConfigFieldRenderer,
|
|
368
597
|
{
|
|
598
|
+
graph,
|
|
599
|
+
nodeId,
|
|
369
600
|
field: sub,
|
|
370
601
|
value: row[sub.key],
|
|
371
602
|
onChange: (cell) => setCell(i, sub.key, cell),
|
|
@@ -480,7 +711,7 @@ function JsonField({
|
|
|
480
711
|
return "";
|
|
481
712
|
}
|
|
482
713
|
}, [value]);
|
|
483
|
-
const [
|
|
714
|
+
const [text2, setText] = useState(serialized);
|
|
484
715
|
const [error, setError] = useState(null);
|
|
485
716
|
const [touched, setTouched] = useState(false);
|
|
486
717
|
const lastProps = useRef(serialized);
|
|
@@ -518,7 +749,7 @@ function JsonField({
|
|
|
518
749
|
...handle,
|
|
519
750
|
className: "ff-panel__input ff-panel__input--json",
|
|
520
751
|
rows: rows ?? 6,
|
|
521
|
-
value:
|
|
752
|
+
value: text2,
|
|
522
753
|
spellCheck: false,
|
|
523
754
|
"aria-invalid": showError || void 0,
|
|
524
755
|
"aria-describedby": showError ? errorId : void 0,
|
|
@@ -547,6 +778,7 @@ function NodeConfigPanel({
|
|
|
547
778
|
renderCredentialField,
|
|
548
779
|
renderDocumentField,
|
|
549
780
|
fieldRenderers,
|
|
781
|
+
graph,
|
|
550
782
|
className,
|
|
551
783
|
style
|
|
552
784
|
}) {
|
|
@@ -652,7 +884,9 @@ function NodeConfigPanel({
|
|
|
652
884
|
onChange: (v) => setConfigValue(field.key, v),
|
|
653
885
|
renderCredentialField,
|
|
654
886
|
renderDocumentField: documentField,
|
|
655
|
-
fieldRenderers
|
|
887
|
+
fieldRenderers,
|
|
888
|
+
graph,
|
|
889
|
+
nodeId: node.id
|
|
656
890
|
}
|
|
657
891
|
)
|
|
658
892
|
] }, field.key))
|
|
@@ -1395,8 +1629,8 @@ function FlowEditorInner({
|
|
|
1395
1629
|
x: labelEdit.x,
|
|
1396
1630
|
y: labelEdit.y,
|
|
1397
1631
|
initial: flow.edges.find((e) => e.id === labelEdit.edgeId)?.label ?? "",
|
|
1398
|
-
onCommit: (
|
|
1399
|
-
api.setEdgeLabel(labelEdit.edgeId,
|
|
1632
|
+
onCommit: (text2) => {
|
|
1633
|
+
api.setEdgeLabel(labelEdit.edgeId, text2);
|
|
1400
1634
|
setLabelEdit(null);
|
|
1401
1635
|
},
|
|
1402
1636
|
onCancel: () => setLabelEdit(null)
|
|
@@ -1416,6 +1650,7 @@ function FlowEditorInner({
|
|
|
1416
1650
|
node: api.selected,
|
|
1417
1651
|
onChange: api.updateNode,
|
|
1418
1652
|
fieldRenderers,
|
|
1653
|
+
graph: flow,
|
|
1419
1654
|
onDelete: builtins.delete === false ? void 0 : (n) => api.deleteNodes([n.id])
|
|
1420
1655
|
}
|
|
1421
1656
|
),
|
|
@@ -1500,7 +1735,7 @@ function EdgeLabelEditor({
|
|
|
1500
1735
|
onCommit,
|
|
1501
1736
|
onCancel
|
|
1502
1737
|
}) {
|
|
1503
|
-
const [
|
|
1738
|
+
const [text2, setText] = useState(initial);
|
|
1504
1739
|
const ref = useRef(null);
|
|
1505
1740
|
useEffect(() => {
|
|
1506
1741
|
ref.current?.focus();
|
|
@@ -1517,17 +1752,17 @@ function EdgeLabelEditor({
|
|
|
1517
1752
|
{
|
|
1518
1753
|
ref,
|
|
1519
1754
|
className: "ff-panel__input",
|
|
1520
|
-
value:
|
|
1755
|
+
value: text2,
|
|
1521
1756
|
placeholder: "Label this connection",
|
|
1522
1757
|
"aria-label": "Connection label",
|
|
1523
1758
|
"data-action": "edge-label-input",
|
|
1524
1759
|
onChange: (e) => setText(e.target.value),
|
|
1525
1760
|
onKeyDown: (e) => {
|
|
1526
1761
|
e.stopPropagation();
|
|
1527
|
-
if (e.key === "Enter") onCommit(
|
|
1762
|
+
if (e.key === "Enter") onCommit(text2);
|
|
1528
1763
|
if (e.key === "Escape") onCancel();
|
|
1529
1764
|
},
|
|
1530
|
-
onBlur: () => onCommit(
|
|
1765
|
+
onBlur: () => onCommit(text2)
|
|
1531
1766
|
}
|
|
1532
1767
|
)
|
|
1533
1768
|
}
|
|
@@ -1588,9 +1823,70 @@ var flowKeys = {
|
|
|
1588
1823
|
run: (runId) => ["flow", "runs", runId]
|
|
1589
1824
|
};
|
|
1590
1825
|
|
|
1826
|
+
// src/expressions/expr.ts
|
|
1827
|
+
var WHOLE = /^\{\{\s*([\s\S]*?)\s*\}\}$/;
|
|
1828
|
+
var EACH = /\{\{\s*([\s\S]*?)\s*\}\}/g;
|
|
1829
|
+
var FALSY_STRINGS = /* @__PURE__ */ new Set(["", "0", "false", "no", "off", "null"]);
|
|
1830
|
+
function resolvePath(path, context) {
|
|
1831
|
+
const trimmed = path.trim();
|
|
1832
|
+
if (trimmed === "") return null;
|
|
1833
|
+
const segments = trimmed.split(".");
|
|
1834
|
+
let cursor;
|
|
1835
|
+
const head = segments[0];
|
|
1836
|
+
if (head === "$json" || head === "$input") {
|
|
1837
|
+
cursor = context !== null && typeof context === "object" && "in" in context ? context.in : context;
|
|
1838
|
+
segments.shift();
|
|
1839
|
+
} else {
|
|
1840
|
+
cursor = context;
|
|
1841
|
+
}
|
|
1842
|
+
for (const segment of segments) {
|
|
1843
|
+
if (cursor === null || cursor === void 0) return null;
|
|
1844
|
+
if (typeof cursor !== "object") return null;
|
|
1845
|
+
const next = cursor[segment];
|
|
1846
|
+
if (next === void 0) return null;
|
|
1847
|
+
cursor = next;
|
|
1848
|
+
}
|
|
1849
|
+
return cursor === void 0 ? null : cursor;
|
|
1850
|
+
}
|
|
1851
|
+
function evaluateExpression(template, context) {
|
|
1852
|
+
if (typeof template !== "string") return template;
|
|
1853
|
+
const whole = WHOLE.exec(template.trim());
|
|
1854
|
+
if (whole) return resolvePath(whole[1] ?? "", context);
|
|
1855
|
+
return template.replace(EACH, (_m, path) => stringify(resolvePath(path, context)));
|
|
1856
|
+
}
|
|
1857
|
+
function truthy(value) {
|
|
1858
|
+
if (typeof value === "boolean") return value;
|
|
1859
|
+
if (value === null || value === void 0) return false;
|
|
1860
|
+
if (typeof value === "string") return !FALSY_STRINGS.has(value.trim().toLowerCase());
|
|
1861
|
+
if (Array.isArray(value)) return value.length > 0;
|
|
1862
|
+
if (typeof value === "number") return value !== 0;
|
|
1863
|
+
return Boolean(value);
|
|
1864
|
+
}
|
|
1865
|
+
function text(value) {
|
|
1866
|
+
return stringify(value);
|
|
1867
|
+
}
|
|
1868
|
+
function stringify(value) {
|
|
1869
|
+
if (typeof value === "string") return value;
|
|
1870
|
+
if (typeof value === "boolean") return value ? "true" : "false";
|
|
1871
|
+
if (value === null || value === void 0) return "";
|
|
1872
|
+
if (typeof value === "number" || typeof value === "bigint") return String(value);
|
|
1873
|
+
try {
|
|
1874
|
+
return JSON.stringify(value) ?? "";
|
|
1875
|
+
} catch {
|
|
1876
|
+
return "";
|
|
1877
|
+
}
|
|
1878
|
+
}
|
|
1879
|
+
function evaluateConfig(config, context) {
|
|
1880
|
+
const out = {};
|
|
1881
|
+
for (const [key, value] of Object.entries(config)) {
|
|
1882
|
+
out[key] = Array.isArray(value) ? value.map((v) => evaluateExpression(v, context)) : value !== null && typeof value === "object" ? evaluateConfig(value, context) : evaluateExpression(value, context);
|
|
1883
|
+
}
|
|
1884
|
+
return out;
|
|
1885
|
+
}
|
|
1886
|
+
|
|
1591
1887
|
// src/index.ts
|
|
1592
1888
|
registerBuiltinKinds();
|
|
1593
1889
|
|
|
1594
|
-
export { ConfigFieldRenderer, FlowEditor, FlowRunControls, FlowRunFeed, NodeConfigPanel, NodePalette, NodePort, defineNode, flowKeys, flowLive, paletteDropHandlers };
|
|
1890
|
+
export { ConfigFieldRenderer, ExpressionField, FlowEditor, FlowRunControls, FlowRunFeed, NodeConfigPanel, NodePalette, NodePort, availableVariables, baseVariables, defineNode, describeExpressionGrammar, evaluateConfig, evaluateExpression, flowKeys, flowLive, outputFieldsFor, paletteDropHandlers, resolvePath, text, truthy };
|
|
1595
1891
|
//# sourceMappingURL=index.js.map
|
|
1596
1892
|
//# sourceMappingURL=index.js.map
|