@particle-academy/fancy-flow 0.36.0 → 0.37.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/FlowViewer-C4QAVgWv.d.ts +62 -0
- package/dist/FlowViewer-nLqo7s2E.d.cts +62 -0
- package/dist/chunk-5UCWY7G3.js +593 -0
- package/dist/chunk-5UCWY7G3.js.map +1 -0
- package/dist/index.d.cts +2 -58
- package/dist/index.d.ts +2 -58
- package/dist/index.js +12 -593
- package/dist/index.js.map +1 -1
- package/dist/screens.cjs +9834 -0
- package/dist/screens.cjs.map +1 -0
- package/dist/screens.css +563 -0
- package/dist/screens.css.map +1 -0
- package/dist/screens.d.cts +25 -0
- package/dist/screens.d.ts +25 -0
- package/dist/screens.js +21 -0
- package/dist/screens.js.map +1 -0
- package/package.json +18 -3
package/dist/index.js
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
|
+
import { removeNodes, removeEdges, cloneSubgraph, alignNodes, distributeNodes, reconnectEdge, assignToLane, removeFromLane, duplicateNode, setEdgeLabel, FlowCanvas } from './chunk-5UCWY7G3.js';
|
|
2
|
+
export { ActionNode, DecisionNode, FlowCanvas, FlowViewer, NodeShell, OutputNode, SubgraphNode, TriggerNode, alignNodes, cloneSubgraph, defaultNodeTypes, distributeNodes, reconnectEdge } from './chunk-5UCWY7G3.js';
|
|
1
3
|
import { useFlowState, useFlowRun, useFlowHistory, applyOutputsToNodes, applyStatusesToNodes } from './chunk-A6RFLGWV.js';
|
|
2
4
|
export { applyOutputsToNodes, applyStatusesToNodes, createHistory, useFlowHistory, useFlowRun, useFlowState } from './chunk-A6RFLGWV.js';
|
|
3
5
|
export { runCohort } from './chunk-QZTGV3ZL.js';
|
|
4
|
-
import { buildNodeTypes, FlowEditorProvider, registerBuiltinKinds
|
|
6
|
+
import { buildNodeTypes, FlowEditorProvider, registerBuiltinKinds } from './chunk-UX65ML3J.js';
|
|
5
7
|
export { ANY_PORT_TYPE, BUILTIN_KINDS, LaneNode, NoteNode, RegistryNode, buildNodeTypes, createConnectionValidator, defaultPortCompatibility, registerBuiltinKinds, useFlowEditor, useFlowEditorOptional } from './chunk-UX65ML3J.js';
|
|
6
|
-
import { ReactFlowProvider, useReactFlow, addEdge, applyEdgeChanges, applyNodeChanges, Position, Handle
|
|
8
|
+
import { ReactFlowProvider, useReactFlow, addEdge, applyEdgeChanges, applyNodeChanges, Position, Handle } from './chunk-OWENS2H5.js';
|
|
7
9
|
export { LEGACY_PAUSE_PREFIXES, PAUSE_PREFIX, decodePause, encodePause, isPause, pauseForHuman } from './chunk-UEOE6B52.js';
|
|
8
10
|
import './chunk-USL4FMFU.js';
|
|
9
11
|
export { runFlow } from './chunk-VLATLVGH.js';
|
|
@@ -14,463 +16,9 @@ import { onNodeKindsChanged, listNodeKinds, getNodeKind, defaultConfigFor, valid
|
|
|
14
16
|
export { categoryAccent, clearNodeKindOverrides, defaultConfigFor, getNodeKind, listNodeKinds, onNodeKindsChanged, overrideNodeKind, registerNodeKind, validateConfig } from './chunk-PVROYW7C.js';
|
|
15
17
|
import { getRichInputAdapter } from './chunk-F5RPRB7A.js';
|
|
16
18
|
export { RichInputPreview, getRichInputAdapter, isRichInputEnabled, onRichInputAdapterChanged, registerRichInputAdapter } from './chunk-F5RPRB7A.js';
|
|
17
|
-
import {
|
|
19
|
+
import { forwardRef, useState, useMemo, useEffect, useCallback, useRef, useImperativeHandle, useId, memo } from 'react';
|
|
18
20
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
19
21
|
|
|
20
|
-
function NodeShellInner({
|
|
21
|
-
node,
|
|
22
|
-
accent,
|
|
23
|
-
tag,
|
|
24
|
-
icon,
|
|
25
|
-
showInputs = true,
|
|
26
|
-
showOutputs = true,
|
|
27
|
-
children
|
|
28
|
-
}) {
|
|
29
|
-
const data = node.data;
|
|
30
|
-
const status = data.status ?? "idle";
|
|
31
|
-
const inputs = data.inputs ?? defaultInputs(showInputs);
|
|
32
|
-
const outputs = data.outputs ?? defaultOutputs(showOutputs);
|
|
33
|
-
return /* @__PURE__ */ jsxs(
|
|
34
|
-
"div",
|
|
35
|
-
{
|
|
36
|
-
className: ["ff-node", `ff-node--status-${status}`, node.selected ? "ff-node--selected" : ""].filter(Boolean).join(" "),
|
|
37
|
-
style: { borderColor: node.selected ? accent : void 0 },
|
|
38
|
-
children: [
|
|
39
|
-
/* @__PURE__ */ jsxs("header", { className: "ff-node__header", style: { background: accent }, children: [
|
|
40
|
-
/* @__PURE__ */ jsx("span", { className: "ff-node__icon", "aria-hidden": true, children: icon ?? null }),
|
|
41
|
-
/* @__PURE__ */ jsx("span", { className: "ff-node__tag", children: tag }),
|
|
42
|
-
/* @__PURE__ */ jsx("span", { className: "ff-node__label", children: data.label }),
|
|
43
|
-
status !== "idle" && /* @__PURE__ */ jsx(StatusDot, { status })
|
|
44
|
-
] }),
|
|
45
|
-
data.description && /* @__PURE__ */ jsx("p", { className: "ff-node__desc", children: data.description }),
|
|
46
|
-
children && /* @__PURE__ */ jsx("div", { className: "ff-node__body", children }),
|
|
47
|
-
data.statusText && /* @__PURE__ */ jsx("p", { className: "ff-node__status-text", children: data.statusText }),
|
|
48
|
-
inputs.map((p, i) => /* @__PURE__ */ jsx(
|
|
49
|
-
Handle,
|
|
50
|
-
{
|
|
51
|
-
type: "target",
|
|
52
|
-
position: Position.Left,
|
|
53
|
-
id: p.id,
|
|
54
|
-
style: portStyle(i, inputs.length),
|
|
55
|
-
title: p.label ?? p.id
|
|
56
|
-
},
|
|
57
|
-
p.id
|
|
58
|
-
)),
|
|
59
|
-
outputs.map((p, i) => /* @__PURE__ */ jsx(
|
|
60
|
-
Handle,
|
|
61
|
-
{
|
|
62
|
-
type: "source",
|
|
63
|
-
position: Position.Right,
|
|
64
|
-
id: p.id,
|
|
65
|
-
style: portStyle(i, outputs.length),
|
|
66
|
-
title: p.label ?? p.id
|
|
67
|
-
},
|
|
68
|
-
p.id
|
|
69
|
-
))
|
|
70
|
-
]
|
|
71
|
-
}
|
|
72
|
-
);
|
|
73
|
-
}
|
|
74
|
-
var NodeShell = memo(NodeShellInner);
|
|
75
|
-
function defaultInputs(show) {
|
|
76
|
-
return show ? [{ id: "in" }] : [];
|
|
77
|
-
}
|
|
78
|
-
function defaultOutputs(show) {
|
|
79
|
-
return show ? [{ id: "out" }] : [];
|
|
80
|
-
}
|
|
81
|
-
function portStyle(i, total) {
|
|
82
|
-
if (total <= 1) return {};
|
|
83
|
-
const slot = 100 / (total + 1) * (i + 1);
|
|
84
|
-
return { top: `${slot}%` };
|
|
85
|
-
}
|
|
86
|
-
function StatusDot({ status }) {
|
|
87
|
-
return /* @__PURE__ */ jsx("span", { className: `ff-node__dot ff-node__dot--${status}`, "aria-label": `status ${status}` });
|
|
88
|
-
}
|
|
89
|
-
function TriggerNodeInner(props) {
|
|
90
|
-
return /* @__PURE__ */ jsx(NodeShell, { node: props, accent: "#10b981", tag: "TRIGGER", icon: "\u26A1", showInputs: false });
|
|
91
|
-
}
|
|
92
|
-
var TriggerNode = memo(TriggerNodeInner);
|
|
93
|
-
function ActionNodeInner(props) {
|
|
94
|
-
return /* @__PURE__ */ jsx(NodeShell, { node: props, accent: "#3b82f6", tag: "ACTION", icon: "\u25B8" });
|
|
95
|
-
}
|
|
96
|
-
var ActionNode = memo(ActionNodeInner);
|
|
97
|
-
var DEFAULT_BRANCHES = [
|
|
98
|
-
{ id: "true", label: "true" },
|
|
99
|
-
{ id: "false", label: "false" }
|
|
100
|
-
];
|
|
101
|
-
function DecisionNodeInner(props) {
|
|
102
|
-
if (!props.data.outputs) {
|
|
103
|
-
props = { ...props, data: { ...props.data, outputs: DEFAULT_BRANCHES } };
|
|
104
|
-
}
|
|
105
|
-
return /* @__PURE__ */ jsx(NodeShell, { node: props, accent: "#f59e0b", tag: "DECISION", icon: "\u25C7" });
|
|
106
|
-
}
|
|
107
|
-
var DecisionNode = memo(DecisionNodeInner);
|
|
108
|
-
function OutputNodeInner(props) {
|
|
109
|
-
return /* @__PURE__ */ jsx(NodeShell, { node: props, accent: "#a855f7", tag: "OUTPUT", icon: "\u25CF", showOutputs: false });
|
|
110
|
-
}
|
|
111
|
-
var OutputNode = memo(OutputNodeInner);
|
|
112
|
-
function SubgraphNodeInner(props) {
|
|
113
|
-
const data = props.data;
|
|
114
|
-
const childCount = data.childIds?.length ?? 0;
|
|
115
|
-
return /* @__PURE__ */ jsx(NodeShell, { node: props, accent: "#0ea5e9", tag: "SUBGRAPH", icon: "\u2750", children: /* @__PURE__ */ jsxs("div", { className: "ff-subgraph__meta", children: [
|
|
116
|
-
/* @__PURE__ */ jsxs("span", { children: [
|
|
117
|
-
childCount,
|
|
118
|
-
" node",
|
|
119
|
-
childCount === 1 ? "" : "s"
|
|
120
|
-
] }),
|
|
121
|
-
/* @__PURE__ */ jsx("span", { children: data.collapsed === false ? "expanded" : "collapsed" })
|
|
122
|
-
] }) });
|
|
123
|
-
}
|
|
124
|
-
var SubgraphNode = memo(SubgraphNodeInner);
|
|
125
|
-
|
|
126
|
-
// src/components/nodes/index.ts
|
|
127
|
-
var defaultNodeTypes = {
|
|
128
|
-
trigger: TriggerNode,
|
|
129
|
-
action: ActionNode,
|
|
130
|
-
decision: DecisionNode,
|
|
131
|
-
output: OutputNode,
|
|
132
|
-
note: NoteNode,
|
|
133
|
-
subgraph: SubgraphNode
|
|
134
|
-
};
|
|
135
|
-
|
|
136
|
-
// src/components/FlowEditor/graph-ops.ts
|
|
137
|
-
function removeNodes(graph, ids) {
|
|
138
|
-
if (ids.length === 0) return graph;
|
|
139
|
-
const doomed = new Set(ids);
|
|
140
|
-
return {
|
|
141
|
-
nodes: graph.nodes.filter((n) => !doomed.has(n.id)),
|
|
142
|
-
edges: graph.edges.filter((e) => !doomed.has(e.source) && !doomed.has(e.target))
|
|
143
|
-
};
|
|
144
|
-
}
|
|
145
|
-
function removeEdges(edges, ids) {
|
|
146
|
-
if (ids.length === 0) return edges;
|
|
147
|
-
const doomed = new Set(ids);
|
|
148
|
-
return edges.filter((e) => !doomed.has(e.id));
|
|
149
|
-
}
|
|
150
|
-
function setEdgeLabel(edges, id, label) {
|
|
151
|
-
const next = label?.trim();
|
|
152
|
-
return edges.map((e) => {
|
|
153
|
-
if (e.id !== id) return e;
|
|
154
|
-
if (!next) {
|
|
155
|
-
const { label: _drop, ...rest } = e;
|
|
156
|
-
return rest;
|
|
157
|
-
}
|
|
158
|
-
return { ...e, label: next };
|
|
159
|
-
});
|
|
160
|
-
}
|
|
161
|
-
function duplicateNode(node, id, offset = 40) {
|
|
162
|
-
return {
|
|
163
|
-
...node,
|
|
164
|
-
id,
|
|
165
|
-
position: { x: node.position.x + offset, y: node.position.y + offset },
|
|
166
|
-
// Deep copy so the clone's config edits don't mutate the original.
|
|
167
|
-
data: JSON.parse(JSON.stringify(node.data ?? {}))
|
|
168
|
-
};
|
|
169
|
-
}
|
|
170
|
-
function cloneSubgraph(nodes, edges, opts) {
|
|
171
|
-
const offset = opts.offset ?? 40;
|
|
172
|
-
const idMap = /* @__PURE__ */ new Map();
|
|
173
|
-
for (const n of nodes) idMap.set(n.id, opts.makeId());
|
|
174
|
-
const clonedNodes = nodes.map((n) => {
|
|
175
|
-
const cloned = duplicateNode(n, idMap.get(n.id), offset);
|
|
176
|
-
const parentId = n.parentId;
|
|
177
|
-
if (parentId && idMap.has(parentId)) cloned.parentId = idMap.get(parentId);
|
|
178
|
-
else if (parentId) delete cloned.parentId;
|
|
179
|
-
return cloned;
|
|
180
|
-
});
|
|
181
|
-
const clonedEdges = edges.filter((e) => idMap.has(e.source) && idMap.has(e.target)).map((e) => ({ ...e, id: opts.makeId(), source: idMap.get(e.source), target: idMap.get(e.target) }));
|
|
182
|
-
return { nodes: clonedNodes, edges: clonedEdges, idMap };
|
|
183
|
-
}
|
|
184
|
-
function reconnectEdge2(edges, oldEdge, newConnection) {
|
|
185
|
-
return reconnectEdge(oldEdge, newConnection, edges, { shouldReplaceId: false });
|
|
186
|
-
}
|
|
187
|
-
var nodeW = (n) => n.width ?? n.measured?.width ?? 0;
|
|
188
|
-
var nodeH = (n) => n.height ?? n.measured?.height ?? 0;
|
|
189
|
-
function alignNodes(nodes, edge) {
|
|
190
|
-
if (nodes.length < 2) return nodes;
|
|
191
|
-
const minL = Math.min(...nodes.map((n) => n.position.x));
|
|
192
|
-
const maxR = Math.max(...nodes.map((n) => n.position.x + nodeW(n)));
|
|
193
|
-
const minT = Math.min(...nodes.map((n) => n.position.y));
|
|
194
|
-
const maxB = Math.max(...nodes.map((n) => n.position.y + nodeH(n)));
|
|
195
|
-
const cx2 = (minL + maxR) / 2;
|
|
196
|
-
const cy = (minT + maxB) / 2;
|
|
197
|
-
return nodes.map((n) => {
|
|
198
|
-
let { x, y } = n.position;
|
|
199
|
-
if (edge === "left") x = minL;
|
|
200
|
-
else if (edge === "right") x = maxR - nodeW(n);
|
|
201
|
-
else if (edge === "hcenter") x = cx2 - nodeW(n) / 2;
|
|
202
|
-
else if (edge === "top") y = minT;
|
|
203
|
-
else if (edge === "bottom") y = maxB - nodeH(n);
|
|
204
|
-
else if (edge === "vcenter") y = cy - nodeH(n) / 2;
|
|
205
|
-
return { ...n, position: { x, y } };
|
|
206
|
-
});
|
|
207
|
-
}
|
|
208
|
-
function sortNodesParentFirst(nodes) {
|
|
209
|
-
const byId = new Map(nodes.map((n) => [n.id, n]));
|
|
210
|
-
const seen = /* @__PURE__ */ new Set();
|
|
211
|
-
const out = [];
|
|
212
|
-
const visit = (n) => {
|
|
213
|
-
if (seen.has(n.id)) return;
|
|
214
|
-
const pid = n.parentId;
|
|
215
|
-
if (pid && byId.has(pid) && !seen.has(pid)) visit(byId.get(pid));
|
|
216
|
-
seen.add(n.id);
|
|
217
|
-
out.push(n);
|
|
218
|
-
};
|
|
219
|
-
for (const n of nodes) visit(n);
|
|
220
|
-
return out;
|
|
221
|
-
}
|
|
222
|
-
function absolutePosition(node, nodes) {
|
|
223
|
-
const pid = node.parentId;
|
|
224
|
-
if (!pid) return node.position;
|
|
225
|
-
const parent = nodes.find((n) => n.id === pid);
|
|
226
|
-
return parent ? { x: node.position.x + parent.position.x, y: node.position.y + parent.position.y } : node.position;
|
|
227
|
-
}
|
|
228
|
-
function assignToLane(nodes, nodeId, laneId) {
|
|
229
|
-
if (nodeId === laneId) return nodes;
|
|
230
|
-
const node = nodes.find((n) => n.id === nodeId);
|
|
231
|
-
const lane = nodes.find((n) => n.id === laneId);
|
|
232
|
-
if (!node || !lane) return nodes;
|
|
233
|
-
const abs = absolutePosition(node, nodes);
|
|
234
|
-
const laneAbs = absolutePosition(lane, nodes);
|
|
235
|
-
const rel = { x: abs.x - laneAbs.x, y: abs.y - laneAbs.y };
|
|
236
|
-
return nodes.map((n) => n.id === nodeId ? { ...n, parentId: laneId, extent: "parent", position: rel } : n);
|
|
237
|
-
}
|
|
238
|
-
function removeFromLane(nodes, nodeId) {
|
|
239
|
-
const node = nodes.find((n) => n.id === nodeId);
|
|
240
|
-
if (!node || !node.parentId) return nodes;
|
|
241
|
-
const abs = absolutePosition(node, nodes);
|
|
242
|
-
return nodes.map((n) => {
|
|
243
|
-
if (n.id !== nodeId) return n;
|
|
244
|
-
const { parentId: _p, extent: _e, ...rest } = n;
|
|
245
|
-
return { ...rest, position: abs };
|
|
246
|
-
});
|
|
247
|
-
}
|
|
248
|
-
function distributeNodes(nodes, axis) {
|
|
249
|
-
if (nodes.length < 3) return nodes;
|
|
250
|
-
const size = (n) => axis === "h" ? nodeW(n) : nodeH(n);
|
|
251
|
-
const coord = (n) => axis === "h" ? n.position.x : n.position.y;
|
|
252
|
-
const sorted = [...nodes].sort((a, b) => coord(a) - coord(b));
|
|
253
|
-
const start = coord(sorted[0]);
|
|
254
|
-
const last = sorted[sorted.length - 1];
|
|
255
|
-
const end = coord(last) + size(last);
|
|
256
|
-
const totalSize = sorted.reduce((s, n) => s + size(n), 0);
|
|
257
|
-
const gap = (end - start - totalSize) / (sorted.length - 1);
|
|
258
|
-
const posById = /* @__PURE__ */ new Map();
|
|
259
|
-
let cursor = start;
|
|
260
|
-
for (const n of sorted) {
|
|
261
|
-
posById.set(n.id, cursor);
|
|
262
|
-
cursor += size(n) + gap;
|
|
263
|
-
}
|
|
264
|
-
return nodes.map((n) => {
|
|
265
|
-
const p = posById.get(n.id);
|
|
266
|
-
return { ...n, position: axis === "h" ? { ...n.position, x: p } : { ...n.position, y: p } };
|
|
267
|
-
});
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
// src/components/canvas/helper-lines.ts
|
|
271
|
-
var w = (n) => n.width ?? n.measured?.width ?? 0;
|
|
272
|
-
var h = (n) => n.height ?? n.measured?.height ?? 0;
|
|
273
|
-
function getHelperLines(change, nodes, distance = 6) {
|
|
274
|
-
const result = { snapPosition: { x: void 0, y: void 0 } };
|
|
275
|
-
const a = nodes.find((n) => n.id === change.id);
|
|
276
|
-
if (!a || !change.position) return result;
|
|
277
|
-
const A = {
|
|
278
|
-
left: change.position.x,
|
|
279
|
-
right: change.position.x + w(a),
|
|
280
|
-
top: change.position.y,
|
|
281
|
-
bottom: change.position.y + h(a),
|
|
282
|
-
width: w(a),
|
|
283
|
-
height: h(a)
|
|
284
|
-
};
|
|
285
|
-
let vDist = distance;
|
|
286
|
-
let hDist = distance;
|
|
287
|
-
for (const b of nodes) {
|
|
288
|
-
if (b.id === a.id) continue;
|
|
289
|
-
const B = { left: b.position.x, right: b.position.x + w(b), top: b.position.y, bottom: b.position.y + h(b) };
|
|
290
|
-
const ll = Math.abs(A.left - B.left);
|
|
291
|
-
if (ll < vDist) {
|
|
292
|
-
result.snapPosition.x = B.left;
|
|
293
|
-
result.vertical = B.left;
|
|
294
|
-
vDist = ll;
|
|
295
|
-
}
|
|
296
|
-
const rr = Math.abs(A.right - B.right);
|
|
297
|
-
if (rr < vDist) {
|
|
298
|
-
result.snapPosition.x = B.right - A.width;
|
|
299
|
-
result.vertical = B.right;
|
|
300
|
-
vDist = rr;
|
|
301
|
-
}
|
|
302
|
-
const lr = Math.abs(A.left - B.right);
|
|
303
|
-
if (lr < vDist) {
|
|
304
|
-
result.snapPosition.x = B.right;
|
|
305
|
-
result.vertical = B.right;
|
|
306
|
-
vDist = lr;
|
|
307
|
-
}
|
|
308
|
-
const rl = Math.abs(A.right - B.left);
|
|
309
|
-
if (rl < vDist) {
|
|
310
|
-
result.snapPosition.x = B.left - A.width;
|
|
311
|
-
result.vertical = B.left;
|
|
312
|
-
vDist = rl;
|
|
313
|
-
}
|
|
314
|
-
const tt = Math.abs(A.top - B.top);
|
|
315
|
-
if (tt < hDist) {
|
|
316
|
-
result.snapPosition.y = B.top;
|
|
317
|
-
result.horizontal = B.top;
|
|
318
|
-
hDist = tt;
|
|
319
|
-
}
|
|
320
|
-
const bb = Math.abs(A.bottom - B.bottom);
|
|
321
|
-
if (bb < hDist) {
|
|
322
|
-
result.snapPosition.y = B.bottom - A.height;
|
|
323
|
-
result.horizontal = B.bottom;
|
|
324
|
-
hDist = bb;
|
|
325
|
-
}
|
|
326
|
-
const tb = Math.abs(A.top - B.bottom);
|
|
327
|
-
if (tb < hDist) {
|
|
328
|
-
result.snapPosition.y = B.bottom;
|
|
329
|
-
result.horizontal = B.bottom;
|
|
330
|
-
hDist = tb;
|
|
331
|
-
}
|
|
332
|
-
const bt = Math.abs(A.bottom - B.top);
|
|
333
|
-
if (bt < hDist) {
|
|
334
|
-
result.snapPosition.y = B.top - A.height;
|
|
335
|
-
result.horizontal = B.top;
|
|
336
|
-
hDist = bt;
|
|
337
|
-
}
|
|
338
|
-
}
|
|
339
|
-
return result;
|
|
340
|
-
}
|
|
341
|
-
function HelperLines({ horizontal, vertical }) {
|
|
342
|
-
if (horizontal === void 0 && vertical === void 0) return null;
|
|
343
|
-
return /* @__PURE__ */ jsxs(ViewportPortal, { children: [
|
|
344
|
-
vertical !== void 0 && /* @__PURE__ */ jsx(
|
|
345
|
-
"div",
|
|
346
|
-
{
|
|
347
|
-
className: "ff-helper-line",
|
|
348
|
-
style: { position: "absolute", transform: `translateX(${vertical}px)`, top: -5e3, height: 1e4, width: 1, pointerEvents: "none" }
|
|
349
|
-
}
|
|
350
|
-
),
|
|
351
|
-
horizontal !== void 0 && /* @__PURE__ */ jsx(
|
|
352
|
-
"div",
|
|
353
|
-
{
|
|
354
|
-
className: "ff-helper-line",
|
|
355
|
-
style: { position: "absolute", transform: `translateY(${horizontal}px)`, left: -5e3, width: 1e4, height: 1, pointerEvents: "none" }
|
|
356
|
-
}
|
|
357
|
-
)
|
|
358
|
-
] });
|
|
359
|
-
}
|
|
360
|
-
function preventScrollWhileZooming(event) {
|
|
361
|
-
if (event.shiftKey) event.preventDefault();
|
|
362
|
-
}
|
|
363
|
-
function wheelZoomProps(zoomOnWheel) {
|
|
364
|
-
return zoomOnWheel ? { zoomActivationKeyCode: null, preventScrolling: true } : {
|
|
365
|
-
zoomActivationKeyCode: "Shift",
|
|
366
|
-
preventScrolling: false,
|
|
367
|
-
onWheelCapture: preventScrollWhileZooming
|
|
368
|
-
};
|
|
369
|
-
}
|
|
370
|
-
var DEFAULT_FIT_VIEW = { padding: 0.2 };
|
|
371
|
-
var DEFAULT_EDGE_OPTIONS = {
|
|
372
|
-
type: "smoothstep",
|
|
373
|
-
animated: false
|
|
374
|
-
};
|
|
375
|
-
function FlowCanvas({
|
|
376
|
-
nodes,
|
|
377
|
-
edges,
|
|
378
|
-
background = BackgroundVariant.Dots,
|
|
379
|
-
showControls = true,
|
|
380
|
-
showMinimap = false,
|
|
381
|
-
height = 600,
|
|
382
|
-
validateConnections = true,
|
|
383
|
-
isValidConnection,
|
|
384
|
-
colorMode,
|
|
385
|
-
showHelperLines = false,
|
|
386
|
-
zoomOnWheel = true,
|
|
387
|
-
onNodesChange,
|
|
388
|
-
toolbar,
|
|
389
|
-
nodeTypes,
|
|
390
|
-
edgeTypes,
|
|
391
|
-
className,
|
|
392
|
-
style,
|
|
393
|
-
...rest
|
|
394
|
-
}) {
|
|
395
|
-
const mergedNodeTypes = useMemo(
|
|
396
|
-
() => ({ ...defaultNodeTypes, ...nodeTypes ?? {} }),
|
|
397
|
-
[nodeTypes]
|
|
398
|
-
);
|
|
399
|
-
const nodesRef = useRef(nodes);
|
|
400
|
-
nodesRef.current = nodes;
|
|
401
|
-
const builtinValidator = useMemo(
|
|
402
|
-
() => validateConnections === false ? void 0 : createConnectionValidator(
|
|
403
|
-
() => nodesRef.current,
|
|
404
|
-
validateConnections === true ? void 0 : validateConnections
|
|
405
|
-
),
|
|
406
|
-
[validateConnections]
|
|
407
|
-
);
|
|
408
|
-
const resolvedIsValidConnection = isValidConnection ?? builtinValidator;
|
|
409
|
-
const mergedEdgeTypes = useMemo(
|
|
410
|
-
() => edgeTypes ? { ...edgeTypes } : void 0,
|
|
411
|
-
[edgeTypes]
|
|
412
|
-
);
|
|
413
|
-
const orderedNodes = useMemo(() => sortNodesParentFirst(nodes), [nodes]);
|
|
414
|
-
const [helperLines, setHelperLines] = useState({});
|
|
415
|
-
const handleNodesChange = useCallback(
|
|
416
|
-
(changes) => {
|
|
417
|
-
if (showHelperLines) {
|
|
418
|
-
const pos = changes.filter((c) => c.type === "position" && c.position);
|
|
419
|
-
if (pos.length === 1 && pos[0].dragging) {
|
|
420
|
-
const lines = getHelperLines(pos[0], nodesRef.current);
|
|
421
|
-
if (lines.snapPosition.x !== void 0) pos[0].position.x = lines.snapPosition.x;
|
|
422
|
-
if (lines.snapPosition.y !== void 0) pos[0].position.y = lines.snapPosition.y;
|
|
423
|
-
setHelperLines({ horizontal: lines.horizontal, vertical: lines.vertical });
|
|
424
|
-
} else {
|
|
425
|
-
setHelperLines({});
|
|
426
|
-
}
|
|
427
|
-
}
|
|
428
|
-
onNodesChange?.(changes);
|
|
429
|
-
},
|
|
430
|
-
[showHelperLines, onNodesChange]
|
|
431
|
-
);
|
|
432
|
-
return /* @__PURE__ */ jsxs(
|
|
433
|
-
"div",
|
|
434
|
-
{
|
|
435
|
-
className: [
|
|
436
|
-
"ff-canvas",
|
|
437
|
-
// colorMode drives BOTH react-flow's chrome (below) and our `ff-` styles
|
|
438
|
-
// via the shared `.dark` class / light opt-out — one theme signal.
|
|
439
|
-
colorMode === "dark" ? "dark" : "",
|
|
440
|
-
colorMode === "light" ? "ff-canvas--light" : "",
|
|
441
|
-
className ?? ""
|
|
442
|
-
].filter(Boolean).join(" "),
|
|
443
|
-
style: { height, ...style },
|
|
444
|
-
children: [
|
|
445
|
-
toolbar && /* @__PURE__ */ jsx("div", { className: "ff-canvas__toolbar", children: toolbar }),
|
|
446
|
-
/* @__PURE__ */ jsx("div", { className: "ff-canvas__surface", children: /* @__PURE__ */ jsxs(
|
|
447
|
-
index,
|
|
448
|
-
{
|
|
449
|
-
nodes: orderedNodes,
|
|
450
|
-
edges,
|
|
451
|
-
onNodesChange: handleNodesChange,
|
|
452
|
-
colorMode,
|
|
453
|
-
nodeTypes: mergedNodeTypes,
|
|
454
|
-
edgeTypes: mergedEdgeTypes,
|
|
455
|
-
fitView: true,
|
|
456
|
-
fitViewOptions: DEFAULT_FIT_VIEW,
|
|
457
|
-
defaultEdgeOptions: DEFAULT_EDGE_OPTIONS,
|
|
458
|
-
proOptions: { hideAttribution: true },
|
|
459
|
-
...wheelZoomProps(zoomOnWheel),
|
|
460
|
-
isValidConnection: resolvedIsValidConnection,
|
|
461
|
-
...rest,
|
|
462
|
-
children: [
|
|
463
|
-
background !== "none" && /* @__PURE__ */ jsx(Background, { variant: background, gap: 20, size: 1, color: "rgba(0,0,0,0.18)" }),
|
|
464
|
-
showControls && /* @__PURE__ */ jsx(Controls, { className: "ff-controls", position: "bottom-right" }),
|
|
465
|
-
showMinimap && /* @__PURE__ */ jsx(MiniMap, { className: "ff-minimap", pannable: true, zoomable: true }),
|
|
466
|
-
showHelperLines && /* @__PURE__ */ jsx(HelperLines, { horizontal: helperLines.horizontal, vertical: helperLines.vertical })
|
|
467
|
-
]
|
|
468
|
-
}
|
|
469
|
-
) })
|
|
470
|
-
]
|
|
471
|
-
}
|
|
472
|
-
);
|
|
473
|
-
}
|
|
474
22
|
var CATEGORY_ORDER = ["trigger", "logic", "data", "ai", "io", "human", "output", "layout", "annotation", "custom"];
|
|
475
23
|
var CATEGORY_LABELS = {
|
|
476
24
|
trigger: "Triggers",
|
|
@@ -1487,7 +1035,7 @@ function FlowEditorInner({
|
|
|
1487
1035
|
[flow]
|
|
1488
1036
|
);
|
|
1489
1037
|
const onReconnect = useCallback(
|
|
1490
|
-
(oldEdge, conn) => flow.setEdges((eds) =>
|
|
1038
|
+
(oldEdge, conn) => flow.setEdges((eds) => reconnectEdge(eds, oldEdge, conn)),
|
|
1491
1039
|
[flow]
|
|
1492
1040
|
);
|
|
1493
1041
|
const isLaneNode = useCallback(
|
|
@@ -1498,10 +1046,10 @@ function FlowEditorInner({
|
|
|
1498
1046
|
(orientation = "horizontal", title) => {
|
|
1499
1047
|
const vertical = orientation === "vertical";
|
|
1500
1048
|
const lanes = flow.nodes.filter(isLaneNode);
|
|
1501
|
-
const
|
|
1502
|
-
const
|
|
1049
|
+
const w = vertical ? 280 : 680;
|
|
1050
|
+
const h = vertical ? 480 : 168;
|
|
1503
1051
|
const end = lanes.reduce(
|
|
1504
|
-
(m, l) => Math.max(m, vertical ? l.position.x + (l.width ??
|
|
1052
|
+
(m, l) => Math.max(m, vertical ? l.position.x + (l.width ?? w) : l.position.y + (l.height ?? h)),
|
|
1505
1053
|
0
|
|
1506
1054
|
);
|
|
1507
1055
|
const id = newNodeId();
|
|
@@ -1510,8 +1058,8 @@ function FlowEditorInner({
|
|
|
1510
1058
|
id,
|
|
1511
1059
|
type: "@particle-academy/lane",
|
|
1512
1060
|
position: vertical ? { x: lanes.length ? end + 12 : 0, y: 0 } : { x: 0, y: lanes.length ? end + 12 : 0 },
|
|
1513
|
-
width:
|
|
1514
|
-
height:
|
|
1061
|
+
width: w,
|
|
1062
|
+
height: h,
|
|
1515
1063
|
data: { kind: "@particle-academy/lane", label: name, config: { title: name, orientation } }
|
|
1516
1064
|
};
|
|
1517
1065
|
flow.setNodes((all) => [...all, node]);
|
|
@@ -1927,135 +1475,6 @@ function EdgeLabelEditor({
|
|
|
1927
1475
|
}
|
|
1928
1476
|
);
|
|
1929
1477
|
}
|
|
1930
|
-
var STATUS_LABEL = {
|
|
1931
|
-
ok: "ok",
|
|
1932
|
-
running: "running",
|
|
1933
|
-
failed: "failed",
|
|
1934
|
-
skipped: "skipped",
|
|
1935
|
-
pending: "pending"
|
|
1936
|
-
};
|
|
1937
|
-
function FlowViewer({
|
|
1938
|
-
graph,
|
|
1939
|
-
variant = "canvas",
|
|
1940
|
-
height = 480,
|
|
1941
|
-
showMinimap = false,
|
|
1942
|
-
showControls = true,
|
|
1943
|
-
statuses,
|
|
1944
|
-
selectedNodeId = null,
|
|
1945
|
-
onSelectNode,
|
|
1946
|
-
className,
|
|
1947
|
-
classNames = {},
|
|
1948
|
-
style,
|
|
1949
|
-
empty
|
|
1950
|
-
}) {
|
|
1951
|
-
const nodeTypes = useMemo(() => buildNodeTypes(), []);
|
|
1952
|
-
const rows = useMemo(
|
|
1953
|
-
() => graph.nodes.map((node, index2) => {
|
|
1954
|
-
const kind = getNodeKind(node.data?.kind ?? node.type ?? "");
|
|
1955
|
-
return {
|
|
1956
|
-
node,
|
|
1957
|
-
index: index2,
|
|
1958
|
-
title: kind?.label ?? node.data?.label ?? node.data?.kind ?? node.id,
|
|
1959
|
-
description: kind?.description ?? null,
|
|
1960
|
-
accent: kind?.accent ?? categoryAccent(kind?.category ?? "custom"),
|
|
1961
|
-
status: statuses?.[node.id] ?? null
|
|
1962
|
-
};
|
|
1963
|
-
}),
|
|
1964
|
-
[graph.nodes, statuses]
|
|
1965
|
-
);
|
|
1966
|
-
if (graph.nodes.length === 0) {
|
|
1967
|
-
return /* @__PURE__ */ jsx("div", { className: cx("ff-viewer ff-viewer--empty", className, classNames.root), style, children: empty ?? /* @__PURE__ */ jsx("span", { className: "ff-viewer__empty", children: "This flow has no nodes." }) });
|
|
1968
|
-
}
|
|
1969
|
-
if (variant === "list") {
|
|
1970
|
-
return /* @__PURE__ */ jsx(
|
|
1971
|
-
"div",
|
|
1972
|
-
{
|
|
1973
|
-
className: cx("ff-viewer ff-viewer--list", className, classNames.root),
|
|
1974
|
-
style,
|
|
1975
|
-
"data-flow-viewer": "list",
|
|
1976
|
-
children: /* @__PURE__ */ jsx("ol", { className: cx("ff-viewer__list", classNames.list), children: rows.map(({ node, index: index2, title, description, accent, status }) => {
|
|
1977
|
-
const selected = node.id === selectedNodeId;
|
|
1978
|
-
const Row = onSelectNode ? "button" : "div";
|
|
1979
|
-
return /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsxs(
|
|
1980
|
-
Row,
|
|
1981
|
-
{
|
|
1982
|
-
...onSelectNode ? { type: "button", onClick: () => onSelectNode(node) } : {},
|
|
1983
|
-
className: cx(
|
|
1984
|
-
"ff-viewer__row",
|
|
1985
|
-
selected && "ff-viewer__row--selected",
|
|
1986
|
-
onSelectNode && "ff-viewer__row--interactive",
|
|
1987
|
-
classNames.row
|
|
1988
|
-
),
|
|
1989
|
-
"data-flow-viewer-node": node.id,
|
|
1990
|
-
"data-flow-viewer-status": status ?? void 0,
|
|
1991
|
-
"aria-current": selected || void 0,
|
|
1992
|
-
children: [
|
|
1993
|
-
/* @__PURE__ */ jsx(
|
|
1994
|
-
"span",
|
|
1995
|
-
{
|
|
1996
|
-
className: cx("ff-viewer__index", classNames.rowIndex),
|
|
1997
|
-
style: { backgroundColor: accent },
|
|
1998
|
-
"aria-hidden": true,
|
|
1999
|
-
children: index2 + 1
|
|
2000
|
-
}
|
|
2001
|
-
),
|
|
2002
|
-
/* @__PURE__ */ jsxs("span", { className: "ff-viewer__body", children: [
|
|
2003
|
-
/* @__PURE__ */ jsx("span", { className: cx("ff-viewer__title", classNames.rowTitle), children: title }),
|
|
2004
|
-
description && /* @__PURE__ */ jsx("span", { className: cx("ff-viewer__desc", classNames.rowDescription), children: description })
|
|
2005
|
-
] }),
|
|
2006
|
-
status && /* @__PURE__ */ jsx(
|
|
2007
|
-
"span",
|
|
2008
|
-
{
|
|
2009
|
-
className: cx(
|
|
2010
|
-
"ff-viewer__status",
|
|
2011
|
-
`ff-viewer__status--${status}`,
|
|
2012
|
-
classNames.rowStatus
|
|
2013
|
-
),
|
|
2014
|
-
children: STATUS_LABEL[status]
|
|
2015
|
-
}
|
|
2016
|
-
)
|
|
2017
|
-
]
|
|
2018
|
-
}
|
|
2019
|
-
) }, node.id);
|
|
2020
|
-
}) })
|
|
2021
|
-
}
|
|
2022
|
-
);
|
|
2023
|
-
}
|
|
2024
|
-
return /* @__PURE__ */ jsx(
|
|
2025
|
-
"div",
|
|
2026
|
-
{
|
|
2027
|
-
className: cx("ff-viewer ff-viewer--canvas", className, classNames.root),
|
|
2028
|
-
style,
|
|
2029
|
-
"data-flow-viewer": "canvas",
|
|
2030
|
-
children: /* @__PURE__ */ jsx(
|
|
2031
|
-
FlowCanvas,
|
|
2032
|
-
{
|
|
2033
|
-
nodes: graph.nodes,
|
|
2034
|
-
edges: graph.edges,
|
|
2035
|
-
nodeTypes,
|
|
2036
|
-
height,
|
|
2037
|
-
showControls,
|
|
2038
|
-
showMinimap,
|
|
2039
|
-
nodesDraggable: false,
|
|
2040
|
-
nodesConnectable: false,
|
|
2041
|
-
nodesFocusable: Boolean(onSelectNode),
|
|
2042
|
-
edgesFocusable: false,
|
|
2043
|
-
elementsSelectable: Boolean(onSelectNode),
|
|
2044
|
-
deleteKeyCode: null,
|
|
2045
|
-
selectionKeyCode: null,
|
|
2046
|
-
multiSelectionKeyCode: null,
|
|
2047
|
-
connectOnClick: false,
|
|
2048
|
-
zoomOnScroll: false,
|
|
2049
|
-
onNodeClick: onSelectNode ? (_, node) => onSelectNode(node) : void 0,
|
|
2050
|
-
fitView: true
|
|
2051
|
-
}
|
|
2052
|
-
)
|
|
2053
|
-
}
|
|
2054
|
-
);
|
|
2055
|
-
}
|
|
2056
|
-
function cx(...parts) {
|
|
2057
|
-
return parts.filter(Boolean).join(" ");
|
|
2058
|
-
}
|
|
2059
1478
|
function defineNode(render) {
|
|
2060
1479
|
function Wrapped(props) {
|
|
2061
1480
|
return render({
|
|
@@ -2090,6 +1509,6 @@ function NodePort({ side, type, id, style, title, className }) {
|
|
|
2090
1509
|
// src/index.ts
|
|
2091
1510
|
registerBuiltinKinds();
|
|
2092
1511
|
|
|
2093
|
-
export {
|
|
1512
|
+
export { ConfigFieldRenderer, FlowEditor, FlowRunControls, FlowRunFeed, NodeConfigPanel, NodePalette, NodePort, defineNode, paletteDropHandlers };
|
|
2094
1513
|
//# sourceMappingURL=index.js.map
|
|
2095
1514
|
//# sourceMappingURL=index.js.map
|