@particle-academy/fancy-flow 0.17.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-532A5QA3.js → chunk-FSC64BPD.js} +37 -3
- package/dist/chunk-FSC64BPD.js.map +1 -0
- package/dist/{chunk-MFMRTRPO.js → chunk-PHX4SBOD.js} +114 -5
- package/dist/chunk-PHX4SBOD.js.map +1 -0
- package/dist/index.cjs +243 -28
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +36 -4
- package/dist/index.d.ts +36 -4
- package/dist/index.js +98 -31
- package/dist/index.js.map +1 -1
- package/dist/registry/index.d.cts +52 -3
- package/dist/registry/index.d.ts +52 -3
- package/dist/registry.cjs +111 -74
- package/dist/registry.cjs.map +1 -1
- package/dist/registry.js +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-532A5QA3.js.map +0 -1
- package/dist/chunk-MFMRTRPO.js.map +0 -1
package/dist/index.d.cts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import * as react from 'react';
|
|
2
2
|
import { ReactNode, CSSProperties, ComponentType } from 'react';
|
|
3
3
|
import { ReactFlowProps, Edge, BackgroundVariant, NodeProps, NodeTypes } from '@xyflow/react';
|
|
4
|
+
import { ConnectionValidatorOptions } from './registry/index.cjs';
|
|
5
|
+
export { ANY_PORT_TYPE, BUILTIN_KINDS, PortCompatibility, RegistryNode, RichInputAdapter, RichInputPreview, buildNodeTypes, categoryAccent, createConnectionValidator, defaultConfigFor, defaultPortCompatibility, getNodeKind, getRichInputAdapter, isRichInputEnabled, listNodeKinds, onNodeKindsChanged, onRichInputAdapterChanged, registerBuiltinKinds, registerNodeKind, registerRichInputAdapter, resolveNodePorts, resolvePortSpec, validateConfig } from './registry/index.cjs';
|
|
4
6
|
import { b as FlowNode, F as FlowGraph, e as NodeRunStatus, E as ExecutorRegistry } from './types-sOmpCitB.cjs';
|
|
5
7
|
export { A as ActionNodeData, B as BaseNodeData, D as DecisionNodeData, a as FlowEdge, c as FlowNodeData, d as FlowNodeKind, N as NodeExecutor, f as NoteNodeData, O as OutputNodeData, P as PortDescriptor, R as RunEvent, S as SubgraphNodeData, T as TriggerNodeData } from './types-sOmpCitB.cjs';
|
|
6
8
|
import { WorkflowSchema, WorkflowMetadata } from './schema/index.cjs';
|
|
@@ -8,8 +10,7 @@ export { ImportIssue, ImportOptions, ImportResult, WORKFLOW_SCHEMA_URL, WORKFLOW
|
|
|
8
10
|
import { N as NodeCategory, a as NodeKindDefinition, C as ConfigField } from './types-D_jOR3Z2.cjs';
|
|
9
11
|
export { D as DocumentConfigField, K as KeyValueConfigField, P as PortSpec, R as RenderBodyContext, d as RepeaterConfigField, e as RepeaterRowField } from './types-D_jOR3Z2.cjs';
|
|
10
12
|
import { FlowRunFeedEntry } from './runtime/index.cjs';
|
|
11
|
-
export { UseFlowRunOptions, UseFlowRunReturn, UseFlowStateReturn, applyStatusesToNodes, useFlowRun, useFlowState } from './runtime/index.cjs';
|
|
12
|
-
export { BUILTIN_KINDS, RegistryNode, RichInputAdapter, RichInputPreview, buildNodeTypes, categoryAccent, defaultConfigFor, getNodeKind, getRichInputAdapter, isRichInputEnabled, listNodeKinds, onNodeKindsChanged, onRichInputAdapterChanged, registerBuiltinKinds, registerNodeKind, registerRichInputAdapter, resolveNodePorts, resolvePortSpec, validateConfig } from './registry/index.cjs';
|
|
13
|
+
export { HistoryController, UseFlowHistoryReturn, UseFlowRunOptions, UseFlowRunReturn, UseFlowStateReturn, applyStatusesToNodes, createHistory, useFlowHistory, useFlowRun, useFlowState } from './runtime/index.cjs';
|
|
13
14
|
export { R as RunOptions, a as RunResult, r as runFlow } from './run-flow-VKm57Hcj.cjs';
|
|
14
15
|
export { L as LEGACY_PAUSE_PREFIXES, a as PAUSE_PREFIX, P as PauseAwaiting, b as PauseSignal, d as decodePause, e as encodePause, i as isPause, p as pauseForHuman } from './pause-9iT4tCEV.cjs';
|
|
15
16
|
import './capabilities-ChE3Xi8R.cjs';
|
|
@@ -25,6 +26,14 @@ type FlowCanvasProps = Omit<ReactFlowProps<FlowNode, Edge>, "nodes" | "edges" |
|
|
|
25
26
|
showMinimap?: boolean;
|
|
26
27
|
/** Pixel height; FlowCanvas expects a sized container. Default 600. */
|
|
27
28
|
height?: number | string;
|
|
29
|
+
/**
|
|
30
|
+
* Enforce port-type compatibility on new connections. `true` (default) uses
|
|
31
|
+
* the built-in validator: a connection is refused only when both ports
|
|
32
|
+
* declare a concrete, differing `type` (so untyped graphs are unaffected),
|
|
33
|
+
* and self-loops are blocked. Pass options to tune the rule, or `false` to
|
|
34
|
+
* disable. An `isValidConnection` you pass yourself always takes precedence.
|
|
35
|
+
*/
|
|
36
|
+
validateConnections?: boolean | ConnectionValidatorOptions;
|
|
28
37
|
/** Optional toolbar / palette etc. rendered above the canvas. */
|
|
29
38
|
toolbar?: ReactNode;
|
|
30
39
|
className?: string;
|
|
@@ -39,7 +48,7 @@ type FlowCanvasProps = Omit<ReactFlowProps<FlowNode, Edge>, "nodes" | "edges" |
|
|
|
39
48
|
* (xyflow's standard pattern). The surrounding `useFlowState` hook in
|
|
40
49
|
* `runtime/use-flow-state.ts` is a convenience that wires those for you.
|
|
41
50
|
*/
|
|
42
|
-
declare function FlowCanvas({ nodes, edges, background, showControls, showMinimap, height, toolbar, nodeTypes, edgeTypes, className, style, ...rest }: FlowCanvasProps): react.JSX.Element;
|
|
51
|
+
declare function FlowCanvas({ nodes, edges, background, showControls, showMinimap, height, validateConnections, isValidConnection, toolbar, nodeTypes, edgeTypes, className, style, ...rest }: FlowCanvasProps): react.JSX.Element;
|
|
43
52
|
|
|
44
53
|
/**
|
|
45
54
|
* Everything the editor knows and can do, handed to every extension point.
|
|
@@ -100,6 +109,16 @@ type FlowEditorApi = {
|
|
|
100
109
|
/** Open a file picker and load a workflow. */
|
|
101
110
|
importWorkflow: () => void;
|
|
102
111
|
fitView: () => void;
|
|
112
|
+
/** Undo the last committing edit (add / delete / connect / config / drag /
|
|
113
|
+
* import). Transient interactions (a drag in progress, selection) are not
|
|
114
|
+
* their own steps. */
|
|
115
|
+
undo: () => void;
|
|
116
|
+
/** Redo the last undone edit. */
|
|
117
|
+
redo: () => void;
|
|
118
|
+
/** True when there is an edit to undo. */
|
|
119
|
+
canUndo: boolean;
|
|
120
|
+
/** True when there is an undone edit to redo. */
|
|
121
|
+
canRedo: boolean;
|
|
103
122
|
};
|
|
104
123
|
/**
|
|
105
124
|
* A declarative toolbar button. JSON-friendly on purpose — a host (or an
|
|
@@ -125,6 +144,8 @@ type FlowEditorAction = {
|
|
|
125
144
|
type FlowEditorBuiltins = {
|
|
126
145
|
run?: boolean;
|
|
127
146
|
delete?: boolean;
|
|
147
|
+
/** Undo/redo toolbar buttons. Default true. */
|
|
148
|
+
history?: boolean;
|
|
128
149
|
/** Right-click a node for Delete / Duplicate. Default true. */
|
|
129
150
|
contextMenu?: boolean;
|
|
130
151
|
/** Right-click a connection for Label / Delete. Default true. */
|
|
@@ -199,6 +220,17 @@ type FlowEditorProps = {
|
|
|
199
220
|
onDelete?: (ids: string[]) => void;
|
|
200
221
|
/** Called after connections are broken, with the deleted edge ids. */
|
|
201
222
|
onEdgeDelete?: (ids: string[]) => void;
|
|
223
|
+
/**
|
|
224
|
+
* Stage destructive edits for human confirmation. When set, every delete path
|
|
225
|
+
* — keyboard, panel, context menu, and `api.deleteNodes`/`deleteEdges` —
|
|
226
|
+
* calls this first; return false to veto. Default: delete immediately. This
|
|
227
|
+
* realizes the component contract's "agents propose, humans confirm" on the
|
|
228
|
+
* canvas.
|
|
229
|
+
*/
|
|
230
|
+
confirmDelete?: (targets: {
|
|
231
|
+
nodes: FlowNode[];
|
|
232
|
+
edges: Edge[];
|
|
233
|
+
}) => boolean | Promise<boolean>;
|
|
202
234
|
className?: string;
|
|
203
235
|
style?: CSSProperties;
|
|
204
236
|
};
|
|
@@ -444,4 +476,4 @@ type FlowRunFeedProps = {
|
|
|
444
476
|
/** FlowRunFeed — scrolling log panel. Auto-scrolls to bottom on new entries. */
|
|
445
477
|
declare function FlowRunFeed({ entries, className, style }: FlowRunFeedProps): react.JSX.Element;
|
|
446
478
|
|
|
447
|
-
export { ActionNode, ConfigField, ConfigFieldRenderer, type ConfigFieldRendererProps, DecisionNode, ExecutorRegistry, FlowCanvas, type FlowCanvasProps, FlowEditor, type FlowEditorAction, type FlowEditorApi, type FlowEditorBuiltins, type FlowEditorProps, type FlowEditorSlots, FlowGraph, FlowNode, type FlowNodeRenderProps, FlowRunControls, type FlowRunControlsProps, FlowRunFeed, FlowRunFeedEntry, type FlowRunFeedProps, NodeCategory, NodeConfigPanel, type NodeConfigPanelProps, NodeKindDefinition, NodePalette, type NodePaletteProps, NodePort, type NodePortProps, type NodePortSide, type NodePortType, NodeRunStatus, NodeShell, type NodeShellProps, NoteNode, OutputNode, SubgraphNode, TriggerNode, WorkflowMetadata, WorkflowSchema, defaultNodeTypes, defineNode, paletteDropHandlers, useFlowEditor, useFlowEditorOptional };
|
|
479
|
+
export { ActionNode, ConfigField, ConfigFieldRenderer, type ConfigFieldRendererProps, ConnectionValidatorOptions, DecisionNode, ExecutorRegistry, FlowCanvas, type FlowCanvasProps, FlowEditor, type FlowEditorAction, type FlowEditorApi, type FlowEditorBuiltins, type FlowEditorProps, type FlowEditorSlots, FlowGraph, FlowNode, type FlowNodeRenderProps, FlowRunControls, type FlowRunControlsProps, FlowRunFeed, FlowRunFeedEntry, type FlowRunFeedProps, NodeCategory, NodeConfigPanel, type NodeConfigPanelProps, NodeKindDefinition, NodePalette, type NodePaletteProps, NodePort, type NodePortProps, type NodePortSide, type NodePortType, NodeRunStatus, NodeShell, type NodeShellProps, NoteNode, OutputNode, SubgraphNode, TriggerNode, WorkflowMetadata, WorkflowSchema, defaultNodeTypes, defineNode, paletteDropHandlers, useFlowEditor, useFlowEditorOptional };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import * as react from 'react';
|
|
2
2
|
import { ReactNode, CSSProperties, ComponentType } from 'react';
|
|
3
3
|
import { ReactFlowProps, Edge, BackgroundVariant, NodeProps, NodeTypes } from '@xyflow/react';
|
|
4
|
+
import { ConnectionValidatorOptions } from './registry/index.js';
|
|
5
|
+
export { ANY_PORT_TYPE, BUILTIN_KINDS, PortCompatibility, RegistryNode, RichInputAdapter, RichInputPreview, buildNodeTypes, categoryAccent, createConnectionValidator, defaultConfigFor, defaultPortCompatibility, getNodeKind, getRichInputAdapter, isRichInputEnabled, listNodeKinds, onNodeKindsChanged, onRichInputAdapterChanged, registerBuiltinKinds, registerNodeKind, registerRichInputAdapter, resolveNodePorts, resolvePortSpec, validateConfig } from './registry/index.js';
|
|
4
6
|
import { b as FlowNode, F as FlowGraph, e as NodeRunStatus, E as ExecutorRegistry } from './types-sOmpCitB.js';
|
|
5
7
|
export { A as ActionNodeData, B as BaseNodeData, D as DecisionNodeData, a as FlowEdge, c as FlowNodeData, d as FlowNodeKind, N as NodeExecutor, f as NoteNodeData, O as OutputNodeData, P as PortDescriptor, R as RunEvent, S as SubgraphNodeData, T as TriggerNodeData } from './types-sOmpCitB.js';
|
|
6
8
|
import { WorkflowSchema, WorkflowMetadata } from './schema/index.js';
|
|
@@ -8,8 +10,7 @@ export { ImportIssue, ImportOptions, ImportResult, WORKFLOW_SCHEMA_URL, WORKFLOW
|
|
|
8
10
|
import { N as NodeCategory, a as NodeKindDefinition, C as ConfigField } from './types-NerkPtHS.js';
|
|
9
11
|
export { D as DocumentConfigField, K as KeyValueConfigField, P as PortSpec, R as RenderBodyContext, d as RepeaterConfigField, e as RepeaterRowField } from './types-NerkPtHS.js';
|
|
10
12
|
import { FlowRunFeedEntry } from './runtime/index.js';
|
|
11
|
-
export { UseFlowRunOptions, UseFlowRunReturn, UseFlowStateReturn, applyStatusesToNodes, useFlowRun, useFlowState } from './runtime/index.js';
|
|
12
|
-
export { BUILTIN_KINDS, RegistryNode, RichInputAdapter, RichInputPreview, buildNodeTypes, categoryAccent, defaultConfigFor, getNodeKind, getRichInputAdapter, isRichInputEnabled, listNodeKinds, onNodeKindsChanged, onRichInputAdapterChanged, registerBuiltinKinds, registerNodeKind, registerRichInputAdapter, resolveNodePorts, resolvePortSpec, validateConfig } from './registry/index.js';
|
|
13
|
+
export { HistoryController, UseFlowHistoryReturn, UseFlowRunOptions, UseFlowRunReturn, UseFlowStateReturn, applyStatusesToNodes, createHistory, useFlowHistory, useFlowRun, useFlowState } from './runtime/index.js';
|
|
13
14
|
export { R as RunOptions, a as RunResult, r as runFlow } from './run-flow-ChBi6q-W.js';
|
|
14
15
|
export { L as LEGACY_PAUSE_PREFIXES, a as PAUSE_PREFIX, P as PauseAwaiting, b as PauseSignal, d as decodePause, e as encodePause, i as isPause, p as pauseForHuman } from './pause-9iT4tCEV.js';
|
|
15
16
|
import './capabilities-DUhAc-EJ.js';
|
|
@@ -25,6 +26,14 @@ type FlowCanvasProps = Omit<ReactFlowProps<FlowNode, Edge>, "nodes" | "edges" |
|
|
|
25
26
|
showMinimap?: boolean;
|
|
26
27
|
/** Pixel height; FlowCanvas expects a sized container. Default 600. */
|
|
27
28
|
height?: number | string;
|
|
29
|
+
/**
|
|
30
|
+
* Enforce port-type compatibility on new connections. `true` (default) uses
|
|
31
|
+
* the built-in validator: a connection is refused only when both ports
|
|
32
|
+
* declare a concrete, differing `type` (so untyped graphs are unaffected),
|
|
33
|
+
* and self-loops are blocked. Pass options to tune the rule, or `false` to
|
|
34
|
+
* disable. An `isValidConnection` you pass yourself always takes precedence.
|
|
35
|
+
*/
|
|
36
|
+
validateConnections?: boolean | ConnectionValidatorOptions;
|
|
28
37
|
/** Optional toolbar / palette etc. rendered above the canvas. */
|
|
29
38
|
toolbar?: ReactNode;
|
|
30
39
|
className?: string;
|
|
@@ -39,7 +48,7 @@ type FlowCanvasProps = Omit<ReactFlowProps<FlowNode, Edge>, "nodes" | "edges" |
|
|
|
39
48
|
* (xyflow's standard pattern). The surrounding `useFlowState` hook in
|
|
40
49
|
* `runtime/use-flow-state.ts` is a convenience that wires those for you.
|
|
41
50
|
*/
|
|
42
|
-
declare function FlowCanvas({ nodes, edges, background, showControls, showMinimap, height, toolbar, nodeTypes, edgeTypes, className, style, ...rest }: FlowCanvasProps): react.JSX.Element;
|
|
51
|
+
declare function FlowCanvas({ nodes, edges, background, showControls, showMinimap, height, validateConnections, isValidConnection, toolbar, nodeTypes, edgeTypes, className, style, ...rest }: FlowCanvasProps): react.JSX.Element;
|
|
43
52
|
|
|
44
53
|
/**
|
|
45
54
|
* Everything the editor knows and can do, handed to every extension point.
|
|
@@ -100,6 +109,16 @@ type FlowEditorApi = {
|
|
|
100
109
|
/** Open a file picker and load a workflow. */
|
|
101
110
|
importWorkflow: () => void;
|
|
102
111
|
fitView: () => void;
|
|
112
|
+
/** Undo the last committing edit (add / delete / connect / config / drag /
|
|
113
|
+
* import). Transient interactions (a drag in progress, selection) are not
|
|
114
|
+
* their own steps. */
|
|
115
|
+
undo: () => void;
|
|
116
|
+
/** Redo the last undone edit. */
|
|
117
|
+
redo: () => void;
|
|
118
|
+
/** True when there is an edit to undo. */
|
|
119
|
+
canUndo: boolean;
|
|
120
|
+
/** True when there is an undone edit to redo. */
|
|
121
|
+
canRedo: boolean;
|
|
103
122
|
};
|
|
104
123
|
/**
|
|
105
124
|
* A declarative toolbar button. JSON-friendly on purpose — a host (or an
|
|
@@ -125,6 +144,8 @@ type FlowEditorAction = {
|
|
|
125
144
|
type FlowEditorBuiltins = {
|
|
126
145
|
run?: boolean;
|
|
127
146
|
delete?: boolean;
|
|
147
|
+
/** Undo/redo toolbar buttons. Default true. */
|
|
148
|
+
history?: boolean;
|
|
128
149
|
/** Right-click a node for Delete / Duplicate. Default true. */
|
|
129
150
|
contextMenu?: boolean;
|
|
130
151
|
/** Right-click a connection for Label / Delete. Default true. */
|
|
@@ -199,6 +220,17 @@ type FlowEditorProps = {
|
|
|
199
220
|
onDelete?: (ids: string[]) => void;
|
|
200
221
|
/** Called after connections are broken, with the deleted edge ids. */
|
|
201
222
|
onEdgeDelete?: (ids: string[]) => void;
|
|
223
|
+
/**
|
|
224
|
+
* Stage destructive edits for human confirmation. When set, every delete path
|
|
225
|
+
* — keyboard, panel, context menu, and `api.deleteNodes`/`deleteEdges` —
|
|
226
|
+
* calls this first; return false to veto. Default: delete immediately. This
|
|
227
|
+
* realizes the component contract's "agents propose, humans confirm" on the
|
|
228
|
+
* canvas.
|
|
229
|
+
*/
|
|
230
|
+
confirmDelete?: (targets: {
|
|
231
|
+
nodes: FlowNode[];
|
|
232
|
+
edges: Edge[];
|
|
233
|
+
}) => boolean | Promise<boolean>;
|
|
202
234
|
className?: string;
|
|
203
235
|
style?: CSSProperties;
|
|
204
236
|
};
|
|
@@ -444,4 +476,4 @@ type FlowRunFeedProps = {
|
|
|
444
476
|
/** FlowRunFeed — scrolling log panel. Auto-scrolls to bottom on new entries. */
|
|
445
477
|
declare function FlowRunFeed({ entries, className, style }: FlowRunFeedProps): react.JSX.Element;
|
|
446
478
|
|
|
447
|
-
export { ActionNode, ConfigField, ConfigFieldRenderer, type ConfigFieldRendererProps, DecisionNode, ExecutorRegistry, FlowCanvas, type FlowCanvasProps, FlowEditor, type FlowEditorAction, type FlowEditorApi, type FlowEditorBuiltins, type FlowEditorProps, type FlowEditorSlots, FlowGraph, FlowNode, type FlowNodeRenderProps, FlowRunControls, type FlowRunControlsProps, FlowRunFeed, FlowRunFeedEntry, type FlowRunFeedProps, NodeCategory, NodeConfigPanel, type NodeConfigPanelProps, NodeKindDefinition, NodePalette, type NodePaletteProps, NodePort, type NodePortProps, type NodePortSide, type NodePortType, NodeRunStatus, NodeShell, type NodeShellProps, NoteNode, OutputNode, SubgraphNode, TriggerNode, WorkflowMetadata, WorkflowSchema, defaultNodeTypes, defineNode, paletteDropHandlers, useFlowEditor, useFlowEditorOptional };
|
|
479
|
+
export { ActionNode, ConfigField, ConfigFieldRenderer, type ConfigFieldRendererProps, ConnectionValidatorOptions, DecisionNode, ExecutorRegistry, FlowCanvas, type FlowCanvasProps, FlowEditor, type FlowEditorAction, type FlowEditorApi, type FlowEditorBuiltins, type FlowEditorProps, type FlowEditorSlots, FlowGraph, FlowNode, type FlowNodeRenderProps, FlowRunControls, type FlowRunControlsProps, FlowRunFeed, FlowRunFeedEntry, type FlowRunFeedProps, NodeCategory, NodeConfigPanel, type NodeConfigPanelProps, NodeKindDefinition, NodePalette, type NodePaletteProps, NodePort, type NodePortProps, type NodePortSide, type NodePortType, NodeRunStatus, NodeShell, type NodeShellProps, NoteNode, OutputNode, SubgraphNode, TriggerNode, WorkflowMetadata, WorkflowSchema, defaultNodeTypes, defineNode, paletteDropHandlers, useFlowEditor, useFlowEditorOptional };
|
package/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { useFlowState, useFlowRun, applyStatusesToNodes } from './chunk-
|
|
2
|
-
export { applyStatusesToNodes, useFlowRun, useFlowState } from './chunk-
|
|
3
|
-
import { buildNodeTypes, registerBuiltinKinds } from './chunk-
|
|
4
|
-
export { BUILTIN_KINDS, RegistryNode, buildNodeTypes, registerBuiltinKinds } from './chunk-
|
|
1
|
+
import { useFlowState, useFlowRun, useFlowHistory, applyStatusesToNodes } from './chunk-PHX4SBOD.js';
|
|
2
|
+
export { applyStatusesToNodes, createHistory, useFlowHistory, useFlowRun, useFlowState } from './chunk-PHX4SBOD.js';
|
|
3
|
+
import { buildNodeTypes, registerBuiltinKinds, createConnectionValidator } from './chunk-FSC64BPD.js';
|
|
4
|
+
export { ANY_PORT_TYPE, BUILTIN_KINDS, RegistryNode, buildNodeTypes, createConnectionValidator, defaultPortCompatibility, registerBuiltinKinds } from './chunk-FSC64BPD.js';
|
|
5
5
|
import { ReactFlowProvider, useReactFlow, addEdge, applyEdgeChanges, applyNodeChanges, Position, Handle, index, BackgroundVariant, Background, Controls, MiniMap } from './chunk-NF6NPY5N.js';
|
|
6
6
|
export { LEGACY_PAUSE_PREFIXES, PAUSE_PREFIX, decodePause, encodePause, isPause, pauseForHuman } from './chunk-UEOE6B52.js';
|
|
7
7
|
export { runFlow } from './chunk-L4AX73Q6.js';
|
|
@@ -151,6 +151,8 @@ function FlowCanvas({
|
|
|
151
151
|
showControls = true,
|
|
152
152
|
showMinimap = false,
|
|
153
153
|
height = 600,
|
|
154
|
+
validateConnections = true,
|
|
155
|
+
isValidConnection,
|
|
154
156
|
toolbar,
|
|
155
157
|
nodeTypes,
|
|
156
158
|
edgeTypes,
|
|
@@ -162,6 +164,16 @@ function FlowCanvas({
|
|
|
162
164
|
() => ({ ...defaultNodeTypes, ...nodeTypes ?? {} }),
|
|
163
165
|
[nodeTypes]
|
|
164
166
|
);
|
|
167
|
+
const nodesRef = useRef(nodes);
|
|
168
|
+
nodesRef.current = nodes;
|
|
169
|
+
const builtinValidator = useMemo(
|
|
170
|
+
() => validateConnections === false ? void 0 : createConnectionValidator(
|
|
171
|
+
() => nodesRef.current,
|
|
172
|
+
validateConnections === true ? void 0 : validateConnections
|
|
173
|
+
),
|
|
174
|
+
[validateConnections]
|
|
175
|
+
);
|
|
176
|
+
const resolvedIsValidConnection = isValidConnection ?? builtinValidator;
|
|
165
177
|
const mergedEdgeTypes = useMemo(
|
|
166
178
|
() => edgeTypes ? { ...edgeTypes } : void 0,
|
|
167
179
|
[edgeTypes]
|
|
@@ -181,6 +193,7 @@ function FlowCanvas({
|
|
|
181
193
|
proOptions: { hideAttribution: true },
|
|
182
194
|
zoomActivationKeyCode: "Shift",
|
|
183
195
|
preventScrolling: false,
|
|
196
|
+
isValidConnection: resolvedIsValidConnection,
|
|
184
197
|
...rest,
|
|
185
198
|
children: [
|
|
186
199
|
background !== "none" && /* @__PURE__ */ jsx(Background, { variant: background, gap: 20, size: 1, color: "rgba(0,0,0,0.18)" }),
|
|
@@ -865,13 +878,16 @@ function FlowEditorInner({
|
|
|
865
878
|
onSelectionChange,
|
|
866
879
|
onDelete,
|
|
867
880
|
onEdgeDelete,
|
|
881
|
+
confirmDelete,
|
|
868
882
|
apiRef
|
|
869
883
|
}) {
|
|
870
884
|
const internal = useFlowState(initial);
|
|
871
885
|
const runner = useFlowRun();
|
|
872
886
|
const rf = useReactFlow();
|
|
873
887
|
const controlled = value !== void 0;
|
|
874
|
-
const
|
|
888
|
+
const baseFlow = controlled ? makeControlledFlowAdapter(value, onChange) : internal;
|
|
889
|
+
const hist = useFlowHistory(baseFlow);
|
|
890
|
+
const flow = hist.flow;
|
|
875
891
|
const [, force] = useState(0);
|
|
876
892
|
useEffect(() => onNodeKindsChanged(() => force((n) => n + 1)), []);
|
|
877
893
|
const nodeTypes = useMemo(() => buildNodeTypes(), [listNodeKinds().length]);
|
|
@@ -924,6 +940,23 @@ function FlowEditorInner({
|
|
|
924
940
|
window.removeEventListener("keydown", onKey);
|
|
925
941
|
};
|
|
926
942
|
}, [menu, labelEdit]);
|
|
943
|
+
useEffect(() => {
|
|
944
|
+
const onKey = (e) => {
|
|
945
|
+
const t = e.target;
|
|
946
|
+
if (t && (t.tagName === "INPUT" || t.tagName === "TEXTAREA" || t.isContentEditable)) return;
|
|
947
|
+
if (!(e.ctrlKey || e.metaKey)) return;
|
|
948
|
+
const key = e.key.toLowerCase();
|
|
949
|
+
if (key === "z" && !e.shiftKey) {
|
|
950
|
+
e.preventDefault();
|
|
951
|
+
hist.undo();
|
|
952
|
+
} else if (key === "z" && e.shiftKey || key === "y") {
|
|
953
|
+
e.preventDefault();
|
|
954
|
+
hist.redo();
|
|
955
|
+
}
|
|
956
|
+
};
|
|
957
|
+
window.addEventListener("keydown", onKey);
|
|
958
|
+
return () => window.removeEventListener("keydown", onKey);
|
|
959
|
+
}, [hist]);
|
|
927
960
|
useEffect(() => {
|
|
928
961
|
if (!controlled) onChange?.({ nodes: flow.nodes, edges: flow.edges });
|
|
929
962
|
}, [flow.nodes, flow.edges, onChange, controlled]);
|
|
@@ -948,15 +981,32 @@ function FlowEditorInner({
|
|
|
948
981
|
[flow]
|
|
949
982
|
);
|
|
950
983
|
const deleteNodes = useCallback(
|
|
951
|
-
(ids) => {
|
|
984
|
+
async (ids) => {
|
|
952
985
|
if (ids.length === 0) return;
|
|
986
|
+
const targets = flow.nodes.filter((n) => ids.includes(n.id));
|
|
987
|
+
if (targets.length === 0) return;
|
|
988
|
+
if (confirmDelete) {
|
|
989
|
+
const attached = flow.edges.filter((e) => ids.includes(e.source) || ids.includes(e.target));
|
|
990
|
+
if (!await confirmDelete({ nodes: targets, edges: attached })) return;
|
|
991
|
+
}
|
|
953
992
|
const doomed = new Set(ids);
|
|
954
|
-
flow.
|
|
955
|
-
flow.setEdges((all) => removeNodes({ nodes: [], edges: all }, ids).edges);
|
|
993
|
+
flow.setGraph(removeNodes({ nodes: flow.nodes, edges: flow.edges }, ids));
|
|
956
994
|
setSelectedId((cur) => cur !== null && doomed.has(cur) ? null : cur);
|
|
957
995
|
onDelete?.(ids);
|
|
958
996
|
},
|
|
959
|
-
[flow, onDelete]
|
|
997
|
+
[flow, onDelete, confirmDelete]
|
|
998
|
+
);
|
|
999
|
+
const deleteEdges = useCallback(
|
|
1000
|
+
async (ids) => {
|
|
1001
|
+
if (ids.length === 0) return;
|
|
1002
|
+
const targets = flow.edges.filter((e) => ids.includes(e.id));
|
|
1003
|
+
if (targets.length === 0) return;
|
|
1004
|
+
if (confirmDelete && !await confirmDelete({ nodes: [], edges: targets })) return;
|
|
1005
|
+
flow.setEdges((all) => removeEdges(all, ids));
|
|
1006
|
+
setSelectedEdgeId((cur) => cur !== null && ids.includes(cur) ? null : cur);
|
|
1007
|
+
onEdgeDelete?.(ids);
|
|
1008
|
+
},
|
|
1009
|
+
[flow, onEdgeDelete, confirmDelete]
|
|
960
1010
|
);
|
|
961
1011
|
const api = useMemo(() => {
|
|
962
1012
|
const toWorkflow = () => exportWorkflow({ nodes: flow.nodes, edges: flow.edges }, metadata);
|
|
@@ -976,18 +1026,8 @@ function FlowEditorInner({
|
|
|
976
1026
|
updateNode: (next) => flow.setNodes((all) => all.map((x) => x.id === next.id ? next : x)),
|
|
977
1027
|
deleteNodes,
|
|
978
1028
|
deleteSelected: () => deleteNodes(selectedId ? [selectedId] : []),
|
|
979
|
-
deleteEdges
|
|
980
|
-
|
|
981
|
-
flow.setEdges((all) => removeEdges(all, ids));
|
|
982
|
-
setSelectedEdgeId((cur) => cur !== null && ids.includes(cur) ? null : cur);
|
|
983
|
-
onEdgeDelete?.(ids);
|
|
984
|
-
},
|
|
985
|
-
deleteSelectedEdge: () => {
|
|
986
|
-
if (!selectedEdgeId) return;
|
|
987
|
-
flow.setEdges((all) => removeEdges(all, [selectedEdgeId]));
|
|
988
|
-
setSelectedEdgeId(null);
|
|
989
|
-
onEdgeDelete?.([selectedEdgeId]);
|
|
990
|
-
},
|
|
1029
|
+
deleteEdges,
|
|
1030
|
+
deleteSelectedEdge: () => deleteEdges(selectedEdgeId ? [selectedEdgeId] : []),
|
|
991
1031
|
setEdgeLabel: (id, label) => flow.setEdges((all) => setEdgeLabel(all, id, label)),
|
|
992
1032
|
duplicateNode: (id) => {
|
|
993
1033
|
const src = flow.nodes.find((n) => n.id === id);
|
|
@@ -997,22 +1037,20 @@ function FlowEditorInner({
|
|
|
997
1037
|
setSelectedId(copy.id);
|
|
998
1038
|
return copy.id;
|
|
999
1039
|
},
|
|
1000
|
-
setGraph: (graph) =>
|
|
1001
|
-
flow.setNodes(graph.nodes);
|
|
1002
|
-
flow.setEdges(graph.edges);
|
|
1003
|
-
},
|
|
1040
|
+
setGraph: (graph) => flow.setGraph(graph),
|
|
1004
1041
|
run: () => runner.run({ nodes: flow.nodes, edges: flow.edges }, executors),
|
|
1005
1042
|
cancel: runner.cancel,
|
|
1006
1043
|
reset: runner.reset,
|
|
1007
1044
|
toWorkflow,
|
|
1008
1045
|
exportWorkflow: () => downloadWorkflow(toWorkflow(), metadata),
|
|
1009
|
-
importWorkflow: () => pickWorkflow((graph) =>
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1046
|
+
importWorkflow: () => pickWorkflow((graph) => flow.setGraph(graph)),
|
|
1047
|
+
fitView: () => rf.fitView({ padding: 0.2 }),
|
|
1048
|
+
undo: hist.undo,
|
|
1049
|
+
redo: hist.redo,
|
|
1050
|
+
canUndo: hist.canUndo,
|
|
1051
|
+
canRedo: hist.canRedo
|
|
1014
1052
|
};
|
|
1015
|
-
}, [flow, selectedId, selected, runner, executors, metadata, addNode, deleteNodes, rf]);
|
|
1053
|
+
}, [flow, selectedId, selected, selectedEdgeId, selectedEdge, runner, executors, metadata, addNode, deleteNodes, deleteEdges, hist, rf]);
|
|
1016
1054
|
useImperativeHandle(apiRef, () => api, [api]);
|
|
1017
1055
|
const dropHandlers = paletteDropHandlers((kindName, evt) => {
|
|
1018
1056
|
const point = rf.screenToFlowPosition({ x: evt.clientX, y: evt.clientY });
|
|
@@ -1023,6 +1061,31 @@ function FlowEditorInner({
|
|
|
1023
1061
|
const toolbar = slots.toolbar ? slots.toolbar(api) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
1024
1062
|
startActions.map((a) => renderAction(a, api)),
|
|
1025
1063
|
builtins.run !== false && /* @__PURE__ */ jsx(FlowRunControls, { running: api.running, onRun: api.run, onCancel: api.cancel, onReset: api.reset }),
|
|
1064
|
+
builtins.history !== false && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
1065
|
+
/* @__PURE__ */ jsx("span", { className: "ff-editor__sep" }),
|
|
1066
|
+
/* @__PURE__ */ jsx(
|
|
1067
|
+
"button",
|
|
1068
|
+
{
|
|
1069
|
+
className: "ff-editor__btn",
|
|
1070
|
+
"data-action": "undo",
|
|
1071
|
+
title: "Undo (Ctrl+Z)",
|
|
1072
|
+
disabled: !api.canUndo,
|
|
1073
|
+
onClick: api.undo,
|
|
1074
|
+
children: "\u21B6 Undo"
|
|
1075
|
+
}
|
|
1076
|
+
),
|
|
1077
|
+
/* @__PURE__ */ jsx(
|
|
1078
|
+
"button",
|
|
1079
|
+
{
|
|
1080
|
+
className: "ff-editor__btn",
|
|
1081
|
+
"data-action": "redo",
|
|
1082
|
+
title: "Redo (Ctrl+Shift+Z)",
|
|
1083
|
+
disabled: !api.canRedo,
|
|
1084
|
+
onClick: api.redo,
|
|
1085
|
+
children: "\u21B7 Redo"
|
|
1086
|
+
}
|
|
1087
|
+
)
|
|
1088
|
+
] }),
|
|
1026
1089
|
(builtins.export !== false || builtins.import !== false) && /* @__PURE__ */ jsx("span", { className: "ff-editor__sep" }),
|
|
1027
1090
|
builtins.export !== false && /* @__PURE__ */ jsx("button", { className: "ff-editor__btn", "data-action": "export", onClick: api.exportWorkflow, children: "\u2193 Export" }),
|
|
1028
1091
|
builtins.import !== false && /* @__PURE__ */ jsx("button", { className: "ff-editor__btn", "data-action": "import", onClick: api.importWorkflow, children: "\u2191 Import" }),
|
|
@@ -1047,12 +1110,14 @@ function FlowEditorInner({
|
|
|
1047
1110
|
onNodesChange: flow.onNodesChange,
|
|
1048
1111
|
onEdgesChange: flow.onEdgesChange,
|
|
1049
1112
|
onConnect: flow.onConnect,
|
|
1113
|
+
onNodeDragStart: hist.onNodeDragStart,
|
|
1050
1114
|
onNodeClick: handleNodeClick,
|
|
1051
1115
|
onNodeContextMenu: builtins.contextMenu === false ? void 0 : handleNodeContextMenu,
|
|
1052
1116
|
onEdgeClick: handleEdgeClick,
|
|
1053
1117
|
onEdgeContextMenu: builtins.edgeContextMenu === false ? void 0 : handleEdgeContextMenu,
|
|
1054
1118
|
onEdgesDelete: (deleted) => onEdgeDelete?.(deleted.map((e) => e.id)),
|
|
1055
1119
|
onNodesDelete: (deleted) => onDelete?.(deleted.map((n) => n.id)),
|
|
1120
|
+
onBeforeDelete: confirmDelete ? async ({ nodes, edges }) => confirmDelete({ nodes, edges }) : void 0,
|
|
1056
1121
|
deleteKeyCode: ["Delete", "Backspace"],
|
|
1057
1122
|
height: "100%",
|
|
1058
1123
|
toolbar,
|
|
@@ -1223,6 +1288,8 @@ function makeControlledFlowAdapter(value, onChange) {
|
|
|
1223
1288
|
const nextEdges = typeof next === "function" ? next(value.edges) : next;
|
|
1224
1289
|
apply({ nodes: value.nodes, edges: nextEdges });
|
|
1225
1290
|
},
|
|
1291
|
+
// Atomic both-at-once commit — the reason this exists (see UseFlowStateReturn).
|
|
1292
|
+
setGraph: (graph) => apply(graph),
|
|
1226
1293
|
onNodesChange: (changes) => {
|
|
1227
1294
|
apply({ nodes: applyNodeChanges(changes, value.nodes), edges: value.edges });
|
|
1228
1295
|
},
|