@flowgram-vue/renderer 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. package/LICENSE +22 -0
  2. package/dist/index.cjs +2933 -0
  3. package/dist/index.cjs.map +1 -0
  4. package/dist/index.d.ts +721 -0
  5. package/dist/index.js +2918 -0
  6. package/dist/index.js.map +1 -0
  7. package/index.module.less +167 -0
  8. package/package.json +64 -0
  9. package/src/components/Adder.ts +107 -0
  10. package/src/components/BranchDraggableRenderer.ts +77 -0
  11. package/src/components/Collapse.ts +87 -0
  12. package/src/components/CollapseAdder.ts +94 -0
  13. package/src/components/CustomLine.ts +35 -0
  14. package/src/components/LabelsRenderer.ts +162 -0
  15. package/src/components/LinesRenderer.ts +99 -0
  16. package/src/components/MarkerActivatedArrow.ts +44 -0
  17. package/src/components/MarkerArrow.ts +44 -0
  18. package/src/components/RoundedTurningLine.ts +165 -0
  19. package/src/components/StraightLine.ts +31 -0
  20. package/src/components/utils.ts +295 -0
  21. package/src/entities/README.md +3 -0
  22. package/src/entities/flow-drag-entity.ts +267 -0
  23. package/src/entities/flow-select-config-entity.ts +114 -0
  24. package/src/entities/index.ts +8 -0
  25. package/src/entities/selector-box-config-entity.ts +88 -0
  26. package/src/env.d.ts +10 -0
  27. package/src/flow-renderer-container-module.ts +14 -0
  28. package/src/flow-renderer-contribution.ts +12 -0
  29. package/src/flow-renderer-registry.ts +155 -0
  30. package/src/flow-renderer-resize-observer.ts +56 -0
  31. package/src/hooks/use-base-color.ts +26 -0
  32. package/src/index.ts +16 -0
  33. package/src/layer-vue-provide.ts +44 -0
  34. package/src/layers/flow-context-menu-layer.ts +153 -0
  35. package/src/layers/flow-debug-layer.ts +227 -0
  36. package/src/layers/flow-drag-layer.ts +413 -0
  37. package/src/layers/flow-labels-layer.ts +100 -0
  38. package/src/layers/flow-lines-layer.ts +111 -0
  39. package/src/layers/flow-nodes-content-layer.ts +155 -0
  40. package/src/layers/flow-nodes-transform-layer.ts +151 -0
  41. package/src/layers/flow-scroll-bar-layer.ts +401 -0
  42. package/src/layers/flow-scroll-limit-layer.ts +36 -0
  43. package/src/layers/flow-selector-bounds-layer.ts +191 -0
  44. package/src/layers/flow-selector-box-layer.ts +244 -0
  45. package/src/layers/index.ts +16 -0
  46. package/src/utils/element.ts +36 -0
  47. package/src/utils/find-selected-nodes.ts +80 -0
  48. package/src/utils/index.ts +7 -0
  49. package/src/utils/scroll-bar-events.ts +13 -0
  50. package/src/utils/scroll-limit.ts +58 -0
