fix(fixed-layout): multi-outputs/multi-inputs collapsed and move branches (#249)

* feat(demo): demo-fixed-layout-simple add tryCatch node

* feat(demo): use-editor-props add fromNodeJSON/toNodeJSON config

* fix(demo): demo-fixed-layout-simple readonly refresh

* fix(fixed-layout): multi-outputs collapsed and move branches

* chore: update codeowners

* fix(fixed-layout): multi-inputs branch adder

* test(fixed-layout-core): test snapshots update

* test(fixed-layout-editor): move block to other dynamicSplit
This commit is contained in:
xiamidaxia 2025-05-21 18:06:41 +08:00 committed by GitHub
parent 245bee3389
commit 92b3adc5d0
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
23 changed files with 410 additions and 100 deletions

4
.github/CODEOWNERS vendored
View File

@ -1,9 +1,9 @@
# 文件路径与代码负责人分配
# 对整个仓库设置代码负责人
* @xiamidaxia @luics @dragooncjw
* @xiamidaxia @luics @dragooncjw @YuanHeDx @sanmaopep @louisyoungx
# 对特定目录设置代码负责人
/apps/docs/ @xiamidaxia @dragooncjw @YuanHeDx @sanmaopep
/apps/docs/ @xiamidaxia @dragooncjw @YuanHeDx @sanmaopep @louisyoungx
/apps/demo-node-form/ @xiamidaxia @dragooncjw @YuanHeDx
/packages/node-engine/ @xiamidaxia @dragooncjw @YuanHeDx
/packages/variable-engine/ @xiamidaxia @dragooncjw @sanmaopep

View File

@ -38,10 +38,12 @@ export const BaseNode = ({ node }: { node: FlowNodeEntity }) => {
...(nodeRender.isBlockOrderIcon || nodeRender.isBlockIcon ? { width: 260 } : {}),
}}
>
<IconDeleteStroked
style={{ position: 'absolute', right: 4, top: 4 }}
onClick={() => ctx.operation.deleteNode(nodeRender.node)}
/>
{!nodeRender.readonly && (
<IconDeleteStroked
style={{ position: 'absolute', right: 4, top: 4 }}
onClick={() => ctx.operation.deleteNode(nodeRender.node)}
/>
)}
{form?.render()}
</div>
);

View File

@ -25,6 +25,15 @@ export function BranchAdder(props: PropsType) {
content: '',
},
});
} else if (node.flowNodeType === 'multiInputs') {
block = operation.addBlock(node, {
id: `input_${nanoid(5)}`,
type: 'input',
data: {
title: 'New Input',
content: '',
},
});
} else {
block = operation.addBlock(node, {
id: `branch_${nanoid(5)}`,
@ -43,6 +52,7 @@ export function BranchAdder(props: PropsType) {
});
}, 10);
}
if (playground.config.readonlyOrDisabled) return null;
const className = [

View File

@ -13,9 +13,10 @@ export function FlowSelect() {
const targetDemoJSON = FLOW_LIST[demoKey];
if (targetDemoJSON) {
clientContext.history.stop(); // Stop redo/undo
clientContext.document.fromJSON(targetDemoJSON);
console.log(clientContext.document.toString());
clientContext.history.start();
clientContext.history.clear(); // Clear redo/undo
clientContext.document.fromJSON(targetDemoJSON); // Reload Data
console.log(clientContext.document.toString()); // Print the document tree
clientContext.history.start(); // Restart redo/undo
clientContext.document.setLayout(
targetDemoJSON.defaultLayout || FlowLayoutDefault.VERTICAL_FIXED_LAYOUT
);
@ -26,7 +27,7 @@ export function FlowSelect() {
}
// Fit View
setTimeout(() => {
clientContext.playground.config.fitView(clientContext.document.root.bounds);
clientContext.playground.config.fitView(clientContext.document.root.bounds, true, 40);
}, 20);
}
}, [demoKey]);

View File

