@gongfu/flowgram
v0.2.0
Published
A powerful flow diagram SDK for building visual workflow editors
Maintainers
Readme
@kongfu/flowgram
A powerful and flexible flow diagram SDK for building visual workflow editors. Built on top of React Flow with additional features for workflow management.
Features
- 🎨 Rich Node Types - Start, End, Task, Decision, Parallel, Subprocess nodes
- 🔧 Drag & Drop - Intuitive node creation and connection
- 📐 Auto Layout - Automatic graph layout with dagre
- ✅ Validation - Built-in flow validation with error/warning display
- 🎯 Context Menus - Right-click menus for nodes, edges, and canvas
- 💾 Import/Export - Support for JSON, SVG, PNG formats
- 🌍 i18n Support - English and Chinese localization
- 🎭 Customizable - Custom nodes, edges, themes, and behaviors
- ⚡ Performance - Optimized for large graphs with virtualization
Installation
npm install @kongfu/flowgram
# or
yarn add @kongfu/flowgram
# or
pnpm add @kongfu/flowgramQuick Start
import { Flowgram } from '@kongfu/flowgram';
import '@kongfu/flowgram/styles.css';
function App() {
const handleSave = async (flow) => {
console.log('Saving flow:', flow);
// Save to your backend
};
return (
<div style={{ height: '600px' }}>
<Flowgram
onSave={handleSave}
locale="en"
/>
</div>
);
}Advanced Usage
With Initial Flow
const initialFlow = {
nodes: [
{
id: '1',
type: 'start',
position: { x: 100, y: 100 },
data: { label: 'Start' },
},
{
id: '2',
type: 'task',
position: { x: 300, y: 100 },
data: {
label: 'Process Data',
status: 'in-progress',
progress: 60,
assignee: 'John Doe'
},
},
{
id: '3',
type: 'end',
position: { x: 500, y: 100 },
data: { label: 'End' },
},
],
edges: [
{ id: 'e1-2', source: '1', target: '2' },
{ id: 'e2-3', source: '2', target: '3' },
],
};
<Flowgram
initialFlow={initialFlow}
showMinimap={true}
showControls={true}
onSave={handleSave}
/>Custom Node Types
import { BaseNode } from '@kongfu/flowgram';
const CustomNode = (props) => {
return (
<BaseNode
{...props}
style={{ backgroundColor: '#e0f2fe' }}
>
<div>Custom Content</div>
</BaseNode>
);
};
<Flowgram
nodeTypes={{
custom: CustomNode,
}}
/>Context Menus
const contextMenu = {
node: [
{
id: 'edit',
label: 'Edit Node',
icon: <EditIcon />,
action: (node) => {
console.log('Edit node:', node);
},
},
{
id: 'delete',
label: 'Delete Node',
icon: <DeleteIcon />,
action: (node) => {
// Delete node
},
},
],
pane: [
{
id: 'add-task',
label: 'Add Task',
action: () => {
// Add new task node
},
},
],
};
<Flowgram
contextMenu={contextMenu}
/>Validation Rules
const validation = {
rules: [
{
id: 'no-orphans',
name: 'No Orphan Nodes',
validate: (flow) => {
const errors = [];
flow.nodes.forEach(node => {
const hasConnection = flow.edges.some(
edge => edge.source === node.id || edge.target === node.id
);
if (!hasConnection) {
errors.push({
nodeId: node.id,
message: `Node "${node.data.label}" is not connected`,
type: 'error',
});
}
});
return { valid: errors.length === 0, errors };
},
},
],
validateOnChange: true,
showErrors: true,
};
<Flowgram
validation={validation}
/>Using the Store
import { useFlowgramStore } from '@kongfu/flowgram';
function FlowControls() {
const {
nodes,
edges,
addNode,
deleteNode,
autoLayout,
validate,
exportFlow,
} = useFlowgramStore();
const handleAddTask = () => {
addNode({
id: `task-${Date.now()}`,
type: 'task',
position: { x: 200, y: 200 },
data: { label: 'New Task' },
});
};
const handleAutoLayout = () => {
autoLayout({ direction: 'TB' });
};
const handleExport = () => {
exportFlow({ format: 'json' });
};
return (
<div>
<button onClick={handleAddTask}>Add Task</button>
<button onClick={handleAutoLayout}>Auto Layout</button>
<button onClick={handleExport}>Export</button>
</div>
);
}API Reference
Flowgram Props
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| initialFlow | FlowData | - | Initial flow data |
| mode | 'light' \| 'dark' | 'light' | Color mode |
| readOnly | boolean | false | Disable editing |
| showGrid | boolean | true | Show background grid |
| showMinimap | boolean | true | Show minimap |
| showControls | boolean | true | Show zoom controls |
| snapToGrid | boolean | true | Snap nodes to grid |
| gridSize | number | 20 | Grid size in pixels |
| nodeTypes | Record<string, Component> | - | Custom node types |
| edgeTypes | Record<string, Component> | - | Custom edge types |
| theme | FlowgramTheme | - | Custom theme |
| locale | 'en' \| 'zh-CN' | 'en' | UI language |
| toolbar | ToolbarConfig | - | Toolbar configuration |
| contextMenu | ContextMenuConfig | - | Context menu configuration |
| validation | ValidationConfig | - | Validation configuration |
| onSave | (flow: FlowData) => void | - | Save callback |
| onNodeClick | (event, node) => void | - | Node click handler |
| onEdgeClick | (event, edge) => void | - | Edge click handler |
| onConnect | (connection) => void | - | Connection handler |
| onDelete | (elements) => void | - | Delete handler |
Node Types
Task Node
{
type: 'task',
data: {
label: string;
status?: 'pending' | 'in-progress' | 'completed' | 'failed';
progress?: number; // 0-100
assignee?: string;
}
}Decision Node
{
type: 'decision',
data: {
label: string;
conditions?: Array<{
id: string;
label: string;
expression?: string;
}>;
}
}Parallel Node
{
type: 'parallel',
data: {
label: string;
branches?: number;
joinType?: 'all' | 'any' | 'custom';
}
}Theming
const theme = {
primaryColor: '#3b82f6',
backgroundColor: '#ffffff',
gridColor: '#e5e5e5',
nodeBackgroundColor: '#f9fafb',
nodeTextColor: '#111827',
nodeBorderColor: '#e5e7eb',
edgeColor: '#9ca3af',
selectedColor: '#3b82f6',
errorColor: '#ef4444',
successColor: '#10b981',
};
<Flowgram theme={theme} />Layout Options
const layoutOptions = {
direction: 'TB', // TB, BT, LR, RL
spacing: {
nodeWidth: 180,
nodeHeight: 80,
horizontalSpacing: 100,
verticalSpacing: 100,
},
algorithm: 'dagre', // dagre, elk, custom
};
// Use with store
const { autoLayout } = useFlowgramStore();
autoLayout(layoutOptions);Export Formats
// JSON export
exportFlow({ format: 'json', filename: 'my-flow.json' });
// SVG export (coming soon)
exportFlow({ format: 'svg', filename: 'my-flow.svg' });
// PNG export (coming soon)
exportFlow({
format: 'png',
filename: 'my-flow.png',
quality: 0.9,
background: '#ffffff',
});Browser Support
- Chrome (latest)
- Firefox (latest)
- Safari (latest)
- Edge (latest)
Contributing
Contributions are welcome! Please read our contributing guidelines before submitting PRs.
License
MIT © Kongfu Team
