The WorkflowBuilder component is the main visual workflow editor powered by React Flow.
Component
function WorkflowBuilder ( props : WorkflowBuilderProps ) : JSX . Element ;
Props
Array of node classes to make available in the palette.
onWorkflowChange
(workflow: Workflow) => void
Callback when workflow changes (nodes added/removed, connections changed, etc.).
Optional initial workflow to load.
Show/hide the node palette sidebar.
Show/hide the property panel sidebar.
Show/hide JSON editor (Monaco).
editorMode
'visual' | 'json' | 'split'
default: "'visual'"
Editor view mode.
onExecute
(result: ExecutionResult) => void
Callback when workflow execution completes.
Callback when an error occurs.
Additional CSS class for the container.
Inline styles for the container.
Basic Usage
import React from 'react' ;
import { WorkflowBuilder } from '@crystalflow/react' ;
import { AddNode , MultiplyNode , DisplayNode } from './nodes' ;
function App () {
const nodes = [ AddNode , MultiplyNode , DisplayNode ];
const handleWorkflowChange = ( workflow ) => {
console . log ( 'Workflow changed:' , workflow . toJSON ());
};
const handleExecute = ( result ) => {
console . log ( 'Execution result:' , result );
};
return (
< WorkflowBuilder
nodes = { nodes }
onWorkflowChange = { handleWorkflowChange }
onExecute = { handleExecute }
/>
);
}
With Initial Workflow
import { Workflow } from '@crystalflow/core' ;
const initialWorkflow = new Workflow ( 'my-workflow' , 'My Workflow' );
// Add nodes and connections...
< WorkflowBuilder
nodes = { [ AddNode , MultiplyNode ] }
initialWorkflow = { initialWorkflow }
onWorkflowChange = { handleChange }
/>
Custom Configuration
< WorkflowBuilder
nodes = { [ AddNode , MultiplyNode ] }
showNodePalette = { true }
showPropertyPanel = { true }
showToolbar = { true }
editorMode = "visual"
className = "my-workflow-builder"
style = { { height: '800px' } }
onWorkflowChange = { handleChange }
onExecute = { handleExecute }
onError = { handleError }
/>
JSON Editor Mode
Work in Progress: Monaco JSON editor integration is currently being implemented.
< WorkflowBuilder
nodes = { [ AddNode , MultiplyNode ] }
showJsonEditor = { true }
editorMode = "split" // visual, json, or split
/>
Features
Drag & Drop Drag nodes from palette to canvas
Visual Connections Connect nodes by dragging between ports
Property Editing Edit node properties in the sidebar
Execute Workflows Run workflows and view results
Save/Load Import and export workflows as JSON
Event Handlers
onWorkflowChange
Called whenever the workflow structure changes:
const handleChange = ( workflow : Workflow ) => {
// Save to localStorage
localStorage . setItem ( 'workflow' , JSON . stringify ( workflow . toJSON ()));
// or send to server
await saveWorkflow ( workflow . toJSON ());
};
onExecute
Called when workflow execution completes:
const handleExecute = ( result : ExecutionResult ) => {
if ( result . status === 'success' ) {
console . log ( 'Success! Duration:' , result . duration , 'ms' );
// Access node results
result . nodeResults . forEach (( nodeResult , nodeId ) => {
console . log ( `Node ${ nodeId } :` , nodeResult . outputs );
});
} else {
console . error ( 'Execution failed:' , result . error );
}
};
onError
Called when errors occur in the UI:
const handleError = ( error : Error ) => {
// Show error notification
toast . error ( error . message );
// Log to error service
errorLogger . log ( error );
};
Styling
The WorkflowBuilder uses CSS modules and can be customized:
/* Your custom styles */
.my-workflow-builder {
border : 1 px solid #ddd ;
border-radius : 8 px ;
box-shadow : 0 2 px 8 px rgba ( 0 , 0 , 0 , 0.1 );
}
/* Override internal styles */
.my-workflow-builder .react-flow__node {
border : 2 px solid #007bff ;
}
Complete Example
import React , { useState , useCallback } from 'react' ;
import { WorkflowBuilder } from '@crystalflow/react' ;
import { Workflow , ExecutionResult } from '@crystalflow/core' ;
import {
NumberInputNode ,
AddNode ,
MultiplyNode ,
DisplayNode
} from './nodes' ;
function WorkflowApp () {
const [ workflow , setWorkflow ] = useState < Workflow | null >( null );
const [ result , setResult ] = useState < ExecutionResult | null >( null );
const nodes = [
NumberInputNode ,
AddNode ,
MultiplyNode ,
DisplayNode
];
const handleWorkflowChange = useCallback (( newWorkflow : Workflow ) => {
setWorkflow ( newWorkflow );
// Auto-save to localStorage
localStorage . setItem (
'workflow' ,
JSON . stringify ( newWorkflow . toJSON ())
);
}, []);
const handleExecute = useCallback (( executionResult : ExecutionResult ) => {
setResult ( executionResult );
if ( executionResult . status === 'success' ) {
console . log ( 'Workflow executed successfully!' );
}
}, []);
const handleError = useCallback (( error : Error ) => {
console . error ( 'Error:' , error );
alert ( `Error: ${ error . message } ` );
}, []);
return (
< div className = "app" >
< h1 > My Workflow Editor </ h1 >
< WorkflowBuilder
nodes = { nodes }
onWorkflowChange = { handleWorkflowChange }
onExecute = { handleExecute }
onError = { handleError }
showNodePalette = { true }
showPropertyPanel = { true }
showToolbar = { true }
style = { { height: '600px' } }
/>
{ result && (
< div className = "results" >
< h2 > Execution Result </ h2 >
< pre > { JSON . stringify ( result , null , 2 ) } </ pre >
</ div >
) }
</ div >
);
}
export default WorkflowApp ;