@ -1,12 +1,13 @@
import { useEffect, useState, useCallback } from 'react';
import { usePlaygroundTools, useClientContext } from '@flowgram.ai/fixed-layout-editor';
import { usePlaygroundTools, useClientContext, useRefresh } from '@flowgram.ai/fixed-layout-editor';
import { IconButton, Space } from '@douyinfe/semi-ui';
import { IconUnlock, IconLock } from '@douyinfe/semi-icons';
export function Tools() {
const { history, playground } = useClientContext();
const tools = usePlaygroundTools();
const refresh = useRefresh();
const [canUndo, setCanUndo] = useState(false);
const [canRedo, setCanRedo] = useState(false);
const toggleReadonly = useCallback(() => {
@ -21,6 +22,11 @@ export function Tools() {
return () => disposable.dispose();
}, [history]);
useEffect(() => {
const disposable = playground.config.onReadonlyOrDisabledChange(() => refresh());
return () => disposable.dispose();
}, [playground]);
return (
<Space
style={{ position: 'absolute', zIndex: 10, bottom: 16, left: 16, display: 'flex', gap: 8 }}

View File

@ -1,9 +1,11 @@
import { FlowDocumentJSON, FlowLayoutDefault } from '@flowgram.ai/fixed-layout-editor';
import { tryCatch } from './trycatch';
import { mindmap } from './mindmap';
import { condition } from './condition';
export const FLOW_LIST: Record<string, FlowDocumentJSON & { defaultLayout?: FlowLayoutDefault }> = {
condition,
mindmap: { ...mindmap, defaultLayout: FlowLayoutDefault.HORIZONTAL_FIXED_LAYOUT },
tryCatch,
};

View File

@ -20,6 +20,13 @@ export const mindmap: FlowDocumentJSON = {
title: 'input_1',
},
},
{
id: 'input_3',
type: 'input',
data: {
title: 'input_3',
},
},
// {
// id: 'multiInputs_2',
// type: 'multiInputs',

View File

@ -0,0 +1,56 @@
import { FlowDocumentJSON } from '@flowgram.ai/fixed-layout-editor';
export const tryCatch: FlowDocumentJSON = {
nodes: [
// 开始节点
{
id: 'start_0',
type: 'start',
data: {
title: 'Start',
content: 'start content',
},
blocks: [],
},
// 分支节点
{
id: 'tryCatch_0',
type: 'tryCatch',
data: {
title: 'TryCatch',
},
blocks: [
{
id: 'tryBlock_0',
type: 'tryBlock',
blocks: [],
},
{
id: 'catchBlock_0',
type: 'catchBlock',
data: {
title: 'Catch Block 1',
},
blocks: [],
},
{
id: 'catchBlock_1',
type: 'catchBlock',
data: {
title: 'Catch Block 2',
},
blocks: [],
},
],
},
// 结束节点
{
id: 'end_0',
type: 'end',
data: {
title: 'End',
content: 'end content',
},
},
],
};

View File

@ -6,12 +6,16 @@ import './index.css';
import { nodeRegistries } from './node-registries';
import { initialData } from './initial-data';
import { useEditorProps } from './hooks/use-editor-props';
import { FLOW_LIST } from './data';
import { Tools } from './components/tools';
import { Minimap } from './components/minimap';
import { FlowSelect } from './components/flow-select';
export const Editor = () => {
const editorProps = useEditorProps(initialData, nodeRegistries);
export const Editor = (props: { demoKey?: string }) => {
const editorProps = useEditorProps(
props.demoKey ? FLOW_LIST[props.demoKey] : initialData,
nodeRegistries
);
return (
<FixedLayoutEditorProvider {...editorProps}>
<div className="demo-fixed-container">

View File

@ -106,6 +106,7 @@ export function useEditorProps(
},
},
/**
* Playground init
*
*/
onInit: (ctx) => {
@ -117,11 +118,30 @@ export function useEditorProps(
console.log('---- Playground Init ----');
},
/**
* Playground dispose
*
*/
onDispose: () => {
console.log('---- Playground Dispose ----');
},
/**
* , ctx.document.fromJSON
* Node data transformation, called by ctx.document.fromJSON
* @param node
* @param json
*/
fromNodeJSON(node, json) {
return json;
},
/**
* , ctx.document.toJSON
* Node data transformation, called by ctx.document.toJSON
* @param node
* @param json
*/
toNodeJSON(node, json) {
return json;
},
plugins: () => [
/**
* Minimap plugin

View File

@ -1,9 +1,5 @@
import { nanoid } from 'nanoid';
import {
FlowNodeRegistry,
FlowNodeEntity,
FlowNodeBaseType,
} from '@flowgram.ai/fixed-layout-editor';
import { FlowNodeRegistry } from '@flowgram.ai/fixed-layout-editor';
/**
*
@ -77,35 +73,4 @@ export const nodeRegistries: FlowNodeRegistry[] = [
};
},
},
{
type: 'multiStart2',
extend: 'dynamicSplit',
meta: {
isStart: true,
},
onCreate(node, json) {
const doc = node.document;
const addedNodes: FlowNodeEntity[] = [];
const blocks = json.blocks || [];
if (blocks.length > 0) {
// 水平布局
const inlineBlocksNode = doc.addNode({
id: `$inlineBlocks$${node.id}`,
type: FlowNodeBaseType.INLINE_BLOCKS,
originParent: node,
parent: node,
});
addedNodes.push(inlineBlocksNode);
blocks.forEach((blockData) => {
doc.addBlock(node, blockData, addedNodes);
});
}
return addedNodes;
},
},
{
type: 'tree',
extend: 'simpleSplit',
},
];

View File

@ -63,6 +63,24 @@ export function useEditorProps(
},
};
},
/**
* , ctx.document.fromJSON
* Node data transformation, called by ctx.document.fromJSON
* @param node
* @param json
*/
fromNodeJSON(node, json) {
return json;
},
/**
* , ctx.document.toJSON
* Node data transformation, called by ctx.document.toJSON
* @param node
* @param json
*/
toNodeJSON(node, json) {
return json;
},
/**
* Set default layout
*/

View File

@ -34,6 +34,24 @@ export const useEditorProps = () =>
*
*/
nodeRegistries,
/**
* , ctx.document.fromJSON
* Node data transformation, called by ctx.document.fromJSON
* @param node
* @param json
*/
fromNodeJSON(node, json) {
return json;
},
/**
* , ctx.document.toJSON
* Node data transformation, called by ctx.document.toJSON
* @param node
* @param json
*/
toNodeJSON(node, json) {
return json;
},
/**
* Get the default node registry, which will be merged with the 'nodeRegistries'
* nodeRegistries

View File

@ -57,6 +57,24 @@ export function useEditorProps(
formMeta: defaultFormMeta,
};
},
/**
* , ctx.document.fromJSON
* Node data transformation, called by ctx.document.fromJSON
* @param node
* @param json
*/
fromNodeJSON(node, json) {
return json;
},
/**
* , ctx.document.toJSON
* Node data transformation, called by ctx.document.toJSON
* @param node
* @param json
*/
toNodeJSON(node, json) {
return json;
},
lineColor: {
hidden: 'transparent',
default: '#4d53e8',

View File

@ -344,20 +344,17 @@ export class FlowDocument<T = FlowDocumentJSON> implements Disposable {
parent: node,
});
addedNodes.push(blockIconNode);
// inlineblocks 为空则不创建
if (blocks.length > 0) {
// 水平布局
const inlineBlocksNode = this.addNode({
id: `$inlineBlocks$${node.id}`,
type: FlowNodeBaseType.INLINE_BLOCKS,
originParent: node,
parent: node,
});
addedNodes.push(inlineBlocksNode);
blocks.forEach((blockData) => {
this.addBlock(node, blockData, addedNodes);
});
}
// 水平布局
const inlineBlocksNode = this.addNode({
id: `$inlineBlocks$${node.id}`,
type: FlowNodeBaseType.INLINE_BLOCKS,
originParent: node,
parent: node,
});
addedNodes.push(inlineBlocksNode);
blocks.forEach((blockData) => {
this.addBlock(node, blockData, addedNodes);
});
return addedNodes;
}

View File

@ -29,6 +29,7 @@ export interface FlowTransitionLine {
arrow?: boolean; // 是否有箭头
renderKey?: string; // 只有自定义线条需要
isHorizontal?: boolean; // 是否为水平布局
isDraggingLine?: boolean; // 是否是拖拽线条
activated?: boolean; // 是否激活态
side?: LABEL_SIDE_TYPE; // 区分是否分支前缀线条
style?: React.CSSProperties;

View File

@ -118,6 +118,7 @@ exports[`flow-activities > extend block addChild 1`] = `
|-------- $blockOrderIcon$test-extend-block
|-- empty-split
|---- $blockIcon$empty-split
|---- $inlineBlocks$empty-split
|-- end_0"
`;

View File

@ -38,8 +38,13 @@ export const BlockRegistry: FlowNodeRegistry = {
// 当有其余分支的时候,绘制一条两个分支之间的线条
if (hasBranchDraggingAdder) {
if (isVertical) {
const currentOffsetRightX = currentTransform.firstChild?.bounds?.right || 0;
const nextOffsetLeftX = currentTransform.next?.firstChild?.bounds?.left || 0;
const currentOffsetRightX = currentTransform.firstChild
? currentTransform.firstChild.bounds.right
: currentTransform.bounds.right;
const nextOffsetLeftX =
(currentTransform.next?.firstChild
? currentTransform.next?.firstChild.bounds?.left
: currentTransform.next?.bounds?.left) || 0;
const currentInputPointY = currentTransform.inputPoint.y;
if (currentTransform?.next) {
lines.push({
@ -53,8 +58,13 @@ export const BlockRegistry: FlowNodeRegistry = {
});
}
} else {
const currentOffsetRightY = currentTransform.firstChild?.bounds?.bottom || 0;
const nextOffsetLeftY = currentTransform.next?.firstChild?.bounds?.top || 0;
const currentOffsetBottomX = currentTransform.firstChild
? currentTransform.firstChild.bounds.bottom
: currentTransform.bounds.bottom;
const nextOffsetTopX =
(currentTransform.next?.firstChild
? currentTransform.next?.firstChild.bounds?.top
: currentTransform.next?.bounds?.top) || 0;
const currentInputPointX = currentTransform.inputPoint.x;
if (currentTransform?.next) {
lines.push({
@ -62,7 +72,7 @@ export const BlockRegistry: FlowNodeRegistry = {
from: currentTransform.parent!.inputPoint,
to: {
x: currentInputPointX,
y: (currentOffsetRightY + nextOffsetLeftY) / 2,
y: (currentOffsetBottomX + nextOffsetTopX) / 2,
},
side: LABEL_SIDE_TYPE.NORMAL_BRANCH,
});
@ -112,8 +122,13 @@ export const BlockRegistry: FlowNodeRegistry = {
// 获取两个分支节点中间点作为拖拽标签插入位置
if (hasBranchDraggingAdder) {
if (isVertical) {
const currentOffsetRightX = currentTransform.firstChild?.bounds?.right || 0;
const nextOffsetLeftX = currentTransform.next?.firstChild?.bounds?.left || 0;
const currentOffsetRightX = currentTransform.firstChild
? currentTransform.firstChild.bounds.right
: currentTransform.bounds.right;
const nextOffsetLeftX =
(currentTransform.next?.firstChild
? currentTransform.next.firstChild.bounds?.left
: currentTransform.next?.bounds?.left) || 0;
const currentInputPointY = currentTransform.inputPoint.y;
if (currentTransform?.next) {
draggingLabel.push({
@ -129,17 +144,22 @@ export const BlockRegistry: FlowNodeRegistry = {
});
}
} else {
const currentOffsetRightY = currentTransform.firstChild?.bounds?.bottom || 0;
const nextOffsetLeftY = currentTransform.next?.firstChild?.bounds?.top || 0;
const currentOffsetBottomX = currentTransform.firstChild
? currentTransform.firstChild.bounds.bottom
: currentTransform.bounds.bottom;
const nextOffsetTopX =
(currentTransform.next?.firstChild
? currentTransform.next.firstChild.bounds?.top
: currentTransform.next?.bounds?.top) || 0;
const currentInputPointX = currentTransform.inputPoint.x;
if (currentTransform?.next) {
draggingLabel.push({
offset: {
x: currentInputPointX,
y: (currentOffsetRightY + nextOffsetLeftY) / 2,
y: (currentOffsetBottomX + nextOffsetTopX) / 2,
},
type: FlowTransitionLabelEnum.BRANCH_DRAGGING_LABEL,
width: nextOffsetLeftY - currentOffsetRightY,
width: nextOffsetTopX - currentOffsetBottomX,
props: {
side: LABEL_SIDE_TYPE.NORMAL_BRANCH,
},

View File

@ -4,6 +4,7 @@ import {
type FlowTransitionLine,
FlowTransitionLineEnum,
LABEL_SIDE_TYPE,
FlowTransitionLabelEnum,
} from '@flowgram.ai/document';
/**
@ -15,7 +16,7 @@ export const InputRegistry: FlowNodeRegistry = {
meta: {
hidden: false,
},
getLines(transition) {
getLines(transition, layout) {
const currentTransform = transition.transform;
const { isVertical } = transition.entity;
const lines: FlowTransitionLine[] = [];
@ -27,32 +28,44 @@ export const InputRegistry: FlowNodeRegistry = {
// 当有其余分支的时候,绘制一条两个分支之间的线条
if (hasBranchDraggingAdder) {
if (isVertical) {
const currentOffsetRightX = currentTransform.firstChild?.bounds?.right || 0;
const nextOffsetLeftX = currentTransform.next?.firstChild?.bounds?.left || 0;
const currentInputPointY = currentTransform.inputPoint.y;
const currentOffsetRightX = currentTransform.firstChild
? currentTransform.firstChild.bounds.right
: currentTransform.bounds.right;
const nextOffsetLeftX =
(currentTransform.next?.firstChild
? currentTransform.next?.firstChild.bounds?.left
: currentTransform.next?.bounds?.left) || 0;
const currentInputPointY = currentTransform.outputPoint.y;
if (currentTransform?.next) {
lines.push({
type: FlowTransitionLineEnum.DRAGGING_LINE,
from: currentTransform.parent!.inputPoint,
to: {
type: FlowTransitionLineEnum.MERGE_LINE,
isDraggingLine: true,
from: {
x: (currentOffsetRightX + nextOffsetLeftX) / 2,
y: currentInputPointY,
},
to: currentTransform.parent!.outputPoint,
side: LABEL_SIDE_TYPE.NORMAL_BRANCH,
});
}
} else {
const currentOffsetRightY = currentTransform.firstChild?.bounds?.bottom || 0;
const nextOffsetLeftY = currentTransform.next?.firstChild?.bounds?.top || 0;
const currentInputPointX = currentTransform.inputPoint.x;
const currentOffsetBottomX = currentTransform.firstChild
? currentTransform.firstChild.bounds.bottom
: currentTransform.bounds.bottom;
const nextOffsetTopX =
(currentTransform.next?.firstChild
? currentTransform.next?.firstChild.bounds?.top
: currentTransform.next?.bounds?.top) || 0;
const currentInputPointX = currentTransform.outputPoint.x;
if (currentTransform?.next) {
lines.push({
type: FlowTransitionLineEnum.DRAGGING_LINE,
from: currentTransform.parent!.inputPoint,
to: {
type: FlowTransitionLineEnum.MERGE_LINE,
isDraggingLine: true,
from: {
x: currentInputPointX,
y: (currentOffsetRightY + nextOffsetLeftY) / 2,
y: (currentOffsetBottomX + nextOffsetTopX) / 2,
},
to: currentTransform.parent!.outputPoint,
side: LABEL_SIDE_TYPE.NORMAL_BRANCH,
});
}
@ -71,7 +84,64 @@ export const InputRegistry: FlowNodeRegistry = {
return lines;
},
getLabels() {
return [];
getLabels(transition) {
const currentTransform = transition.transform;
const { isVertical } = transition.entity;
const draggingLabel = [];
const hasBranchDraggingAdder =
currentTransform && currentTransform.entity.isInlineBlock && transition.renderData.draggable;
// 获取两个分支节点中间点作为拖拽标签插入位置
if (hasBranchDraggingAdder) {
if (isVertical) {
const currentOffsetRightX = currentTransform.firstChild
? currentTransform.firstChild.bounds.right
: currentTransform.bounds.right;
const nextOffsetLeftX =
(currentTransform.next?.firstChild
? currentTransform.next.firstChild.bounds?.left
: currentTransform.next?.bounds?.left) || 0;
const currentInputPointY = currentTransform.outputPoint.y;
if (currentTransform?.next) {
draggingLabel.push({
offset: {
x: (currentOffsetRightX + nextOffsetLeftX) / 2,
y: currentInputPointY,
},
type: FlowTransitionLabelEnum.BRANCH_DRAGGING_LABEL,
width: nextOffsetLeftX - currentOffsetRightX,
props: {
side: LABEL_SIDE_TYPE.NORMAL_BRANCH,
},
});
}
} else {
const currentOffsetBottomX = currentTransform.firstChild
? currentTransform.firstChild.bounds.bottom
: currentTransform.bounds.bottom;
const nextOffsetTopX =
(currentTransform.next?.firstChild
? currentTransform.next.firstChild.bounds?.top
: currentTransform.next?.bounds?.top) || 0;
const currentInputPointX = currentTransform.outputPoint.x;
if (currentTransform?.next) {
draggingLabel.push({
offset: {
x: currentInputPointX,
y: (currentOffsetBottomX + nextOffsetTopX) / 2,
},
type: FlowTransitionLabelEnum.BRANCH_DRAGGING_LABEL,
width: nextOffsetTopX - currentOffsetBottomX,
props: {
side: LABEL_SIDE_TYPE.NORMAL_BRANCH,
},
});
}
}
}
return [...draggingLabel];
},
};

View File

@ -1,4 +1,14 @@
import { FlowNodeBaseType, FlowNodeSplitType, type FlowNodeRegistry } from '@flowgram.ai/document';
import { Point } from '@flowgram.ai/utils';
import { FlowRendererKey } from '@flowgram.ai/renderer';
import {
FlowNodeBaseType,
type FlowNodeRegistry,
FlowNodeRenderData,
FlowTransitionLabelEnum,
FlowNodeSplitType,
getDefaultSpacing,
ConstantKeys,
} from '@flowgram.ai/document';
/**
* ,
@ -15,6 +25,7 @@ export const MultiInputsRegistry: FlowNodeRegistry = {
type: FlowNodeBaseType.BLOCK_ICON,
meta: {
hidden: true,
spacing: 0,
},
getLines() {
return [];
@ -25,8 +36,54 @@ export const MultiInputsRegistry: FlowNodeRegistry = {
},
{
type: FlowNodeBaseType.INLINE_BLOCKS,
getLabels() {
return [];
meta: {
inlineSpacingPre: 0,
},
getLabels(transition) {
const isVertical = transition.entity.isVertical;
const currentTransform = transition.transform;
const spacing = getDefaultSpacing(
transition.entity,
ConstantKeys.INLINE_BLOCKS_PADDING_BOTTOM
);
if (currentTransform.collapsed || transition.entity.childrenLength === 0) {
return [
{
type: FlowTransitionLabelEnum.CUSTOM_LABEL,
renderKey: FlowRendererKey.BRANCH_ADDER,
offset: Point.move(
currentTransform.outputPoint,
isVertical ? { y: spacing } : { x: spacing }
),
props: {
// 激活状态
activated: transition.entity.getData(FlowNodeRenderData)!.activated,
transform: currentTransform,
// 传给外部使用的 node 信息
node: currentTransform.originParent?.entity,
},
},
];
}
return [
{
type: FlowTransitionLabelEnum.CUSTOM_LABEL,
renderKey: FlowRendererKey.BRANCH_ADDER,
offset: Point.move(
currentTransform.outputPoint,
isVertical ? { y: -spacing / 2 } : { x: -spacing / 2 }
),
props: {
// 激活状态
activated: transition.entity.getData(FlowNodeRenderData)!.activated,
transform: currentTransform,
// 传给外部使用的 node 信息
node: currentTransform.originParent?.entity,
},
},
];
},
},
],

View File

@ -1,5 +1,11 @@
import { FlowNodeBaseType, type FlowNodeRegistry, FlowNodeSplitType } from '@flowgram.ai/document';
import {
FlowLayoutDefault,
type FlowNodeRegistry,
FlowNodeSplitType,
FlowNodeBaseType,
} from '@flowgram.ai/document';
import { DynamicSplitRegistry } from './dynamic-split';
import { BlockRegistry } from './block';
/**
@ -13,10 +19,42 @@ import { BlockRegistry } from './block';
export const MultiOuputsRegistry: FlowNodeRegistry = {
type: FlowNodeBaseType.MULTI_OUTPUTS,
extend: FlowNodeSplitType.SIMPLE_SPLIT,
meta: {
isNodeEnd: true,
},
getLines: (transition, layout) => {
// 嵌套在 mutliOutputs 下边
if (transition.entity.parent?.flowNodeType === FlowNodeBaseType.INLINE_BLOCKS) {
return BlockRegistry.getLines!(transition, layout);
}
return [];
},
getLabels: (transition, layout) => [
...DynamicSplitRegistry.getLabels!(transition, layout),
...BlockRegistry.getLabels!(transition, layout),
],
getOutputPoint(transform, layout) {
const isVertical = FlowLayoutDefault.isVertical(layout);
const lastChildOutput = transform.lastChild?.outputPoint;
if (isVertical) {
return {
x: lastChildOutput ? lastChildOutput.x : transform.bounds.center.x,
y: transform.bounds.bottom,
};
}
return {
x: transform.bounds.right,
y: lastChildOutput ? lastChildOutput.y : transform.bounds.center.y,
};
},
extendChildRegistries: [
{
type: FlowNodeBaseType.BLOCK_ICON,
meta: {
// isNodeEnd: true
},
},
],
};

View File

@ -37,11 +37,11 @@ export function createLines(props: PropsType): void {
const { lineActivated } = renderData || {};
const draggingLineHide =
line.type === FlowTransitionLineEnum.DRAGGING_LINE &&
(line.type === FlowTransitionLineEnum.DRAGGING_LINE || line.isDraggingLine) &&
!dragService.isDroppableBranch(data.entity, line.side);
const draggingLineActivated =
line.type === FlowTransitionLineEnum.DRAGGING_LINE &&
(line.type === FlowTransitionLineEnum.DRAGGING_LINE || line.isDraggingLine) &&
data.entity?.id === dragService.dropNodeId &&
line.side === dragService.labelSide;

View File

@ -89,11 +89,10 @@ describe('history-operation-service moveNode', () => {
const split = flowDocument.getNode('dynamicSplit_0');
const split1 = flowDocument.getNode('dynamicSplit_1');
// 没有执行成功,因为没有 children 的分支节点,$inlineBlocks$dynamicSplit_1 不存在
expect(getNodeChildrenIds(split, true)).toEqual(['block_0', 'block_1', 'block_2']);
expect(getNodeChildrenIds(split1, true)).toEqual([]);
expect(getNodeChildrenIds(split, true)).toEqual(['block_0', 'block_2']);
expect(getNodeChildrenIds(split1, true)).toEqual(['block_1']);
expect(historyService.canUndo()).toBe(false);
expect(historyService.canUndo()).toBe(true);
});
it('move node without parent and index', async () => {