@particle-academy/fancy-flow 0.18.0 → 0.19.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/{chunk-MFMRTRPO.js → chunk-PHX4SBOD.js} +114 -5
- package/dist/chunk-PHX4SBOD.js.map +1 -0
- package/dist/index.cjs +193 -28
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +24 -1
- package/dist/index.d.ts +24 -1
- package/dist/index.js +83 -29
- package/dist/index.js.map +1 -1
- package/dist/runtime/index.d.cts +61 -1
- package/dist/runtime/index.d.ts +61 -1
- package/dist/runtime.cjs +112 -1
- package/dist/runtime.cjs.map +1 -1
- package/dist/runtime.js +1 -1
- package/package.json +6 -3
- package/dist/chunk-MFMRTRPO.js.map +0 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { applyNodeChanges, applyEdgeChanges, addEdge } from './chunk-NF6NPY5N.js';
|
|
2
2
|
import { runFlow } from './chunk-L4AX73Q6.js';
|
|
3
|
-
import { useState, useRef, useCallback } from 'react';
|
|
3
|
+
import { useState, useRef, useCallback, useMemo } from 'react';
|
|
4
4
|
|
|
5
5
|
function useFlowRun({ maxFeed = 200 } = {}) {
|
|
6
6
|
const [statuses, setStatuses] = useState({});
|
|
@@ -105,10 +105,119 @@ function useFlowState(initial) {
|
|
|
105
105
|
const onConnect = useCallback((connection) => {
|
|
106
106
|
setEdges((es) => addEdge(connection, es));
|
|
107
107
|
}, []);
|
|
108
|
+
const setGraph = useCallback((graph) => {
|
|
109
|
+
setNodes(graph.nodes);
|
|
110
|
+
setEdges(graph.edges);
|
|
111
|
+
}, []);
|
|
108
112
|
const toGraph = useCallback(() => ({ nodes, edges }), [nodes, edges]);
|
|
109
|
-
return { nodes, edges, setNodes, setEdges, onNodesChange, onEdgesChange, onConnect, toGraph };
|
|
113
|
+
return { nodes, edges, setNodes, setEdges, setGraph, onNodesChange, onEdgesChange, onConnect, toGraph };
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// src/runtime/history.ts
|
|
117
|
+
function createHistory(limit = 100) {
|
|
118
|
+
let past = [];
|
|
119
|
+
let future = [];
|
|
120
|
+
return {
|
|
121
|
+
push(graph) {
|
|
122
|
+
past.push(graph);
|
|
123
|
+
if (past.length > limit) past.shift();
|
|
124
|
+
future = [];
|
|
125
|
+
},
|
|
126
|
+
undo(current) {
|
|
127
|
+
const prev = past.pop();
|
|
128
|
+
if (prev === void 0) return null;
|
|
129
|
+
future.push(current);
|
|
130
|
+
return prev;
|
|
131
|
+
},
|
|
132
|
+
redo(current) {
|
|
133
|
+
const next = future.pop();
|
|
134
|
+
if (next === void 0) return null;
|
|
135
|
+
past.push(current);
|
|
136
|
+
return next;
|
|
137
|
+
},
|
|
138
|
+
canUndo: () => past.length > 0,
|
|
139
|
+
canRedo: () => future.length > 0,
|
|
140
|
+
clear() {
|
|
141
|
+
past = [];
|
|
142
|
+
future = [];
|
|
143
|
+
},
|
|
144
|
+
size: () => ({ past: past.length, future: future.length })
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// src/runtime/use-flow-history.ts
|
|
149
|
+
function useFlowHistory(flow) {
|
|
150
|
+
const history = useRef(createHistory()).current;
|
|
151
|
+
const restoring = useRef(false);
|
|
152
|
+
const coalesced = useRef(false);
|
|
153
|
+
const [, bump] = useState(0);
|
|
154
|
+
const rerender = useCallback(() => bump((n) => n + 1), []);
|
|
155
|
+
const graphRef = useRef({ nodes: flow.nodes, edges: flow.edges });
|
|
156
|
+
graphRef.current = { nodes: flow.nodes, edges: flow.edges };
|
|
157
|
+
const capture = useCallback(() => {
|
|
158
|
+
if (restoring.current || coalesced.current) return;
|
|
159
|
+
coalesced.current = true;
|
|
160
|
+
queueMicrotask(() => {
|
|
161
|
+
coalesced.current = false;
|
|
162
|
+
});
|
|
163
|
+
history.push(graphRef.current);
|
|
164
|
+
rerender();
|
|
165
|
+
}, [history, rerender]);
|
|
166
|
+
const restore = useCallback(
|
|
167
|
+
(g) => {
|
|
168
|
+
if (!g) return;
|
|
169
|
+
restoring.current = true;
|
|
170
|
+
flow.setGraph(g);
|
|
171
|
+
queueMicrotask(() => {
|
|
172
|
+
restoring.current = false;
|
|
173
|
+
});
|
|
174
|
+
rerender();
|
|
175
|
+
},
|
|
176
|
+
[flow, rerender]
|
|
177
|
+
);
|
|
178
|
+
const undo = useCallback(() => restore(history.undo(graphRef.current)), [history, restore]);
|
|
179
|
+
const redo = useCallback(() => restore(history.redo(graphRef.current)), [history, restore]);
|
|
180
|
+
const wrapped = useMemo(
|
|
181
|
+
() => ({
|
|
182
|
+
...flow,
|
|
183
|
+
setNodes: (next) => {
|
|
184
|
+
capture();
|
|
185
|
+
flow.setNodes(next);
|
|
186
|
+
},
|
|
187
|
+
setEdges: (next) => {
|
|
188
|
+
capture();
|
|
189
|
+
flow.setEdges(next);
|
|
190
|
+
},
|
|
191
|
+
setGraph: (g) => {
|
|
192
|
+
capture();
|
|
193
|
+
flow.setGraph(g);
|
|
194
|
+
},
|
|
195
|
+
onNodesChange: (changes) => {
|
|
196
|
+
if (!restoring.current && changes.some((c) => c.type === "remove")) capture();
|
|
197
|
+
flow.onNodesChange(changes);
|
|
198
|
+
},
|
|
199
|
+
onEdgesChange: (changes) => {
|
|
200
|
+
if (!restoring.current && changes.some((c) => c.type === "remove")) capture();
|
|
201
|
+
flow.onEdgesChange(changes);
|
|
202
|
+
},
|
|
203
|
+
onConnect: (conn) => {
|
|
204
|
+
capture();
|
|
205
|
+
flow.onConnect(conn);
|
|
206
|
+
}
|
|
207
|
+
}),
|
|
208
|
+
[flow, capture]
|
|
209
|
+
);
|
|
210
|
+
return {
|
|
211
|
+
flow: wrapped,
|
|
212
|
+
undo,
|
|
213
|
+
redo,
|
|
214
|
+
canUndo: history.canUndo(),
|
|
215
|
+
canRedo: history.canRedo(),
|
|
216
|
+
capture,
|
|
217
|
+
onNodeDragStart: capture
|
|
218
|
+
};
|
|
110
219
|
}
|
|
111
220
|
|
|
112
|
-
export { applyStatusesToNodes, useFlowRun, useFlowState };
|
|
113
|
-
//# sourceMappingURL=chunk-
|
|
114
|
-
//# sourceMappingURL=chunk-
|
|
221
|
+
export { applyStatusesToNodes, createHistory, useFlowHistory, useFlowRun, useFlowState };
|
|
222
|
+
//# sourceMappingURL=chunk-PHX4SBOD.js.map
|
|
223
|
+
//# sourceMappingURL=chunk-PHX4SBOD.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/runtime/use-flow-run.ts","../src/runtime/use-flow-state.ts","../src/runtime/history.ts","../src/runtime/use-flow-history.ts"],"names":["useState","useCallback","useRef"],"mappings":"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","file":"chunk-PHX4SBOD.js","sourcesContent":["import { useCallback, useRef, useState } from \"react\";\nimport { runFlow, type RunOptions, type RunResult } from \"./run-flow\";\nimport type {\n ExecutorRegistry,\n FlowGraph,\n NodeRunStatus,\n RunEvent,\n} from \"../types\";\n\nexport type FlowRunFeedEntry = {\n id: string;\n at: number;\n level: \"info\" | \"warn\" | \"error\" | \"status\";\n text: string;\n nodeId?: string;\n detail?: unknown;\n};\n\nexport type UseFlowRunReturn = {\n /** Status keyed by nodeId — drive the UI overlay from this. */\n statuses: Record<string, NodeRunStatus>;\n /** Per-node status text (e.g. error message). */\n statusText: Record<string, string | undefined>;\n /** Live event log (capped to last N). */\n feed: FlowRunFeedEntry[];\n /** Whether a run is currently in progress. */\n running: boolean;\n /** Last run result, or null. */\n lastResult: RunResult | null;\n /** Kick off a run with the provided graph + executors. */\n run: (graph: FlowGraph, executors: ExecutorRegistry, options?: RunOptions) => Promise<RunResult>;\n /** Cancel the current run (if any). */\n cancel: () => void;\n /** Reset all runtime state (statuses, feed, lastResult). */\n reset: () => void;\n};\n\nexport type UseFlowRunOptions = {\n /** Cap the in-memory feed to this many entries. Default 200. */\n maxFeed?: number;\n};\n\n/**\n * useFlowRun — drives `runFlow` + maintains observability state. Pair with\n * `applyStatusesToNodes` (below) before passing nodes to `<FlowCanvas>` so\n * the per-node status badge renders.\n */\nexport function useFlowRun({ maxFeed = 200 }: UseFlowRunOptions = {}): UseFlowRunReturn {\n const [statuses, setStatuses] = useState<Record<string, NodeRunStatus>>({});\n const [statusText, setStatusText] = useState<Record<string, string | undefined>>({});\n const [feed, setFeed] = useState<FlowRunFeedEntry[]>([]);\n const [running, setRunning] = useState(false);\n const [lastResult, setLastResult] = useState<RunResult | null>(null);\n const abortRef = useRef<AbortController | null>(null);\n\n const handleEvent = useCallback(\n (e: RunEvent) => {\n switch (e.type) {\n case \"node-status\":\n setStatuses((s) => ({ ...s, [e.nodeId]: e.status }));\n setStatusText((t) => ({ ...t, [e.nodeId]: e.text }));\n appendFeed({ level: \"status\", text: `${e.nodeId} → ${e.status}${e.text ? ` (${e.text})` : \"\"}`, nodeId: e.nodeId });\n break;\n case \"node-output\":\n appendFeed({ level: \"info\", text: `${e.nodeId}.${e.portId} = ${preview(e.value)}`, nodeId: e.nodeId, detail: e.value });\n break;\n case \"log\":\n appendFeed({ level: e.level, text: e.message, nodeId: e.nodeId, detail: e.detail });\n break;\n case \"run-start\":\n appendFeed({ level: \"info\", text: \"▶ run started\" });\n break;\n case \"run-end\":\n appendFeed({ level: e.ok ? \"info\" : \"error\", text: e.ok ? \"✓ run complete\" : \"✗ run failed\" });\n break;\n case \"run-error\":\n appendFeed({ level: \"error\", text: e.error });\n break;\n }\n function appendFeed(partial: Omit<FlowRunFeedEntry, \"id\" | \"at\">) {\n setFeed((f) => {\n const entry: FlowRunFeedEntry = { id: `${Date.now()}_${f.length}`, at: Date.now(), ...partial };\n const next = [...f, entry];\n return next.length > maxFeed ? next.slice(next.length - maxFeed) : next;\n });\n }\n },\n [maxFeed],\n );\n\n const run = useCallback(\n async (graph: FlowGraph, executors: ExecutorRegistry, options: RunOptions = {}) => {\n if (running) {\n return { ok: false, outputs: {}, error: \"another run is already in progress\" } satisfies RunResult;\n }\n const controller = new AbortController();\n abortRef.current = controller;\n // Reset previous statuses for the nodes we're about to run.\n const idleStatuses: Record<string, NodeRunStatus> = {};\n for (const n of graph.nodes) idleStatuses[n.id] = \"idle\";\n setStatuses(idleStatuses);\n setStatusText({});\n setRunning(true);\n try {\n const result = await runFlow(graph, executors, handleEvent, { ...options, signal: controller.signal });\n setLastResult(result);\n return result;\n } finally {\n setRunning(false);\n abortRef.current = null;\n }\n },\n [handleEvent, running],\n );\n\n const cancel = useCallback(() => abortRef.current?.abort(), []);\n\n const reset = useCallback(() => {\n setStatuses({});\n setStatusText({});\n setFeed([]);\n setLastResult(null);\n }, []);\n\n return { statuses, statusText, feed, running, lastResult, run, cancel, reset };\n}\n\n/** Merge runtime statuses into nodes for rendering. */\nexport function applyStatusesToNodes<TNode extends { id: string; data: any }>(\n nodes: TNode[],\n statuses: Record<string, NodeRunStatus>,\n statusText: Record<string, string | undefined>,\n): TNode[] {\n return nodes.map((n) => ({\n ...n,\n data: {\n ...n.data,\n status: statuses[n.id] ?? n.data?.status ?? \"idle\",\n statusText: statusText[n.id] ?? n.data?.statusText,\n },\n }));\n}\n\nfunction preview(v: unknown): string {\n try {\n const s = JSON.stringify(v);\n return s && s.length > 60 ? s.slice(0, 57) + \"…\" : (s ?? String(v));\n } catch {\n return String(v);\n }\n}\n","import { useCallback, useState } from \"react\";\nimport {\n addEdge,\n applyEdgeChanges,\n applyNodeChanges,\n type Connection,\n type Edge,\n type EdgeChange,\n type NodeChange,\n} from \"@xyflow/react\";\nimport type { FlowEdge, FlowGraph, FlowNode } from \"../types\";\n\nexport type UseFlowStateReturn = {\n nodes: FlowNode[];\n edges: FlowEdge[];\n setNodes: React.Dispatch<React.SetStateAction<FlowNode[]>>;\n setEdges: React.Dispatch<React.SetStateAction<FlowEdge[]>>;\n /**\n * Replace nodes AND edges atomically in a single commit. Use this for any op\n * that touches both (delete-with-edge-prune, undo/redo restore, setGraph):\n * calling `setNodes` then `setEdges` is NOT atomic in controlled mode (each\n * closes over a stale `value`), so the second write clobbers the first.\n */\n setGraph: (graph: FlowGraph) => void;\n onNodesChange: (changes: NodeChange[]) => void;\n onEdgesChange: (changes: EdgeChange[]) => void;\n onConnect: (connection: Connection) => void;\n /** Snapshot the current graph (suitable for serialization). */\n toGraph: () => FlowGraph;\n};\n\n/**\n * useFlowState — React Flow's standard controlled-state plumbing in one hook.\n * Spread into <FlowCanvas>.\n */\nexport function useFlowState(initial: FlowGraph): UseFlowStateReturn {\n const [nodes, setNodes] = useState<FlowNode[]>(initial.nodes);\n const [edges, setEdges] = useState<FlowEdge[]>(initial.edges);\n\n const onNodesChange = useCallback((changes: NodeChange[]) => {\n setNodes((ns) => applyNodeChanges(changes, ns) as FlowNode[]);\n }, []);\n const onEdgesChange = useCallback((changes: EdgeChange[]) => {\n setEdges((es) => applyEdgeChanges(changes, es));\n }, []);\n const onConnect = useCallback((connection: Connection) => {\n setEdges((es) => addEdge(connection, es) as Edge[]);\n }, []);\n\n const setGraph = useCallback((graph: FlowGraph) => {\n // Two useState writes in one event are batched, so this IS atomic here.\n setNodes(graph.nodes);\n setEdges(graph.edges);\n }, []);\n\n const toGraph = useCallback(() => ({ nodes, edges }), [nodes, edges]);\n\n return { nodes, edges, setNodes, setEdges, setGraph, onNodesChange, onEdgesChange, onConnect, toGraph };\n}\n","import type { FlowGraph } from \"../types\";\n\n/**\n * Undo/redo history — a pure, React-free snapshot controller. The editor pushes\n * a graph snapshot BEFORE each committing mutation; `undo`/`redo` swap snapshots\n * between the past/future stacks. Kept free of React so it can be unit-tested\n * and reused by any host (or a headless driver).\n *\n * Coalescing (collapsing a burst of setState calls from one logical op into a\n * single undo step) is the caller's job — see `useFlowHistory`.\n */\nexport type HistoryController = {\n /** Record `graph` as an undo point. Clears the redo stack (new branch). */\n push: (graph: FlowGraph) => void;\n /** Pop the last undo point; `current` is pushed onto the redo stack. */\n undo: (current: FlowGraph) => FlowGraph | null;\n /** Pop the last redo point; `current` is pushed back onto the undo stack. */\n redo: (current: FlowGraph) => FlowGraph | null;\n canUndo: () => boolean;\n canRedo: () => boolean;\n clear: () => void;\n /** Test/inspection helper — sizes of the two stacks. */\n size: () => { past: number; future: number };\n};\n\nexport function createHistory(limit = 100): HistoryController {\n let past: FlowGraph[] = [];\n let future: FlowGraph[] = [];\n\n return {\n push(graph) {\n past.push(graph);\n if (past.length > limit) past.shift();\n future = [];\n },\n undo(current) {\n const prev = past.pop();\n if (prev === undefined) return null;\n future.push(current);\n return prev;\n },\n redo(current) {\n const next = future.pop();\n if (next === undefined) return null;\n past.push(current);\n return next;\n },\n canUndo: () => past.length > 0,\n canRedo: () => future.length > 0,\n clear() {\n past = [];\n future = [];\n },\n size: () => ({ past: past.length, future: future.length }),\n };\n}\n","import { useCallback, useMemo, useRef, useState } from \"react\";\nimport type { EdgeChange, NodeChange } from \"@xyflow/react\";\nimport type { FlowGraph } from \"../types\";\nimport { createHistory } from \"./history\";\nimport type { UseFlowStateReturn } from \"./use-flow-state\";\n\nexport type UseFlowHistoryReturn = {\n /** The flow sink wrapped so committing mutations snapshot for undo first. */\n flow: UseFlowStateReturn;\n undo: () => void;\n redo: () => void;\n canUndo: boolean;\n canRedo: boolean;\n /** Snapshot the current graph as an undo point (before a programmatic edit). */\n capture: () => void;\n /** Wire to `<FlowCanvas onNodeDragStart>` — snapshots the pre-drag graph. */\n onNodeDragStart: () => void;\n};\n\n/**\n * useFlowHistory — the commit/undo pipeline. Wraps a flow sink (the uncontrolled\n * `useFlowState` hook OR the controlled adapter) so every *committing* mutation\n * records a snapshot first, giving undo/redo without the editor threading\n * history through each call site. This is the single interception point the\n * two-sink architecture otherwise lacks.\n *\n * Granularity: a burst of setState calls from one logical op (e.g. a\n * delete = setNodes+setEdges) is coalesced into ONE undo step; transient\n * interactive changes (drag-move, dimension-measure, selection) are NOT captured\n * — a drag is captured once at `onNodeDragStart` instead.\n */\nexport function useFlowHistory(flow: UseFlowStateReturn): UseFlowHistoryReturn {\n const history = useRef(createHistory()).current;\n const restoring = useRef(false);\n const coalesced = useRef(false);\n const [, bump] = useState(0);\n const rerender = useCallback(() => bump((n) => n + 1), []);\n\n // Latest graph via a ref, so capture never reads a stale snapshot.\n const graphRef = useRef<FlowGraph>({ nodes: flow.nodes, edges: flow.edges });\n graphRef.current = { nodes: flow.nodes, edges: flow.edges };\n\n const capture = useCallback(() => {\n if (restoring.current || coalesced.current) return;\n coalesced.current = true;\n queueMicrotask(() => {\n coalesced.current = false;\n });\n history.push(graphRef.current);\n rerender();\n }, [history, rerender]);\n\n const restore = useCallback(\n (g: FlowGraph | null) => {\n if (!g) return;\n restoring.current = true;\n flow.setGraph(g);\n queueMicrotask(() => {\n restoring.current = false;\n });\n rerender();\n },\n [flow, rerender],\n );\n\n const undo = useCallback(() => restore(history.undo(graphRef.current)), [history, restore]);\n const redo = useCallback(() => restore(history.redo(graphRef.current)), [history, restore]);\n\n const wrapped = useMemo<UseFlowStateReturn>(\n () => ({\n ...flow,\n setNodes: (next) => {\n capture();\n flow.setNodes(next);\n },\n setEdges: (next) => {\n capture();\n flow.setEdges(next);\n },\n setGraph: (g) => {\n capture();\n flow.setGraph(g);\n },\n onNodesChange: (changes: NodeChange[]) => {\n // Only structural removes commit; position/dimensions/select are transient.\n if (!restoring.current && changes.some((c) => c.type === \"remove\")) capture();\n flow.onNodesChange(changes);\n },\n onEdgesChange: (changes: EdgeChange[]) => {\n if (!restoring.current && changes.some((c) => c.type === \"remove\")) capture();\n flow.onEdgesChange(changes);\n },\n onConnect: (conn) => {\n capture();\n flow.onConnect(conn);\n },\n }),\n [flow, capture],\n );\n\n return {\n flow: wrapped,\n undo,\n redo,\n canUndo: history.canUndo(),\n canRedo: history.canRedo(),\n capture,\n onNodeDragStart: capture,\n };\n}\n"]}
|
package/dist/index.cjs
CHANGED
|
@@ -10996,8 +10996,117 @@ function useFlowState(initial) {
|
|
|
10996
10996
|
const onConnect = ReactExports.useCallback((connection) => {
|
|
10997
10997
|
setEdges((es) => addEdge2(connection, es));
|
|
10998
10998
|
}, []);
|
|
10999
|
+
const setGraph = ReactExports.useCallback((graph) => {
|
|
11000
|
+
setNodes(graph.nodes);
|
|
11001
|
+
setEdges(graph.edges);
|
|
11002
|
+
}, []);
|
|
10999
11003
|
const toGraph = ReactExports.useCallback(() => ({ nodes, edges }), [nodes, edges]);
|
|
11000
|
-
return { nodes, edges, setNodes, setEdges, onNodesChange, onEdgesChange, onConnect, toGraph };
|
|
11004
|
+
return { nodes, edges, setNodes, setEdges, setGraph, onNodesChange, onEdgesChange, onConnect, toGraph };
|
|
11005
|
+
}
|
|
11006
|
+
|
|
11007
|
+
// src/runtime/history.ts
|
|
11008
|
+
function createHistory(limit = 100) {
|
|
11009
|
+
let past = [];
|
|
11010
|
+
let future = [];
|
|
11011
|
+
return {
|
|
11012
|
+
push(graph) {
|
|
11013
|
+
past.push(graph);
|
|
11014
|
+
if (past.length > limit) past.shift();
|
|
11015
|
+
future = [];
|
|
11016
|
+
},
|
|
11017
|
+
undo(current) {
|
|
11018
|
+
const prev = past.pop();
|
|
11019
|
+
if (prev === void 0) return null;
|
|
11020
|
+
future.push(current);
|
|
11021
|
+
return prev;
|
|
11022
|
+
},
|
|
11023
|
+
redo(current) {
|
|
11024
|
+
const next = future.pop();
|
|
11025
|
+
if (next === void 0) return null;
|
|
11026
|
+
past.push(current);
|
|
11027
|
+
return next;
|
|
11028
|
+
},
|
|
11029
|
+
canUndo: () => past.length > 0,
|
|
11030
|
+
canRedo: () => future.length > 0,
|
|
11031
|
+
clear() {
|
|
11032
|
+
past = [];
|
|
11033
|
+
future = [];
|
|
11034
|
+
},
|
|
11035
|
+
size: () => ({ past: past.length, future: future.length })
|
|
11036
|
+
};
|
|
11037
|
+
}
|
|
11038
|
+
|
|
11039
|
+
// src/runtime/use-flow-history.ts
|
|
11040
|
+
function useFlowHistory(flow) {
|
|
11041
|
+
const history = ReactExports.useRef(createHistory()).current;
|
|
11042
|
+
const restoring = ReactExports.useRef(false);
|
|
11043
|
+
const coalesced = ReactExports.useRef(false);
|
|
11044
|
+
const [, bump] = ReactExports.useState(0);
|
|
11045
|
+
const rerender = ReactExports.useCallback(() => bump((n) => n + 1), []);
|
|
11046
|
+
const graphRef = ReactExports.useRef({ nodes: flow.nodes, edges: flow.edges });
|
|
11047
|
+
graphRef.current = { nodes: flow.nodes, edges: flow.edges };
|
|
11048
|
+
const capture = ReactExports.useCallback(() => {
|
|
11049
|
+
if (restoring.current || coalesced.current) return;
|
|
11050
|
+
coalesced.current = true;
|
|
11051
|
+
queueMicrotask(() => {
|
|
11052
|
+
coalesced.current = false;
|
|
11053
|
+
});
|
|
11054
|
+
history.push(graphRef.current);
|
|
11055
|
+
rerender();
|
|
11056
|
+
}, [history, rerender]);
|
|
11057
|
+
const restore = ReactExports.useCallback(
|
|
11058
|
+
(g) => {
|
|
11059
|
+
if (!g) return;
|
|
11060
|
+
restoring.current = true;
|
|
11061
|
+
flow.setGraph(g);
|
|
11062
|
+
queueMicrotask(() => {
|
|
11063
|
+
restoring.current = false;
|
|
11064
|
+
});
|
|
11065
|
+
rerender();
|
|
11066
|
+
},
|
|
11067
|
+
[flow, rerender]
|
|
11068
|
+
);
|
|
11069
|
+
const undo = ReactExports.useCallback(() => restore(history.undo(graphRef.current)), [history, restore]);
|
|
11070
|
+
const redo = ReactExports.useCallback(() => restore(history.redo(graphRef.current)), [history, restore]);
|
|
11071
|
+
const wrapped = ReactExports.useMemo(
|
|
11072
|
+
() => ({
|
|
11073
|
+
...flow,
|
|
11074
|
+
setNodes: (next) => {
|
|
11075
|
+
capture();
|
|
11076
|
+
flow.setNodes(next);
|
|
11077
|
+
},
|
|
11078
|
+
setEdges: (next) => {
|
|
11079
|
+
capture();
|
|
11080
|
+
flow.setEdges(next);
|
|
11081
|
+
},
|
|
11082
|
+
setGraph: (g) => {
|
|
11083
|
+
capture();
|
|
11084
|
+
flow.setGraph(g);
|
|
11085
|
+
},
|
|
11086
|
+
onNodesChange: (changes) => {
|
|
11087
|
+
if (!restoring.current && changes.some((c) => c.type === "remove")) capture();
|
|
11088
|
+
flow.onNodesChange(changes);
|
|
11089
|
+
},
|
|
11090
|
+
onEdgesChange: (changes) => {
|
|
11091
|
+
if (!restoring.current && changes.some((c) => c.type === "remove")) capture();
|
|
11092
|
+
flow.onEdgesChange(changes);
|
|
11093
|
+
},
|
|
11094
|
+
onConnect: (conn) => {
|
|
11095
|
+
capture();
|
|
11096
|
+
flow.onConnect(conn);
|
|
11097
|
+
}
|
|
11098
|
+
}),
|
|
11099
|
+
[flow, capture]
|
|
11100
|
+
);
|
|
11101
|
+
return {
|
|
11102
|
+
flow: wrapped,
|
|
11103
|
+
undo,
|
|
11104
|
+
redo,
|
|
11105
|
+
canUndo: history.canUndo(),
|
|
11106
|
+
canRedo: history.canRedo(),
|
|
11107
|
+
capture,
|
|
11108
|
+
onNodeDragStart: capture
|
|
11109
|
+
};
|
|
11001
11110
|
}
|
|
11002
11111
|
function useFlowRun({ maxFeed = 200 } = {}) {
|
|
11003
11112
|
const [statuses, setStatuses] = ReactExports.useState({});
|
|
@@ -11453,13 +11562,16 @@ function FlowEditorInner({
|
|
|
11453
11562
|
onSelectionChange,
|
|
11454
11563
|
onDelete,
|
|
11455
11564
|
onEdgeDelete,
|
|
11565
|
+
confirmDelete,
|
|
11456
11566
|
apiRef
|
|
11457
11567
|
}) {
|
|
11458
11568
|
const internal = useFlowState(initial);
|
|
11459
11569
|
const runner = useFlowRun();
|
|
11460
11570
|
const rf = useReactFlow();
|
|
11461
11571
|
const controlled = value !== void 0;
|
|
11462
|
-
const
|
|
11572
|
+
const baseFlow = controlled ? makeControlledFlowAdapter(value, onChange) : internal;
|
|
11573
|
+
const hist = useFlowHistory(baseFlow);
|
|
11574
|
+
const flow = hist.flow;
|
|
11463
11575
|
const [, force] = ReactExports.useState(0);
|
|
11464
11576
|
ReactExports.useEffect(() => onNodeKindsChanged(() => force((n) => n + 1)), []);
|
|
11465
11577
|
const nodeTypes = ReactExports.useMemo(() => buildNodeTypes(), [listNodeKinds().length]);
|
|
@@ -11512,6 +11624,23 @@ function FlowEditorInner({
|
|
|
11512
11624
|
window.removeEventListener("keydown", onKey);
|
|
11513
11625
|
};
|
|
11514
11626
|
}, [menu, labelEdit]);
|
|
11627
|
+
ReactExports.useEffect(() => {
|
|
11628
|
+
const onKey = (e) => {
|
|
11629
|
+
const t = e.target;
|
|
11630
|
+
if (t && (t.tagName === "INPUT" || t.tagName === "TEXTAREA" || t.isContentEditable)) return;
|
|
11631
|
+
if (!(e.ctrlKey || e.metaKey)) return;
|
|
11632
|
+
const key = e.key.toLowerCase();
|
|
11633
|
+
if (key === "z" && !e.shiftKey) {
|
|
11634
|
+
e.preventDefault();
|
|
11635
|
+
hist.undo();
|
|
11636
|
+
} else if (key === "z" && e.shiftKey || key === "y") {
|
|
11637
|
+
e.preventDefault();
|
|
11638
|
+
hist.redo();
|
|
11639
|
+
}
|
|
11640
|
+
};
|
|
11641
|
+
window.addEventListener("keydown", onKey);
|
|
11642
|
+
return () => window.removeEventListener("keydown", onKey);
|
|
11643
|
+
}, [hist]);
|
|
11515
11644
|
ReactExports.useEffect(() => {
|
|
11516
11645
|
if (!controlled) onChange?.({ nodes: flow.nodes, edges: flow.edges });
|
|
11517
11646
|
}, [flow.nodes, flow.edges, onChange, controlled]);
|
|
@@ -11536,15 +11665,32 @@ function FlowEditorInner({
|
|
|
11536
11665
|
[flow]
|
|
11537
11666
|
);
|
|
11538
11667
|
const deleteNodes = ReactExports.useCallback(
|
|
11539
|
-
(ids) => {
|
|
11668
|
+
async (ids) => {
|
|
11540
11669
|
if (ids.length === 0) return;
|
|
11670
|
+
const targets = flow.nodes.filter((n) => ids.includes(n.id));
|
|
11671
|
+
if (targets.length === 0) return;
|
|
11672
|
+
if (confirmDelete) {
|
|
11673
|
+
const attached = flow.edges.filter((e) => ids.includes(e.source) || ids.includes(e.target));
|
|
11674
|
+
if (!await confirmDelete({ nodes: targets, edges: attached })) return;
|
|
11675
|
+
}
|
|
11541
11676
|
const doomed = new Set(ids);
|
|
11542
|
-
flow.
|
|
11543
|
-
flow.setEdges((all) => removeNodes({ nodes: [], edges: all }, ids).edges);
|
|
11677
|
+
flow.setGraph(removeNodes({ nodes: flow.nodes, edges: flow.edges }, ids));
|
|
11544
11678
|
setSelectedId((cur) => cur !== null && doomed.has(cur) ? null : cur);
|
|
11545
11679
|
onDelete?.(ids);
|
|
11546
11680
|
},
|
|
11547
|
-
[flow, onDelete]
|
|
11681
|
+
[flow, onDelete, confirmDelete]
|
|
11682
|
+
);
|
|
11683
|
+
const deleteEdges = ReactExports.useCallback(
|
|
11684
|
+
async (ids) => {
|
|
11685
|
+
if (ids.length === 0) return;
|
|
11686
|
+
const targets = flow.edges.filter((e) => ids.includes(e.id));
|
|
11687
|
+
if (targets.length === 0) return;
|
|
11688
|
+
if (confirmDelete && !await confirmDelete({ nodes: [], edges: targets })) return;
|
|
11689
|
+
flow.setEdges((all) => removeEdges(all, ids));
|
|
11690
|
+
setSelectedEdgeId((cur) => cur !== null && ids.includes(cur) ? null : cur);
|
|
11691
|
+
onEdgeDelete?.(ids);
|
|
11692
|
+
},
|
|
11693
|
+
[flow, onEdgeDelete, confirmDelete]
|
|
11548
11694
|
);
|
|
11549
11695
|
const api = ReactExports.useMemo(() => {
|
|
11550
11696
|
const toWorkflow = () => exportWorkflow({ nodes: flow.nodes, edges: flow.edges }, metadata);
|
|
@@ -11564,18 +11710,8 @@ function FlowEditorInner({
|
|
|
11564
11710
|
updateNode: (next) => flow.setNodes((all) => all.map((x) => x.id === next.id ? next : x)),
|
|
11565
11711
|
deleteNodes,
|
|
11566
11712
|
deleteSelected: () => deleteNodes(selectedId ? [selectedId] : []),
|
|
11567
|
-
deleteEdges
|
|
11568
|
-
|
|
11569
|
-
flow.setEdges((all) => removeEdges(all, ids));
|
|
11570
|
-
setSelectedEdgeId((cur) => cur !== null && ids.includes(cur) ? null : cur);
|
|
11571
|
-
onEdgeDelete?.(ids);
|
|
11572
|
-
},
|
|
11573
|
-
deleteSelectedEdge: () => {
|
|
11574
|
-
if (!selectedEdgeId) return;
|
|
11575
|
-
flow.setEdges((all) => removeEdges(all, [selectedEdgeId]));
|
|
11576
|
-
setSelectedEdgeId(null);
|
|
11577
|
-
onEdgeDelete?.([selectedEdgeId]);
|
|
11578
|
-
},
|
|
11713
|
+
deleteEdges,
|
|
11714
|
+
deleteSelectedEdge: () => deleteEdges(selectedEdgeId ? [selectedEdgeId] : []),
|
|
11579
11715
|
setEdgeLabel: (id2, label) => flow.setEdges((all) => setEdgeLabel(all, id2, label)),
|
|
11580
11716
|
duplicateNode: (id2) => {
|
|
11581
11717
|
const src = flow.nodes.find((n) => n.id === id2);
|
|
@@ -11585,22 +11721,20 @@ function FlowEditorInner({
|
|
|
11585
11721
|
setSelectedId(copy.id);
|
|
11586
11722
|
return copy.id;
|
|
11587
11723
|
},
|
|
11588
|
-
setGraph: (graph) =>
|
|
11589
|
-
flow.setNodes(graph.nodes);
|
|
11590
|
-
flow.setEdges(graph.edges);
|
|
11591
|
-
},
|
|
11724
|
+
setGraph: (graph) => flow.setGraph(graph),
|
|
11592
11725
|
run: () => runner.run({ nodes: flow.nodes, edges: flow.edges }, executors),
|
|
11593
11726
|
cancel: runner.cancel,
|
|
11594
11727
|
reset: runner.reset,
|
|
11595
11728
|
toWorkflow,
|
|
11596
11729
|
exportWorkflow: () => downloadWorkflow(toWorkflow(), metadata),
|
|
11597
|
-
importWorkflow: () => pickWorkflow((graph) =>
|
|
11598
|
-
|
|
11599
|
-
|
|
11600
|
-
|
|
11601
|
-
|
|
11730
|
+
importWorkflow: () => pickWorkflow((graph) => flow.setGraph(graph)),
|
|
11731
|
+
fitView: () => rf.fitView({ padding: 0.2 }),
|
|
11732
|
+
undo: hist.undo,
|
|
11733
|
+
redo: hist.redo,
|
|
11734
|
+
canUndo: hist.canUndo,
|
|
11735
|
+
canRedo: hist.canRedo
|
|
11602
11736
|
};
|
|
11603
|
-
}, [flow, selectedId, selected2, runner, executors, metadata, addNode, deleteNodes, rf]);
|
|
11737
|
+
}, [flow, selectedId, selected2, selectedEdgeId, selectedEdge, runner, executors, metadata, addNode, deleteNodes, deleteEdges, hist, rf]);
|
|
11604
11738
|
ReactExports.useImperativeHandle(apiRef, () => api, [api]);
|
|
11605
11739
|
const dropHandlers = paletteDropHandlers((kindName, evt) => {
|
|
11606
11740
|
const point = rf.screenToFlowPosition({ x: evt.clientX, y: evt.clientY });
|
|
@@ -11611,6 +11745,31 @@ function FlowEditorInner({
|
|
|
11611
11745
|
const toolbar = slots.toolbar ? slots.toolbar(api) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
11612
11746
|
startActions.map((a) => renderAction(a, api)),
|
|
11613
11747
|
builtins.run !== false && /* @__PURE__ */ jsxRuntime.jsx(FlowRunControls, { running: api.running, onRun: api.run, onCancel: api.cancel, onReset: api.reset }),
|
|
11748
|
+
builtins.history !== false && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
11749
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "ff-editor__sep" }),
|
|
11750
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
11751
|
+
"button",
|
|
11752
|
+
{
|
|
11753
|
+
className: "ff-editor__btn",
|
|
11754
|
+
"data-action": "undo",
|
|
11755
|
+
title: "Undo (Ctrl+Z)",
|
|
11756
|
+
disabled: !api.canUndo,
|
|
11757
|
+
onClick: api.undo,
|
|
11758
|
+
children: "\u21B6 Undo"
|
|
11759
|
+
}
|
|
11760
|
+
),
|
|
11761
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
11762
|
+
"button",
|
|
11763
|
+
{
|
|
11764
|
+
className: "ff-editor__btn",
|
|
11765
|
+
"data-action": "redo",
|
|
11766
|
+
title: "Redo (Ctrl+Shift+Z)",
|
|
11767
|
+
disabled: !api.canRedo,
|
|
11768
|
+
onClick: api.redo,
|
|
11769
|
+
children: "\u21B7 Redo"
|
|
11770
|
+
}
|
|
11771
|
+
)
|
|
11772
|
+
] }),
|
|
11614
11773
|
(builtins.export !== false || builtins.import !== false) && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "ff-editor__sep" }),
|
|
11615
11774
|
builtins.export !== false && /* @__PURE__ */ jsxRuntime.jsx("button", { className: "ff-editor__btn", "data-action": "export", onClick: api.exportWorkflow, children: "\u2193 Export" }),
|
|
11616
11775
|
builtins.import !== false && /* @__PURE__ */ jsxRuntime.jsx("button", { className: "ff-editor__btn", "data-action": "import", onClick: api.importWorkflow, children: "\u2191 Import" }),
|
|
@@ -11635,12 +11794,14 @@ function FlowEditorInner({
|
|
|
11635
11794
|
onNodesChange: flow.onNodesChange,
|
|
11636
11795
|
onEdgesChange: flow.onEdgesChange,
|
|
11637
11796
|
onConnect: flow.onConnect,
|
|
11797
|
+
onNodeDragStart: hist.onNodeDragStart,
|
|
11638
11798
|
onNodeClick: handleNodeClick2,
|
|
11639
11799
|
onNodeContextMenu: builtins.contextMenu === false ? void 0 : handleNodeContextMenu,
|
|
11640
11800
|
onEdgeClick: handleEdgeClick,
|
|
11641
11801
|
onEdgeContextMenu: builtins.edgeContextMenu === false ? void 0 : handleEdgeContextMenu,
|
|
11642
11802
|
onEdgesDelete: (deleted) => onEdgeDelete?.(deleted.map((e) => e.id)),
|
|
11643
11803
|
onNodesDelete: (deleted) => onDelete?.(deleted.map((n) => n.id)),
|
|
11804
|
+
onBeforeDelete: confirmDelete ? async ({ nodes, edges }) => confirmDelete({ nodes, edges }) : void 0,
|
|
11644
11805
|
deleteKeyCode: ["Delete", "Backspace"],
|
|
11645
11806
|
height: "100%",
|
|
11646
11807
|
toolbar,
|
|
@@ -11811,6 +11972,8 @@ function makeControlledFlowAdapter(value, onChange) {
|
|
|
11811
11972
|
const nextEdges = typeof next === "function" ? next(value.edges) : next;
|
|
11812
11973
|
apply({ nodes: value.nodes, edges: nextEdges });
|
|
11813
11974
|
},
|
|
11975
|
+
// Atomic both-at-once commit — the reason this exists (see UseFlowStateReturn).
|
|
11976
|
+
setGraph: (graph) => apply(graph),
|
|
11814
11977
|
onNodesChange: (changes) => {
|
|
11815
11978
|
apply({ nodes: applyNodeChanges(changes, value.nodes), edges: value.edges });
|
|
11816
11979
|
},
|
|
@@ -11924,6 +12087,7 @@ exports.applyStatusesToNodes = applyStatusesToNodes;
|
|
|
11924
12087
|
exports.buildNodeTypes = buildNodeTypes;
|
|
11925
12088
|
exports.categoryAccent = categoryAccent;
|
|
11926
12089
|
exports.createConnectionValidator = createConnectionValidator;
|
|
12090
|
+
exports.createHistory = createHistory;
|
|
11927
12091
|
exports.decodePause = decodePause;
|
|
11928
12092
|
exports.defaultConfigFor = defaultConfigFor;
|
|
11929
12093
|
exports.defaultNodeTypes = defaultNodeTypes;
|
|
@@ -11949,6 +12113,7 @@ exports.resolvePortSpec = resolvePortSpec;
|
|
|
11949
12113
|
exports.runFlow = runFlow;
|
|
11950
12114
|
exports.useFlowEditor = useFlowEditor;
|
|
11951
12115
|
exports.useFlowEditorOptional = useFlowEditorOptional;
|
|
12116
|
+
exports.useFlowHistory = useFlowHistory;
|
|
11952
12117
|
exports.useFlowRun = useFlowRun;
|
|
11953
12118
|
exports.useFlowState = useFlowState;
|
|
11954
12119
|
exports.validateConfig = validateConfig;
|