Flow Editor

@tangramino/flow-editor 提供流程编辑器能力,用于构建可视化的逻辑流程图。基于 @flowgram.ai/free-layout-editor 构建。

安装

npm install @tangramino/flow-editor
# 或
pnpm add @tangramino/flow-editor

FlowEditor

流程编辑器主组件,提供完整的流程图编辑能力。

import { FlowEditor } from '@tangramino/flow-editor';

<FlowEditor
  nodes={nodeDefinitions}
  value={flowData}
  onChange={(data) => setFlowData(data)}
  readonly={false}
>
  <NodePanel />
  <AttributePanel />
</FlowEditor>;

Props

属性类型必填说明
nodesFlowNode[]节点定义数组
valueFlowGraphData流程图数据
onChange(data: FlowGraphData) => void数据变化回调
readonlyboolean是否只读模式,默认 false
childrenReact.ReactNode子组件(如面板)
canAddLineFreeLayoutProps['canAddLine']是否允许添加连线
canDeleteNodeFreeLayoutProps['canDeleteNode']是否允许删除节点
canDeleteLineFreeLayoutProps['canDeleteLine']是否允许删除连线
canResetLineFreeLayoutProps['canResetLine']是否允许重置连线
canDropToNodeFreeLayoutProps['canDropToNode']是否允许拖拽到节点
pluginsPlugin[]流程编辑器插件

FlowNode

流程节点定义接口。

interface FlowNode {
  // 节点类型
  type: string;
  // 节点标题
  title: string;
  // 节点元数据
  nodeMeta?: Partial<WorkflowNodeMeta>;
  // 节点渲染
  renderNode?: () => React.ReactElement;
  // 节点表单渲染
  renderForm?: <T>(props: T) => React.ReactElement;
  // 流程逻辑执行函数
  flowLogic?: <T>(ctx: T) => Promise<unknown> | unknown;
  // 节点默认属性
  defaultProps?: Record<string, unknown>;
}

FlowNode 示例

const conditionNode: FlowNode = {
  type: 'condition',
  title: '条件判断',
  nodeMeta: {
    defaultExpanded: true,
  },
  defaultProps: {
    condition: '',
    trueLabel: '是',
    falseLabel: '否',
  },
  renderNode: () => (
    <div className="condition-node">
      <ConditionIcon />
      <span>条件判断</span>
    </div>
  ),
  renderForm: ({ data, updateData }) => (
    <ConditionForm
      value={data.condition}
      onChange={(v) => updateData({ condition: v })}
    />
  ),
  flowLogic: async (ctx) => {
    const { data, outputs } = ctx;
    const result = evaluateCondition(data.condition);
    return result ? outputs.true : outputs.false;
  },
};

FlowGraphData

流程图数据结构。

interface FlowGraphData {
  nodes: WorkflowNodeJSON[];
  edges: WorkflowEdgeJSON[];
}

useEditorContext

获取流程编辑器上下文。

import { useEditorContext } from '@tangramino/flow-editor';

function AttributePanel() {
  const { activeNode, nodes, setActiveNode } = useEditorContext();

  if (!activeNode) {
    return <div>请选择节点</div>;
  }

  return (
    <div>
      <h3>{activeNode.title}</h3>
      {activeNode.renderForm && activeNode.renderForm()}
    </div>
  );
}

返回值

属性类型说明
activeNodeActiveNode | null当前激活的节点
nodesFlowNode[]所有节点定义
setActiveNode(node: ActiveNode) => void设置激活节点

ActiveNode 类型

interface ActiveNode {
  id: string;
  type: string;
  data: Record<string, unknown>;
  title: string | null;
  renderForm: () => React.ReactNode;
  updateData: (data: Record<string, unknown>) => void;
}

useNodeContext

获取当前节点渲染上下文(在节点组件内部使用)。

import { useNodeContext } from '@tangramino/flow-editor';

function MyNodeComponent() {
  const { id, type, data, form, updateData, selected } = useNodeContext();

  return (
    <div className={selected ? 'selected' : ''}>
      <h4>{data.title}</h4>
      {form?.render()}
    </div>
  );
}

返回值

属性类型说明
idstring节点 ID
typestring节点类型
dataRecord<string, unknown>节点数据
formobject表单对象
updateData(data: Record<string, unknown>) => void更新节点数据
selectedboolean是否被选中

useClientContext

获取流程编辑器客户端上下文。

import { useClientContext } from '@tangramino/flow-editor';

function ToolBar() {
  const ctx = useClientContext();

  const handleZoomIn = () => {
    ctx.tools.zoomIn();
  };

  const handleFitView = () => {
    ctx.tools.fitView();
  };

  return (
    <div className="toolbar">
      <button onClick={handleZoomIn}>放大</button>
      <button onClick={handleFitView}>适应视图</button>
    </div>
  );
}

BaseNode

基础节点渲染组件,FlowEditor 内部使用。自定义节点时可参考其实现。

import { BaseNode } from '@tangramino/flow-editor';

// BaseNode 会自动处理:
// - 节点选中状态
// - 节点数据更新
// - 表单渲染
// - 与 EditorContext 的同步

控制函数属性

canAddLine

控制是否允许添加连线。

<FlowEditor
  canAddLine={(ctx, fromPort, toPort) => {
    // 禁止自连接
    if (fromPort.node === toPort.node) {
      return false;
    }
    // 禁止从输入端口连接
    if (fromPort.type === 'input') {
      return false;
    }
    return true;
  }}
/>

canDeleteNode

控制是否允许删除节点。

<FlowEditor
  canDeleteNode={(ctx, node) => {
    // 禁止删除开始节点
    if (node.type === 'start') {
      return false;
    }
    return true;
  }}
/>

canDeleteLine

控制是否允许删除连线。

<FlowEditor
  canDeleteLine={(ctx, edge) => {
    // 禁止删除主流程连线
    if (edge.data?.isMainFlow) {
      return false;
    }
    return true;
  }}
/>

样式导入

使用 FlowEditor 时需要导入基础样式:

import '@flowgram.ai/free-layout-editor/index.css';

或者在 FlowEditor 组件中已自动导入,无需额外操作。