Best-practice demo for free layout
npx @flowgram.ai/create-app@latest free-layout- Frontend framework: React 18 + TypeScript
- Build tool: Rsbuild (a modern build tool based on Rspack)
- Styling: Less + Styled Components + CSS Variables
- UI library: Semi Design (@douyinfe/semi-ui)
- State management: Flowgramβs in-house editor framework
- Dependency injection: Inversify
- @flowgram.ai/free-layout-editor: Core dependency for the free layout editor
- @flowgram.ai/free-snap-plugin: Auto-alignment and guide-lines plugin
- @flowgram.ai/free-lines-plugin: Connection line rendering plugin
- @flowgram.ai/free-node-panel-plugin: Node add-panel rendering plugin
- @flowgram.ai/minimap-plugin: Minimap plugin
- @flowgram.ai/free-container-plugin: Sub-canvas plugin
- @flowgram.ai/free-group-plugin: Grouping plugin
- @flowgram.ai/form-materials: Form materials
- @flowgram.ai/runtime-interface: Runtime interfaces
- @flowgram.ai/runtime-js: JS runtime module
- @flowgram.ai/panel-manager-plugin: Sidebar panel management
src/
βββ app.tsx # Application entry file
βββ editor.tsx # Main editor component
βββ initial-data.ts # Initial data configuration
βββ assets/ # Static assets
βββ components/ # Component library
β βββ index.ts
β βββ add-node/ # Add-node component
β βββ base-node/ # Base node components
β βββ comment/ # Comment components
β βββ group/ # Group components
β βββ line-add-button/ # Connection add button
β βββ node-menu/ # Node menu
β βββ node-panel/ # Node add panel
β βββ selector-box-popover/ # Selection box popover
β βββ sidebar/ # Sidebar
β βββ testrun/ # Test-run module
β β βββ hooks/ # Test-run hooks
β β βββ node-status-bar/ # Node status bar
β β βββ testrun-button/ # Test-run button
β β βββ testrun-form/ # Test-run form
β β βββ testrun-json-input/ # JSON input component
β β βββ testrun-panel/ # Test-run panel
β βββ tools/ # Utility components
βββ context/ # React Context
β βββ node-render-context.ts # Current rendering node context
β βββ sidebar-context # Sidebar context
βββ form-components/ # Form component library
β βββ form-content/ # Form content
β βββ form-header/ # Form header
β βββ form-inputs/ # Form inputs
β βββ form-item/ # Form item
β βββ feedback.tsx # Validation error rendering
βββ hooks/
β βββ index.ts
β βββ use-editor-props.tsx # Editor props hook
β βββ use-is-sidebar.ts # Sidebar state hook
β βββ use-node-render-context.ts # Node render context hook
β βββ use-port-click.ts # Port click hook
βββ nodes/ # Node definitions
β βββ index.ts
β βββ constants.ts # Node constants
β βββ default-form-meta.ts # Default form metadata
β βββ block-end/ # Block end node
β βββ block-start/ # Block start node
β βββ break/ # Break node
β βββ code/ # Code node
β βββ comment/ # Comment node
β βββ condition/ # Condition node
β βββ continue/ # Continue node
β βββ end/ # End node
β βββ group/ # Group node
β βββ http/ # HTTP node
β βββ llm/ # LLM node
β βββ loop/ # Loop node
β βββ start/ # Start node
β βββ variable/ # Variable node
βββ plugins/ # Plugin system
β βββ index.ts
β βββ context-menu-plugin/ # Right-click context menu plugin
β βββ runtime-plugin/ # Runtime plugin
β β βββ client/ # Client
β β β βββ browser-client/ # Browser client
β β β βββ server-client/ # Server client
β β βββ runtime-service/ # Runtime service
β βββ variable-panel-plugin/ # Variable panel plugin
β βββ components/ # Variable panel components
βββ services/ # Service layer
β βββ index.ts
β βββ custom-service.ts # Custom service
βββ shortcuts/ # Shortcuts system
β βββ index.ts
β βββ constants.ts # Shortcut constants
β βββ shortcuts.ts # Shortcut definitions
β βββ type.ts # Type definitions
β βββ collapse/ # Collapse shortcut
β βββ copy/ # Copy shortcut
β βββ delete/ # Delete shortcut
β βββ expand/ # Expand shortcut
β βββ paste/ # Paste shortcut
β βββ select-all/ # Select-all shortcut
β βββ zoom-in/ # Zoom-in shortcut
β βββ zoom-out/ # Zoom-out shortcut
βββ styles/ # Styles
βββ typings/ # Type definitions
β βββ index.ts
β βββ json-schema.ts # JSON Schema types
β βββ node.ts # Node type definitions
βββ utils/ # Utility functions
βββ index.ts
βββ on-drag-line-end.ts # Handle end of drag line
- base-node: Base rendering components for all nodes
- testrun: Complete test-run module, including status bar, form, and panel
- sidebar: Sidebar components providing tools and property panels
- node-panel: Node add panel with drag-to-add capability
Each node type has its own directory, including:
- Node registration (
index.ts) - Form metadata (
form-meta.ts) - Node-specific components and logic
- runtime-plugin: Supports both browser and server modes
- context-menu-plugin: Right-click context menu
- variable-panel-plugin: Variable management panel
Complete keyboard shortcut support, including:
- Basic actions: copy, paste, delete, select-all
- View actions: zoom-in, zoom-out, collapse, expand
- Each shortcut has its own implementation module
Highly modular plugin system; each feature is an independent plugin:
plugins: () => [
createFreeLinesPlugin({ renderInsideLine: LineAddButton }),
createMinimapPlugin({ /* config */ }),
createFreeSnapPlugin({ /* alignment config */ }),
createFreeNodePanelPlugin({ renderer: NodePanel }),
createContainerNodePlugin({}),
createFreeGroupPlugin({ groupNodeRender: GroupNodeRender }),
createContextMenuPlugin({}),
createRuntimePlugin({ mode: 'browser' }),
createVariablePanelPlugin({})
]Manage different workflow node types via a registry:
export const nodeRegistries: FlowNodeRegistry[] = [
ConditionNodeRegistry, // Condition node
StartNodeRegistry, // Start node
EndNodeRegistry, // End node
LLMNodeRegistry, // LLM node
LoopNodeRegistry, // Loop node
CommentNodeRegistry, // Comment node
HTTPNodeRegistry, // HTTP node
CodeNodeRegistry, // Code node
// ... more node types
];Use Inversify for service DI:
onBind: ({ bind }) => {
bind(CustomService).toSelf().inSingletonScope();
}useEditorProps is the configuration center of the editor:
export function useEditorProps(
initialData: FlowDocumentJSON,
nodeRegistries: FlowNodeRegistry[]
): FreeLayoutProps {
return useMemo<FreeLayoutProps>(() => ({
background: true, // Background grid
readonly: false, // Readonly mode
initialData, // Initial data
nodeRegistries, // Node registries
// Core feature configs
playground: { preventGlobalGesture: true /* Prevent Mac browser swipe gestures */ },
nodeEngine: { enable: true },
variableEngine: { enable: true },
history: { enable: true, enableChangeNode: true },
// Business rules
canAddLine: (ctx, fromPort, toPort) => { /* Connection rules */ },
canDeleteLine: (ctx, line) => { /* Line deletion rules */ },
canDeleteNode: (ctx, node) => { /* Node deletion rules */ },
canDropToNode: (ctx, params) => { /* Drag-and-drop rules */ },
// Plugins
plugins: () => [/* Plugin list */],
// Events
onContentChange: debounce((ctx, event) => { /* Auto save */ }, 1000),
onInit: (ctx) => { /* Initialization */ },
onAllLayersRendered: (ctx) => { /* After render */ }
}), []);
}The app supports multiple workflow node types:
export enum WorkflowNodeType {
Start = 'start', // Start node
End = 'end', // End node
LLM = 'llm', // Large language model node
HTTP = 'http', // HTTP request node
Code = 'code', // Code execution node
Variable = 'variable', // Variable node
Condition = 'condition', // Conditional node
Loop = 'loop', // Loop node
BlockStart = 'block-start', // Sub-canvas start node
BlockEnd = 'block-end', // Sub-canvas end node
Comment = 'comment', // Comment node
Continue = 'continue', // Continue node
Break = 'break', // Break node
}Each node follows a unified registration pattern:
export const StartNodeRegistry: FlowNodeRegistry = {
type: WorkflowNodeType.Start,
meta: {
isStart: true,
deleteDisable: true, // Not deletable
copyDisable: true, // Not copyable
nodePanelVisible: false, // Hidden in node panel
defaultPorts: [{ type: 'output' }],
size: { width: 360, height: 211 }
},
info: {
icon: iconStart,
description: 'The starting node of the workflow, used to set up information needed to launch the workflow.'
},
formMeta, // Form configuration
canAdd() { return false; } // Disallow multiple start nodes
};App features are modularized via the plugin system:
- FreeLinesPlugin - Connection rendering and interaction
- MinimapPlugin - Minimap navigation
- FreeSnapPlugin - Auto-alignment and guide-lines
- FreeNodePanelPlugin - Node add panel
- ContainerNodePlugin - Container nodes (e.g., loop nodes)
- FreeGroupPlugin - Node grouping
- ContextMenuPlugin - Right-click context menu
- RuntimePlugin - Workflow runtime
- VariablePanelPlugin - Variable management panel
Two run modes are supported:
createRuntimePlugin({
mode: 'browser', // Browser mode
// mode: 'server', // Server mode
// serverConfig: {
// domain: 'localhost',
// port: 4000,
// protocol: 'http',
// },
})- Plugin architecture: Each feature is an independent plugin, easy to extend and maintain
- Node registry system: Add new node types without changing core code
- Componentized UI: Highly reusable components with clear responsibilities
- Full TypeScript support: End-to-end type safety from configuration to runtime
- JSON Schema integration: Node data validated by schemas
- Strongly typed plugin interfaces: Clear type constraints for plugin development
- Real-time preview: Run and debug workflows live
- Rich interactions: Dragging, zooming, snapping, shortcuts for a complete editing experience
- Visual feedback: Minimap, status indicators, line animations
- Open plugin system: Third parties can easily develop custom plugins
- Flexible node system: Custom node types and form configurations supported
- Multiple runtimes: Both browser and server modes
- On-demand loading: Components and plugins support lazy loading
- Debounce: Performance optimizations for high-frequency operations like auto-save
Based on @flowgram.ai/free-layout-editor, providing:
- Free-layout canvas system
- Full undo/redo functionality
- Lifecycle management for nodes and connections
- Variable engine and expression system
Using Rsbuild as the build tool:
export default defineConfig({
plugins: [pluginReact(), pluginLess()],
source: {
entry: { index: './src/app.tsx' },
decorators: { version: 'legacy' } // Enable decorators
},
tools: {
rspack: {
ignoreWarnings: [/Critical dependency/] // Ignore specific warnings
}
}
});Built-in multilingual support:
i18n: {
locale: navigator.language,
languages: {
'zh-CN': {
'Never Remind': 'δΈεζη€Ί',
'Hold {{key}} to drag node out': 'ζδ½ {{key}} ε―δ»₯ε°θηΉζεΊ',
},
'en-US': {},
}
}