@@ -0,0 +1,227 @@
1
+ /**
2
+ * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
3
+ * SPDX-License-Identifier: MIT
4
+ */
5
+
6
+ import { inject, injectable } from 'inversify';
7
+ import { domUtils } from '@flowgram-vue/utils';
8
+ import {
9
+ FlowDocument,
10
+ FlowDocumentTransformerEntity,
11
+ FlowNodeEntity,
12
+ FlowNodeTransformData,
13
+ } from '@flowgram-vue/document';
14
+ import { Layer, observeEntity, observeEntityDatas } from '@flowgram-vue/core';
15
+
16
+ import { getScrollViewport } from '../utils';
17
+
18
+ let rgbTimes = 0;
19
+
20
+ function randomColor(percent: number): string {
21
+ const max = Math.min((percent / 10) * 255, 255);
22
+ rgbTimes += 1;
23
+ // rgb 轮询就可以错开颜色
24
+ const rgb = rgbTimes % 3;
25
+ const random = () => Math.floor(Math.random() * max);
26
+ return `rgb(${rgb === 0 ? random() : 0}, ${rgb === 1 ? random() : 0}, ${
27
+ rgb === 2 ? random() : 0
28
+ })`;
29
+ }
30
+
31
+ /**
32
+ * 调试用,会绘出所有节点的边界
33
+ */
34
+ @injectable()
35
+ export class FlowDebugLayer extends Layer {
36
+ @inject(FlowDocument) readonly document: FlowDocument;
37
+
38
+ @observeEntity(FlowDocumentTransformerEntity)
39
+ readonly documentTransformer: FlowDocumentTransformerEntity;
40
+
41
+ @observeEntityDatas(FlowNodeEntity, FlowNodeTransformData) _transforms: FlowNodeTransformData[];
42
+
43
+ get transforms(): FlowNodeTransformData[] {
44
+ return this.document.getRenderDatas<FlowNodeTransformData>(FlowNodeTransformData);
45
+ }
46
+
47
+ node = document.createElement('div') as HTMLElement;
48
+
49
+ viewport = domUtils.createDivWithClass('gedit-flow-debug-bounds');
50
+
51
+ boundsNodes = domUtils.createDivWithClass('gedit-flow-debug-bounds');
52
+
53
+ pointsNodes = domUtils.createDivWithClass('gedit-flow-debug-points');
54
+
55
+ versionNodes = domUtils.createDivWithClass('gedit-flow-debug-versions gedit-hidden');
56
+
57
+ /**
58
+ * ?debug=xxxx, 则返回 xxxx
59
+ */
60
+ filterKey = window.location.search.match(/debug=([^&]+)/)?.[1] || '';
61
+
62
+ protected originLine = document.createElement('div') as HTMLDivElement;
63
+
64
+ domCache = new WeakMap<
65
+ FlowNodeTransformData,
66
+ {
67
+ color: string;
68
+ bbox: HTMLDivElement;
69
+ version: HTMLDivElement;
70
+ input: HTMLDivElement;
71
+ output: HTMLDivElement;
72
+ }
73
+ >();
74
+
75
+ onReady() {
76
+ this.node!.style.zIndex = '20';
77
+ domUtils.setStyle(this.originLine, {
78
+ position: 'absolute',
79
+ width: 1,
80
+ height: '100%',
81
+ left: this.pipelineNode.style.left,
82
+ top: 0,
83
+ borderLeft: '1px dashed rgba(255, 0, 0, 0.5)',
84
+ });
85
+ this.pipelineNode.parentElement!.appendChild(this.originLine);
86
+ this.node.appendChild(this.viewport);
87
+ this.node.appendChild(this.versionNodes);
88
+ this.node.appendChild(this.boundsNodes);
89
+ this.node.appendChild(this.pointsNodes);
90
+ this.renderScrollViewportBounds();
91
+ }
92
+
93
+ onScroll() {
94
+ this.originLine.style.left = this.pipelineNode.style.left;
95
+ this.renderScrollViewportBounds();
96
+ }
97
+
98
+ onResize() {
99
+ this.renderScrollViewportBounds();
100
+ }
101
+
102
+ onZoom(scale: number) {
103
+ this.node!.style.transform = `scale(${scale})`;
104
+ this.renderScrollViewportBounds();
105
+ }
106
+
107
+ createBounds(transform: FlowNodeTransformData, color: string, depth: number): void {
108
+ // 根据 debug=xxxx 进行匹配过滤
109
+ if (this.filterKey && transform.key.indexOf(this.filterKey) === -1) return;
110
+ let cache = this.domCache.get(transform)!;
111
+ const { bounds, inputPoint, outputPoint } = transform;
112
+ if (!cache) {
113
+ const bbox = domUtils.createDivWithClass('') as HTMLDivElement;
114
+ const input = domUtils.createDivWithClass('') as HTMLDivElement;
115
+ const output = domUtils.createDivWithClass('') as HTMLDivElement;
116
+ const version = domUtils.createDivWithClass('') as HTMLDivElement;
117
+ bbox.title = transform.key;
118
+ input.title = transform.key + '(input)';
119
+ output.title = transform.key + '(output)';
120
+ version.title = transform.key;
121
+ this.boundsNodes.appendChild(bbox);
122
+ this.pointsNodes.appendChild(input);
123
+ this.pointsNodes.appendChild(output);
124
+ this.versionNodes.appendChild(version);
125
+ transform.onDispose(() => {
126
+ bbox.remove();
127
+ input.remove();
128
+ output.remove();
129
+ });
130
+ cache = { bbox, input, output, version, color };
131
+ this.domCache.set(transform, cache);
132
+ }
133
+ domUtils.setStyle(cache.version, {
134
+ position: 'absolute',
135
+ marginLeft: '-9px',
136
+ marginTop: '-10px',
137
+ borderRadius: 12,
138
+ background: '#f54a45',
139
+ padding: 4,
140
+ color: 'navajowhite',
141
+ display: transform.renderState.hidden ? 'none' : 'block',
142
+ zIndex: depth + 1000,
143
+ left: bounds.center.x,
144
+ top: bounds.center.y,
145
+ });
146
+ cache.version.innerHTML = transform.version.toString();
147
+ domUtils.setStyle(cache.input, {
148
+ position: 'absolute',
149
+ width: 10,
150
+ height: 10,
151
+ marginLeft: -5,
152
+ marginTop: -5,
153
+ borderRadius: 5,
154
+ left: inputPoint.x,
155
+ top: inputPoint.y,
156
+ opacity: 0.4,
157
+ zIndex: depth,
158
+ backgroundColor: cache.color,
159
+ whiteSpace: 'nowrap',
160
+ overflow: 'visible',
161
+ });
162
+ cache.input.innerHTML = `${inputPoint.x},${inputPoint.y}`;
163
+ domUtils.setStyle(cache.output, {
164
+ position: 'absolute',
165
+ width: 10,
166
+ height: 10,
167
+ marginLeft: -5,
168
+ marginTop: -5,
169
+ borderRadius: 5,
170
+ left: outputPoint.x,
171
+ top: outputPoint.y,
172
+ opacity: 0.4,
173
+ zIndex: depth,
174
+ backgroundColor: cache.color,
175
+ whiteSpace: 'nowrap',
176
+ overflow: 'visible',
177
+ });
178
+ cache.output.innerHTML = `${outputPoint.x},${outputPoint.y}`;
179
+ domUtils.setStyle(cache.bbox, {
180
+ position: 'absolute',
181
+ width: bounds.width,
182
+ height: bounds.height,
183
+ left: bounds.left,
184
+ top: bounds.top,
185
+ opacity: `${depth / 30}`,
186
+ backgroundColor: cache.color,
187
+ });
188
+ }
189
+
190
+ /**
191
+ * 显示 viewport 可滚动区域
192
+ */
193
+ renderScrollViewportBounds() {
194
+ const viewportBounds = getScrollViewport(
195
+ {
196
+ scrollX: this.config.config.scrollX,
197
+ scrollY: this.config.config.scrollY,
198
+ },
199
+ this.config
200
+ );
201
+ domUtils.setStyle(this.viewport, {
202
+ position: 'absolute',
203
+ width: viewportBounds.width - 2,
204
+ height: viewportBounds.height - 2,
205
+ left: viewportBounds.left + 1,
206
+ top: viewportBounds.top + 1,
207
+ border: '1px solid rgba(200, 200, 255, 0.5)',
208
+ });
209
+ }
210
+
211
+ autorun() {
212
+ if (this.documentTransformer.loading) return;
213
+ this.documentTransformer.refresh();
214
+ // let lastDepth = 0
215
+ let color = randomColor(0);
216
+ this.document.traverse((entity, depth) => {
217
+ const transform = entity.getData<FlowNodeTransformData>(FlowNodeTransformData)!;
218
+ // if (lastDepth !== depth) {
219
+ // // 层级变化则更新颜色
220
+ // }
221
+ color = randomColor(depth);
222
+ this.createBounds(transform, color, depth);
223
+ // lastDepth = depth
224
+ });
225
+ this.renderScrollViewportBounds();
226
+ }
227
+ }
@@ -0,0 +1,413 @@
1
+ /**
2
+ * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
3
+ * SPDX-License-Identifier: MIT
4
+ */
5
+
6
+ import { h, Teleport } from 'vue';
7
+ import type { Component } from 'vue';
8
+ import { inject, injectable } from 'inversify';
9
+ import { Rectangle, Xor } from '@flowgram-vue/utils';
10
+ import {
11
+ FlowDocument,
12
+ FlowNodeBaseType,
13
+ FlowNodeEntity,
14
+ FlowNodeRenderData,
15
+ FlowNodeTransformData,
16
+ FlowNodeTransitionData,
17
+ FlowRendererStateEntity,
18
+ type LABEL_SIDE_TYPE,
19
+ FlowDragService,
20
+ FlowNodeJSON,
21
+ } from '@flowgram-vue/document';
22
+ import {
23
+ EditorState,
24
+ EditorStateConfigEntity,
25
+ Layer,
26
+ observeEntity,
27
+ observeEntityDatas,
28
+ PlaygroundConfigEntity,
29
+ PlaygroundContainerFactory,
30
+ PlaygroundDrag,
31
+ } from '@flowgram-vue/core';
32
+
33
+ import { wrapLayerRender } from '../layer-vue-provide';
34
+ import {
35
+ type FlowRendererComponent,
36
+ FlowRendererKey,
37
+ FlowRendererRegistry,
38
+ } from '../flow-renderer-registry';
39
+ import { type CollisionRetType, FlowDragEntity } from '../entities/flow-drag-entity';
40
+ import { FlowSelectConfigEntity } from '../entities';
41
+
42
+ const DRAG_OFFSET = 10;
43
+
44
+ const DEFAULT_DRAG_OFFSET_X = 8;
45
+ const DEFAULT_DRAG_OFFSET_Y = 8;
46
+
47
+ interface Position {
48
+ x: number;
49
+ y: number;
50
+ }
51
+
52
+ type StartDragProps = {
53
+ dragEntities?: FlowNodeEntity[];
54
+ } & Xor<
55
+ {
56
+ dragStartEntity: FlowNodeEntity;
57
+ },
58
+ {
59
+ dragJSON: FlowNodeJSON;
60
+ isBranch?: boolean;
61
+ onCreateNode: (json: FlowNodeJSON, dropEntity: FlowNodeEntity) => Promise<FlowNodeEntity>;
62
+ }
63
+ >;
64
+
65
+ export interface FlowDragOptions {
66
+ onDrop?: (opts: { dragNodes: FlowNodeEntity[]; dropNode: FlowNodeEntity }) => void;
67
+ canDrop?: (
68
+ opts: {
69
+ dropNode: FlowNodeEntity;
70
+ isBranch?: boolean;
71
+ } & Xor<
72
+ {
73
+ dragNodes: FlowNodeEntity[];
74
+ },
75
+ {
76
+ dragJSON: FlowNodeJSON;
77
+ }
78
+ >
79
+ ) => boolean;
80
+ }
81
+ /**
82
+ * 监听节点的激活状态
83
+ */
84
+ @injectable()
85
+ export class FlowDragLayer extends Layer<FlowDragOptions> {
86
+ @inject(FlowDocument) readonly document: FlowDocument;
87
+
88
+ @inject(FlowDragService) readonly flowDragService: FlowDragService;
89
+
90
+ @inject(PlaygroundContainerFactory) readonly playgroundContainer: PlaygroundContainerFactory;
91
+
92
+ @observeEntityDatas(FlowNodeEntity, FlowNodeTransformData) transforms: FlowNodeTransformData[];
93
+
94
+ @observeEntity(EditorStateConfigEntity)
95
+ protected editorStateConfig: EditorStateConfigEntity;
96
+
97
+ @observeEntity(PlaygroundConfigEntity)
98
+ protected playgroundConfigEntity: PlaygroundConfigEntity;
99
+
100
+ @observeEntity(FlowDragEntity)
101
+ protected flowDragConfigEntity: FlowDragEntity;
102
+
103
+ @observeEntity(FlowRendererStateEntity)
104
+ protected flowRenderStateEntity: FlowRendererStateEntity;
105
+
106
+ @observeEntity(FlowSelectConfigEntity)
107
+ protected selectConfigEntity: FlowSelectConfigEntity;
108
+
109
+ private initialPosition: Position;
110
+
111
+ private disableDragScroll: Boolean = false;
112
+
113
+ private dragJSON?: FlowNodeJSON;
114
+
115
+ private onCreateNode?: (
116
+ json: FlowNodeJSON,
117
+ dropEntity: FlowNodeEntity
118
+ ) => Promise<FlowNodeEntity>;
119
+
120
+ dragOffset = {
121
+ x: DEFAULT_DRAG_OFFSET_X,
122
+ y: DEFAULT_DRAG_OFFSET_Y,
123
+ };
124
+
125
+ get transitions(): FlowNodeTransitionData[] {
126
+ const result: FlowNodeTransitionData[] = [];
127
+ this.document.traverse((entity) => {
128
+ result.push(entity.getData<FlowNodeTransitionData>(FlowNodeTransitionData)!);
129
+ });
130
+ return result;
131
+ }
132
+
133
+ @inject(FlowRendererRegistry) readonly rendererRegistry: FlowRendererRegistry;
134
+
135
+ get dragStartEntity() {
136
+ return this.flowRenderStateEntity.getDragStartEntity()!;
137
+ }
138
+
139
+ set dragStartEntity(entity: FlowNodeEntity | undefined) {
140
+ this.flowRenderStateEntity.setDragStartEntity(entity);
141
+ }
142
+
143
+ get dragEntities() {
144
+ return this.flowRenderStateEntity.getDragEntities()!;
145
+ }
146
+
147
+ set dragEntities(entities: FlowNodeEntity[]) {
148
+ this.flowRenderStateEntity.setDragEntities(entities);
149
+ }
150
+
151
+ private dragNodeComp: FlowRendererComponent;
152
+
153
+ containerRef: { current: HTMLDivElement | null } = { current: null };
154
+
155
+ draggingNodeMask = document.createElement('div');
156
+
157
+ protected isGrab(): boolean {
158
+ const currentState = this.editorStateConfig.getCurrentState();
159
+ return currentState === EditorState.STATE_GRAB;
160
+ }
161
+
162
+ setDraggingStatus(status: boolean): void {
163
+ if (this.flowDragService.nodeDragIdsWithChildren.length) {
164
+ this.flowDragService.nodeDragIdsWithChildren.forEach((_id) => {
165
+ const node = this.entityManager.getEntityById(_id);
166
+ const data = node?.getData<FlowNodeRenderData>(FlowNodeRenderData)!;
167
+ data.dragging = status;
168
+ });
169
+ }
170
+ this.flowRenderStateEntity.setDragging(status);
171
+ }
172
+
173
+ dragEnable(e: MouseEvent) {
174
+ return (
175
+ Math.abs(e.clientX - this.initialPosition.x) > DRAG_OFFSET ||
176
+ Math.abs(e.clientY - this.initialPosition.y) > DRAG_OFFSET
177
+ );
178
+ }
179
+
180
+ handleMouseMove(event: MouseEvent) {
181
+ if ((this.dragJSON || this.dragStartEntity) && this.dragEnable(event)) {
182
+ this.setDraggingStatus(true);
183
+ const scale = this.playgroundConfigEntity.finalScale;
184
+
185
+ if (this.containerRef.current) {
186
+ const dragNode = this.containerRef.current.children?.[0];
187
+ if (!dragNode) {
188
+ return;
189
+ }
190
+ const clientBounds = this.playgroundConfigEntity.getClientBounds();
191
+ const dragBlockX =
192
+ event.clientX -
193
+ (this.pipelineNode.offsetLeft || 0) -
194
+ clientBounds.x -
195
+ ((dragNode as HTMLElement).clientWidth - this.dragOffset.x) * scale;
196
+ const dragBlockY =
197
+ event.clientY -
198
+ (this.pipelineNode.offsetTop || 0) -
199
+ clientBounds.y -
200
+ ((dragNode as HTMLElement).clientHeight - this.dragOffset.y) * scale;
201
+
202
+ const isBranch = this.flowDragService.isDragBranch;
203
+
204
+ const draggingRect = new Rectangle(
205
+ dragBlockX,
206
+ dragBlockY,
207
+ (dragNode as HTMLElement).clientWidth * scale,
208
+ (dragNode as HTMLElement).clientHeight * scale
209
+ );
210
+ let side: LABEL_SIDE_TYPE | undefined;
211
+ const collisionTransition = this.transitions.find((transition) => {
212
+ if (transition?.entity?.parent?.collapsed) {
213
+ return false;
214
+ }
215
+ const { hasCollision, labelOffsetType } = this.flowDragConfigEntity.isCollision(
216
+ transition,
217
+ draggingRect,
218
+ isBranch
219
+ ) as CollisionRetType;
220
+ side = labelOffsetType;
221
+ return hasCollision;
222
+ });
223
+ if (
224
+ collisionTransition &&
225
+ (isBranch
226
+ ? this.flowDragService.isDroppableBranch(collisionTransition.entity, side)
227
+ : this.flowDragService.isDroppableNode(collisionTransition.entity)) &&
228
+ (!this.options.canDrop ||
229
+ this.options.canDrop({
230
+ dragNodes: this.dragEntities,
231
+ dropNode: collisionTransition.entity,
232
+ isBranch,
233
+ }))
234
+ ) {
235
+ this.flowRenderStateEntity.setNodeDroppingId(collisionTransition.entity.id);
236
+ } else {
237
+ this.flowRenderStateEntity.setNodeDroppingId('');
238
+ }
239
+
240
+ this.flowRenderStateEntity.setDragLabelSide(side);
241
+
242
+ this.containerRef.current.style.visibility = 'visible';
243
+ this.pipelineNode.parentElement!.appendChild(this.draggingNodeMask);
244
+
245
+ this.containerRef.current.style.left = `${
246
+ dragBlockX + this.pipelineNode.offsetLeft + clientBounds.x + window.scrollX
247
+ }px`;
248
+ this.containerRef.current.style.top = `${
249
+ dragBlockY + this.pipelineNode.offsetTop + clientBounds.y + window.scrollY
250
+ }px`;
251
+ this.containerRef.current.style.transformOrigin = 'top left';
252
+ this.containerRef.current.style.transform = `scale(${scale})`;
253
+
254
+ if (!this.disableDragScroll) {
255
+ this.flowDragConfigEntity.scrollDirection(event, dragBlockX, dragBlockY);
256
+ }
257
+ }
258
+ }
259
+ }
260
+
261
+ async handleMouseUp() {
262
+ this.setDraggingStatus(false);
263
+ if (this.dragStartEntity || this.dragJSON) {
264
+ const activatedNodeId = this.flowDragService.dropNodeId;
265
+
266
+ if (activatedNodeId) {
267
+ if (this.flowDragService.isDragBranch) {
268
+ if (this.dragJSON) {
269
+ await this.flowDragService.dropCreateNode(this.dragJSON, this.onCreateNode);
270
+ } else {
271
+ this.flowDragService.dropBranch();
272
+ }
273
+ } else {
274
+ if (this.dragJSON) {
275
+ await this.flowDragService.dropCreateNode(this.dragJSON, this.onCreateNode);
276
+ } else {
277
+ this.flowDragService.dropNode();
278
+ }
279
+ this.selectConfigEntity.clearSelectedNodes();
280
+ }
281
+ }
282
+
283
+ this.flowRenderStateEntity.setNodeDroppingId('');
284
+ this.flowRenderStateEntity.setDragLabelSide();
285
+ this.flowRenderStateEntity.setIsBranch(false);
286
+ this.dragStartEntity = undefined;
287
+ this.dragEntities = [];
288
+
289
+ this.flowDragConfigEntity.stopAllScroll();
290
+ }
291
+
292
+ this.disableDragScroll = false;
293
+ this.dragJSON = undefined;
294
+ if (this.containerRef.current) {
295
+ this.containerRef.current.style.visibility = 'hidden';
296
+ if (this.pipelineNode.parentElement!.contains(this.draggingNodeMask)) {
297
+ this.pipelineNode.parentElement!.removeChild(this.draggingNodeMask);
298
+ }
299
+ }
300
+ }
301
+
302
+ protected _dragger = new PlaygroundDrag({
303
+ onDrag: (e) => {
304
+ this.handleMouseMove(e);
305
+ },
306
+ onDragEnd: () => {
307
+ this.handleMouseUp();
308
+ },
309
+ stopGlobalEventNames: ['contextmenu'],
310
+ });
311
+
312
+ /**
313
+ * 开始拖拽事件
314
+ * @param e
315
+ */
316
+ async startDrag(
317
+ e: { clientX: number; clientY: number },
318
+ {
319
+ dragStartEntity: startEntityFromProps,
320
+ dragEntities,
321
+ dragJSON,
322
+ isBranch,
323
+ onCreateNode,
324
+ }: StartDragProps,
325
+ options?: {
326
+ dragOffsetX?: number;
327
+ dragOffsetY?: number;
328
+ disableDragScroll?: boolean;
329
+ }
330
+ ) {
331
+ if (this.isGrab() || this.config.disabled || this.config.readonly) {
332
+ return;
333
+ }
334
+
335
+ this.disableDragScroll = Boolean(options?.disableDragScroll);
336
+ this.dragJSON = dragJSON;
337
+ this.onCreateNode = onCreateNode;
338
+ this.flowRenderStateEntity.setIsBranch(Boolean(isBranch));
339
+
340
+ this.dragOffset.x = options?.dragOffsetX || DEFAULT_DRAG_OFFSET_X;
341
+ this.dragOffset.y = options?.dragOffsetY || DEFAULT_DRAG_OFFSET_Y;
342
+
343
+ const type = startEntityFromProps?.flowNodeType || dragJSON?.type;
344
+
345
+ const isIcon = type === FlowNodeBaseType.BLOCK_ICON;
346
+ const isOrderIcon = type === FlowNodeBaseType.BLOCK_ORDER_ICON;
347
+
348
+ const dragStartEntity =
349
+ isIcon || isOrderIcon ? startEntityFromProps!.parent! : startEntityFromProps;
350
+
351
+ if (dragStartEntity && !dragStartEntity!.getData(FlowNodeRenderData).draggable) {
352
+ return;
353
+ }
354
+
355
+ this.initialPosition = {
356
+ x: e.clientX,
357
+ y: e.clientY,
358
+ };
359
+
360
+ this.dragStartEntity = dragStartEntity;
361
+ this.dragEntities = dragEntities || (this.dragStartEntity ? [this.dragStartEntity!] : []);
362
+
363
+ return this._dragger.start(e.clientX, e.clientY);
364
+ }
365
+
366
+ onReady() {
367
+ this.draggingNodeMask.style.width = '100%';
368
+ this.draggingNodeMask.style.height = '100%';
369
+ this.draggingNodeMask.style.position = 'absolute';
370
+ this.draggingNodeMask.classList.add('dragging-node');
371
+ this.draggingNodeMask.style.zIndex = '99';
372
+ this.draggingNodeMask.style.cursor = 'pointer';
373
+
374
+ this.dragNodeComp = this.rendererRegistry.getRendererComponent(FlowRendererKey.DRAG_NODE);
375
+ if (this.options.onDrop) {
376
+ this.toDispose.push(this.flowDragService.onDrop(this.options.onDrop));
377
+ }
378
+ }
379
+
380
+ dispose(): void {
381
+ this._dragger.dispose();
382
+ super.dispose();
383
+ }
384
+
385
+ render() {
386
+ const DragComp = this.dragNodeComp?.renderer as Component;
387
+
388
+ return wrapLayerRender(
389
+ this.playgroundContainer,
390
+ h(Teleport, { to: 'body' }, [
391
+ h(
392
+ 'div',
393
+ {
394
+ ref: (el: unknown) => {
395
+ this.containerRef.current = (el as HTMLDivElement) || null;
396
+ },
397
+ style: { position: 'absolute', zIndex: 99999, visibility: 'hidden' },
398
+ onMouseenter: (e: MouseEvent) => e.stopPropagation(),
399
+ },
400
+ [
401
+ DragComp
402
+ ? h(DragComp, {
403
+ dragJSON: this.dragJSON,
404
+ dragStart: this.dragStartEntity,
405
+ dragNodes: this.dragEntities,
406
+ })
407
+ : null,
408
+ ]
409
+ ),
410
+ ])
411
+ );
412
+ }
413
+ }