Skip to content

Commit 4a81db9

Browse files
authored
Merge branch 'master' into xflow-version-7
2 parents e27b0f0 + bf4bf6b commit 4a81db9

File tree

6 files changed

+88
-35
lines changed

6 files changed

+88
-35
lines changed

docs/xflow/api.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ group:
2121
| globalConfig | 全局的面板和节点配置 | {nodePanel:[TNodePanel](#tnodepanel),nodeView:[TNodeView](#tnodeview),edge:[TEdge](#tedge),controls:[TControl](#tcontrol),handle:[THandle](#thandle),deleteKeyCode:[TdeleteKeyCode](#tdeletekeycode) } | |
2222
| logPanel | 日志面板配置 | [TLogPanel](#tlogpanel) | |
2323
| onNodeClick | 节点点击事件 | `NodeMouseHandler` | |
24+
| onEdgeClick | 边点击事件 | `EdgeMouseHandler` | |
2425
| antdVersion | antd 的版本 | `V4 \| V5` | `V5` |
2526
| readOnly | 只读模式 | `boolean` | `false` |
2627
| onTesting | 单点调试方法 | `(node,nodes)=>void` | |
@@ -168,6 +169,7 @@ Handle 配置继承自 React Flow 的 Handle 配置,用于控制节点连接
168169
| parallelExtra | 并行节点属性配置 | [TParallelExtra](#tparallelextra) | |
169170
| showTestingBtn | 是否展示节点的单点调试按钮 | `boolean` | `false` |
170171
| getSettingSchema | 动态获取节点的业务配置信息,返回值同settingSchema。同时设置`settingSchema``getSettingSchema`只生效`getSettingSchema` | `(nodeId: string, nodeType: string, nodeItem: TNodeItem, nodeData: any, form: ReturnType<typeof useForm>) => Promise<Schema>` | |
172+
| renderHandle | 自定义渲染节点的handle,以实现某个节点自定义的出口数量.`sourceHandle`是原handle组件 | `(sourceHandle: SourceHandleType,sourceHandleProps:ComponentProps<SourceHandleType>,nodeProps: {id: string;type: string;data: any;layout: 'LR';isConnectable: boolean;readOnly: boolean;}) => React.JSX.Element`| |
171173

172174

173175

packages/x-flow/src/XFlow.tsx

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -87,12 +87,7 @@ const XFlow: FC<FlowProps> = memo(props => {
8787
const { settingMap, globalConfig, readOnly } = useContext(ConfigContext);
8888
const [openPanel, setOpenPanel] = useState<boolean>(true);
8989
const [openLogPanel, setOpenLogPanel] = useState<boolean>(true);
90-
const {
91-
onNodeClick,
92-
zoomOnScroll = true,
93-
panOnScroll = false,
94-
preventScrolling = true,
95-
} = props;
90+
const { onNodeClick, onEdgeClick, zoomOnScroll = true, panOnScroll = false, preventScrolling = true } = props;
9691
const nodeEditorRef = useRef(null);
9792

9893
useEffect(() => {
@@ -361,10 +356,14 @@ const XFlow: FC<FlowProps> = memo(props => {
361356
});
362357
}}
363358
onEdgeMouseEnter={(_, edge: any) => {
364-
getUpdateEdgeConfig(edge, '#2970ff');
359+
if(!edge.style.stroke || edge.style.stroke === '#c9c9c9'){
360+
getUpdateEdgeConfig(edge, '#2970ff');
361+
}
365362
}}
366363
onEdgeMouseLeave={(_, edge) => {
367-
getUpdateEdgeConfig(edge, '#c9c9c9');
364+
if(['#2970ff',"#c9c9c9"].includes(edge.style.stroke)){
365+
getUpdateEdgeConfig(edge, '#c9c9c9');
366+
}
368367
}}
369368
onNodesDelete={() => {
370369
// setActiveNode(null);
@@ -373,6 +372,9 @@ const XFlow: FC<FlowProps> = memo(props => {
373372
onNodeClick && onNodeClick(event, node);
374373
}}
375374
deleteKeyCode={globalConfig?.deleteKeyCode}
375+
onEdgeClick={(event,edge)=>{
376+
onEdgeClick && onEdgeClick(event,edge)
377+
}}
376378
>
377379
<CandidateNode />
378380
<Operator addNode={handleAddNode} xflowRef={workflowContainerRef} />

packages/x-flow/src/components/CustomNode/index.less

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
border: 2px solid var(--nodeBorderColor,#fff);
33
border-radius: 14px;
44
position: relative;
5+
background: #ffffff;
56
.react-flow__edge-path,
67
.react-flow__connection-path {
78
stroke: #d0d5dc;
@@ -74,12 +75,12 @@
7475
transition: all 0.3s;
7576
}
7677

77-
.xflow-node-switch-title{
78-
position: absolute;
78+
.xflow-node-switch-title {
79+
position: absolute;
7980
left: -45px;
8081
top: 6px;
8182
font-weight: 600;
82-
text-align: right;
83+
text-align: right;
8384
width: 35px;
8485
}
8586
}
@@ -106,6 +107,6 @@
106107

107108

108109
.xflow-node-container-note{
109-
border: none;
110-
padding: 2px 6px 6px 6px;
110+
border: none;
111+
padding: 2px 6px 6px 6px;
111112
}

packages/x-flow/src/components/CustomNode/index.tsx

Lines changed: 44 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { Dropdown, Menu, message } from 'antd';
44
import { ItemType } from 'antd/es/menu/interface';
55
import classNames from 'classnames';
66
import { isFunction } from 'lodash';
7-
import React, { memo, useCallback, useContext, useMemo, useState } from 'react';
7+
import React, { Fragment, memo, useCallback, useContext, useMemo, useState } from 'react';
88
import { shallow } from 'zustand/shallow';
99
import { useStore } from '../../hooks/useStore';
1010
import { ConfigContext } from '../../models/context';
@@ -35,6 +35,7 @@ export default memo((props: any) => {
3535
const disabledDelete = settingMap[type]?.disabledDelete ?? false;
3636
const switchExtra = settingMap[type]?.switchExtra || {};
3737
const handleProps = globalConfig?.handle || {}
38+
const renderHandle = settingMap[type]?.renderHandle || void(0)
3839
// const isConnectableStart = globalConfig?.handle?.isConnectableStart ?? true;
3940
// const isConnectableEnd = globalConfig?.handle?.isConnectableEnd ?? true;
4041

@@ -324,20 +325,47 @@ export default memo((props: any) => {
324325
isHovered={isHovered}
325326
handleAddNode={handleAddNode}
326327
/>
327-
{!settingMap?.[type]?.sourceHandleHidden && !isSwitchNode && (
328-
<>
329-
<SourceHandle
330-
position={sourcePosition}
331-
isConnectable={connectable}
332-
selected={selected}
333-
isHovered={isHovered}
334-
handleAddNode={handleAddNode}
335-
isConnected={isSourceHandleConnected}
336-
// isConnectableStart={isConnectableStart}
337-
// isConnectableEnd={isConnectableEnd}
338-
/>
339-
</>
340-
)}
328+
{typeof renderHandle === 'function' ?
329+
<div onClick={()=>{
330+
onClick(data)
331+
}}>
332+
{renderHandle(
333+
SourceHandle,
334+
{
335+
position:sourcePosition,
336+
isConnectable:connectable,
337+
selected:selected,
338+
isHovered:isHovered,
339+
handleAddNode:handleAddNode
340+
},
341+
{
342+
id,
343+
type,
344+
data,
345+
layout,
346+
isConnectable,
347+
readOnly
348+
}
349+
)}
350+
</div>
351+
:
352+
<Fragment>
353+
{!settingMap?.[type]?.sourceHandleHidden && !isSwitchNode && (
354+
<>
355+
<SourceHandle
356+
position={sourcePosition}
357+
isConnectable={connectable}
358+
selected={selected}
359+
isHovered={isHovered}
360+
handleAddNode={handleAddNode}
361+
isConnected={isSourceHandleConnected}
362+
// isConnectableStart={isConnectableStart}
363+
// isConnectableEnd={isConnectableEnd}
364+
/>
365+
</>
366+
)}
367+
</Fragment>
368+
}
341369
</div>
342370
);
343-
});
371+
});

packages/x-flow/src/components/CustomNode/sourceHandle.tsx

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,14 @@ import { PlusOutlined } from '@ant-design/icons';
22
import { Handle } from '@xyflow/react';
33
import { Tooltip } from 'antd';
44
import classNames from 'classnames';
5-
import React, { memo, useContext, useMemo, useRef, useState } from 'react';
6-
import { ConfigContext } from '../../models/context';
5+
import React, { ComponentProps, memo, useContext, useMemo, useRef, useState } from 'react';
76
import NodeSelectPopover from '../NodesPopover';
7+
import { ConfigContext } from '../../models/context';
88
import './index.less';
99

10-
export default memo((props: any) => {
10+
export type HandleProps = ComponentProps<typeof Handle>
11+
12+
export default memo((props:Partial<HandleProps> & Record<string,any> ) => {
1113
const {
1214
position,
1315
isConnectable,

packages/x-flow/src/types.ts

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,15 @@
1-
import { NodeMouseHandler,Handle } from '@xyflow/react';
1+
import { NodeMouseHandler,Handle, Edge } from '@xyflow/react';
22
import { TabPaneProps } from 'antd';
33
import { Schema,useForm } from 'form-render';
4+
import { ReactFlow } from '@xyflow/react';
45
import React, { ReactNode ,ComponentProps} from 'react';
56

6-
type HandleProps = ComponentProps<typeof Handle>
7+
import SourceHandle, {
8+
HandleProps,
9+
} from './components/CustomNode/sourceHandle';
710

11+
type SourceHandleType = typeof SourceHandle;
12+
type ReactFlowProps = ComponentProps<typeof ReactFlow>
813
export interface TNodeItem {
914
title: string; // 节点 title
1015
type: string; // 节点类型 _group 比较te
@@ -25,6 +30,18 @@ export interface TNodeItem {
2530
hideDesc?: boolean; // 配置面板描述
2631
};
2732
nodeWidget?:string// 自定义节点组件
33+
renderHandle?: (
34+
sourceHandle: SourceHandleType,
35+
sourceHandleProps: ComponentProps<SourceHandleType>,
36+
nodeProps: {
37+
id: string;
38+
type: string;
39+
data: any;
40+
layout: 'LR' | 'TB';
41+
isConnectable: boolean;
42+
readOnly: boolean;
43+
}
44+
) => React.JSX.Element;
2845
getSettingSchema?: (nodeId: string, nodeType: string, nodeItem:TNodeItem,nodeData:any,form: ReturnType<typeof useForm>) => Promise<Schema>;
2946
switchExtra: { // 条件节点额外属性配置
3047
hideElse: boolean;
@@ -161,7 +178,8 @@ export interface FlowProps {
161178
};
162179
logPanel?: TLogPanel; // 日志面板配置
163180
readOnly?:boolean//只读模式
164-
onNodeClick?: NodeMouseHandler;
181+
onNodeClick?: ReactFlowProps['onNodeClick']
182+
onEdgeClick?:ReactFlowProps['onEdgeClick']
165183
onMenuItemClick?: (itemInfo: ItemInfo, defaultAction: () => void) => void;
166184
clickAddNode?: (type: string, nodeItem: TNodeItem, addNode: (initData?: Record<string, any>) => void) => void;
167185
zoomOnScroll?: boolean;

0 commit comments

Comments
 (0)