固定布局最佳实践 demo
npx @flowgram.ai/create-app@latest fixed-layout
src/
├── app.tsx # 应用入口组件
├── editor.tsx # 主编辑器组件
├── index.ts # 模块导出入口
├── initial-data.ts # 初始化数据配置
├── type.d.ts # 全局类型声明
│
├── assets/ # 静态资源
│ ├── icon-mouse.tsx # 鼠标图标组件
│ └── icon-pad.tsx # 触控板图标组件
│
├── components/ # 通用组件库
│ ├── index.ts # 组件导出入口
│ ├── node-list.tsx # 节点列表组件
│ │
│ ├── agent-adder/ # Agent 添加器组件
│ │ └── index.tsx
│ ├── agent-label/ # Agent 标签组件
│ │ └── index.tsx
│ ├── base-node/ # 基础节点组件
│ │ ├── index.tsx
│ │ └── styles.tsx
│ ├── branch-adder/ # 分支添加器组件
│ │ ├── index.tsx
│ │ └── styles.tsx
│ ├── drag-node/ # 拖拽节点组件
│ │ ├── index.tsx
│ │ └── styles.tsx
│ ├── node-adder/ # 节点添加器组件
│ │ ├── index.tsx
│ │ ├── styles.tsx
│ │ └── utils.ts
│ ├── selector-box-popover/ # 选择框弹出层组件
│ │ └── index.tsx
│ ├── sidebar/ # 侧边栏组件
│ │ ├── index.tsx
│ │ ├── sidebar-node-renderer.tsx
│ │ ├── sidebar-provider.tsx
│ │ └── sidebar-renderer.tsx
│ └── tools/ # 工具栏组件群
│ ├── index.tsx
│ ├── styles.tsx
│ ├── fit-view.tsx # 适应视图工具
│ ├── minimap-switch.tsx # 缩略图开关
│ ├── minimap.tsx # 缩略图组件
│ ├── readonly.tsx # 只读模式切换
│ ├── run.tsx # 运行工具
│ ├── save.tsx # 保存工具
│ ├── switch-vertical.tsx # 垂直布局切换
│ └── zoom-select.tsx # 缩放选择器
│
├── context/ # React Context 状态管理
│ ├── index.ts # Context 导出入口
│ ├── node-render-context.ts # 节点渲染上下文
│ └── sidebar-context.ts # 侧边栏上下文
│
├── form-components/ # 表单组件库
│ ├── index.ts # 表单组件导出入口
│ ├── feedback.tsx # 反馈组件
│ │
│ ├── form-content/ # 表单内容组件
│ │ ├── index.tsx
│ │ └── styles.tsx
│ ├── form-header/ # 表单头部组件
│ │ ├── index.tsx
│ │ ├── styles.tsx
│ │ ├── title-input.tsx
│ │ └── utils.tsx
│ ├── form-inputs/ # 表单输入组件
│ │ ├── index.tsx
│ │ └── styles.tsx
│ ├── form-item/ # 表单项组件
│ │ ├── index.css
│ │ └── index.tsx
│ ├── form-outputs/ # 表单输出组件
│ │ ├── index.tsx
│ │ └── styles.tsx
│ └── properties-edit/ # 属性编辑组件
│ ├── index.tsx
│ ├── property-edit.tsx
│ └── styles.tsx
│
├── hooks/ # 自定义 React Hooks
│ ├── index.ts # Hooks 导出入口
│ ├── use-editor-props.ts # 编辑器属性 Hook
│ ├── use-is-sidebar.ts # 侧边栏状态 Hook
│ └── use-node-render-context.ts # 节点渲染上下文 Hook
│
├── nodes/ # 流程节点定义
│ ├── index.ts # 节点注册表
│ ├── default-form-meta.tsx # 默认表单元数据
│ │
│ ├── agent/ # Agent 节点类型
│ │ ├── index.ts
│ │ ├── agent.ts
│ │ ├── agent-llm.ts
│ │ ├── agent-memory.ts
│ │ ├── agent-tools.ts
│ │ ├── memory.ts
│ │ └── tool.ts
│ ├── break-loop/ # 跳出循环节点
│ │ ├── index.ts
│ │ └── form-meta.tsx
│ ├── case/ # Case 分支节点
│ │ ├── index.ts
│ │ └── form-meta.tsx
│ ├── case-default/ # 默认 Case 节点
│ │ ├── index.ts
│ │ └── form-meta.tsx
│ ├── catch-block/ # 异常捕获块节点
│ │ ├── index.ts
│ │ └── form-meta.tsx
│ ├── end/ # 结束节点
│ │ ├── index.ts
│ │ └── form-meta.tsx
│ ├── if/ # 条件判断节点
│ │ └── index.ts
│ ├── if-block/ # 条件块节点
│ │ ├── index.ts
│ │ └── form-meta.tsx
│ ├── llm/ # LLM 节点
│ │ └── index.ts
│ ├── loop/ # 循环节点
│ │ ├── index.ts
│ │ └── form-meta.tsx
│ ├── start/ # 开始节点
│ │ ├── index.ts
│ │ └── form-meta.tsx
│ ├── switch/ # Switch 分支节点
│ │ └── index.ts
│ └── trycatch/ # Try-Catch 节点
│ ├── index.ts
│ └── form-meta.tsx
│
├── plugins/ # 插件系统
│ ├── index.ts # 插件导出入口
│ │
│ ├── clipboard-plugin/ # 剪贴板插件
│ │ └── create-clipboard-plugin.ts
│ ├── group-plugin/ # 分组插件
│ │ ├── index.ts
│ │ ├── group-box-header.tsx
│ │ ├── group-node.tsx
│ │ ├── group-note.tsx
│ │ ├── group-tools.tsx
│ │ ├── icons/
│ │ │ └── index.tsx
│ │ └── multilang-textarea-editor/
│ │ ├── index.css
│ │ ├── index.tsx
│ │ └── base-textarea.tsx
│ └── variable-panel-plugin/ # 变量面板插件
│ ├── index.ts
│ ├── variable-panel-layer.tsx
│ ├── variable-panel-plugin.ts
│ └── components/
│ ├── full-variable-list.tsx
│ ├── global-variable-editor.tsx
│ └── variable-panel.tsx
│
├── services/ # 服务层
│ ├── index.ts
│ └── custom-service.ts # 自定义服务
│
├── shortcuts/ # 快捷键系统
│ ├── index.ts
│ ├── constants.ts # 快捷键常量
│ └── utils.ts # 快捷键工具函数
│
└── typings/ # 类型定义
├── index.ts # 类型导出入口
├── json-schema.ts # JSON Schema 类型
└── node.ts # 节点类型定义
该项目采用了分层架构和模块化设计相结合的架构模式:
表现层 (Presentation Layer)
业务逻辑层 (Business Logic Layer)
数据层 (Data Layer)
// 主编辑器组件使用多层 Provider 嵌套
<FixedLayoutEditorProvider {...editorProps}>
<SidebarProvider>
<EditorRenderer />
<DemoTools />
<SidebarRenderer />
</SidebarProvider>
</FixedLayoutEditorProvider>
应用场景:
FixedLayoutEditorProvider: 提供编辑器核心功能和状态SidebarProvider: 管理侧边栏的显示状态和选中节点export const FlowNodeRegistries: FlowNodeRegistry[] = [
StartNodeRegistry,
EndNodeRegistry,
SwitchNodeRegistry,
LLMNodeRegistry,
// ... 更多节点类型
];
设计优势:
plugins: () => [
createMinimapPlugin({...}),
createGroupPlugin({...}),
createClipboardPlugin(),
createVariablePanelPlugin({}),
]
插件系统特点:
在节点创建和配置中广泛使用:
getNodeDefaultRegistry(type) {
return {
type,
meta: {
defaultExpanded: true,
},
};
}
通过历史记录系统实现:
history: {
enable: true,
enableChangeNode: true,
onApply: debounce((ctx, opt) => {
console.log('auto save: ', ctx.document.toJSON());
}, 100),
}
在材料系统中体现:
materials: {
components: {
...defaultFixedSemiMaterials,
[FlowRendererKey.ADDER]: NodeAdder,
[FlowRendererKey.BRANCH_ADDER]: BranchAdder,
// 可根据 key 替换不同的渲染策略
}
}
项目采用了多个专用的 Context 来管理不同领域的状态:
SidebarContext: 管理侧边栏状态
export const SidebarContext = React.createContext<{
visible: boolean;
nodeId?: string;
setNodeId: (node: string | undefined) => void;
}>({ visible: false, setNodeId: () => {} });
NodeRenderContext: 管理节点渲染相关状态
IsSidebarContext: 简单的布尔状态管理
useEditorProps: 集中管理编辑器的所有配置属性useIsSidebar: 判断当前是否在侧边栏环境中useNodeRenderContext: 获取节点渲染上下文基础组件层
BaseNode: 所有节点的基础渲染组件DragNode: 拖拽状态下的节点组件功能组件层
NodeAdder, BranchAdder, AgentAdder容器组件层
Sidebar: 侧边栏容器及其子组件Tools: 工具栏容器项目定义了完整的初始流程数据,包含多种节点类型的示例:
fromNodeJSON(node, json) {
return json; // 数据导入时的转换逻辑
},
toNodeJSON(node, json) {
return json; // 数据导出时的转换逻辑
}