
Product
Introducing Webhook Events for Alert Changes
Add real-time Socket webhook events to your workflows to automatically receive software supply chain alert changes in real time.
@flowgram.ai/demo-free-layout
Advanced tools
Best-practice demo for free layout
npx @flowgram.ai/create-app@latest free-layout
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
/components - Component Library/nodes - Node SystemEach node type has its own directory, including:
index.ts)form-meta.ts)/plugins - Plugin System/shortcuts - Shortcuts SystemComplete keyboard shortcut support, including:
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:
Two run modes are supported:
createRuntimePlugin({
mode: 'browser', // Browser mode
// mode: 'server', // Server mode
// serverConfig: {
// domain: 'localhost',
// port: 4000,
// protocol: 'http',
// },
})
Based on @flowgram.ai/free-layout-editor, providing:
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': {},
}
}
FAQs
自由布局最佳实践 demo
We found that @flowgram.ai/demo-free-layout demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 3 open source maintainers collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Product
Add real-time Socket webhook events to your workflows to automatically receive software supply chain alert changes in real time.

Security News
ENISA has become a CVE Program Root, giving the EU a central authority for coordinating vulnerability reporting, disclosure, and cross-border response.

Product
Socket now scans OpenVSX extensions, giving teams early detection of risky behaviors, hidden capabilities, and supply chain threats in developer tools.