@flowgram-vue/free-layout-core 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 (68) hide show
  1. package/LICENSE +22 -0
  2. package/dist/index.cjs +0 -0
  3. package/dist/index.cjs.map +1 -0
  4. package/dist/index.d.ts +1 -0
  5. package/dist/index.js +0 -0
  6. package/dist/index.js.map +1 -0
  7. package/dist/typings.cjs +46 -0
  8. package/dist/typings.cjs.map +1 -0
  9. package/dist/typings.d.ts +1 -0
  10. package/dist/typings.js +40 -0
  11. package/dist/typings.js.map +1 -0
  12. package/package.json +78 -0
  13. package/src/composables/index.ts +24 -0
  14. package/src/composables/typings.ts +97 -0
  15. package/src/composables/use-current-dom-node.ts +18 -0
  16. package/src/composables/use-current-entity.ts +15 -0
  17. package/src/composables/use-node-render-context.ts +18 -0
  18. package/src/composables/use-node-render.ts +192 -0
  19. package/src/composables/use-playground-readonly-state.ts +25 -0
  20. package/src/composables/use-workflow-document.ts +12 -0
  21. package/src/constants.ts +17 -0
  22. package/src/entities/index.ts +8 -0
  23. package/src/entities/workflow-line-entity.ts +640 -0
  24. package/src/entities/workflow-node-entity.ts +17 -0
  25. package/src/entities/workflow-port-entity.ts +340 -0
  26. package/src/entity-datas/index.ts +8 -0
  27. package/src/entity-datas/workflow-line-render-data.ts +136 -0
  28. package/src/entity-datas/workflow-node-lines-data.ts +166 -0
  29. package/src/entity-datas/workflow-node-ports-data.ts +253 -0
  30. package/src/env.d.ts +10 -0
  31. package/src/index.ts +18 -0
  32. package/src/layout/free-layout.ts +166 -0
  33. package/src/layout/index.ts +6 -0
  34. package/src/service/index.ts +10 -0
  35. package/src/service/workflow-drag-service.ts +969 -0
  36. package/src/service/workflow-hover-service.ts +106 -0
  37. package/src/service/workflow-operation-base-service.ts +118 -0
  38. package/src/service/workflow-reset-layout-service.ts +87 -0
  39. package/src/service/workflow-select-service.ts +128 -0
  40. package/src/typings/index.ts +19 -0
  41. package/src/typings/workflow-drag.ts +51 -0
  42. package/src/typings/workflow-edge.ts +15 -0
  43. package/src/typings/workflow-json.ts +64 -0
  44. package/src/typings/workflow-line.ts +71 -0
  45. package/src/typings/workflow-node.ts +52 -0
  46. package/src/typings/workflow-operation.ts +40 -0
  47. package/src/typings/workflow-registry.ts +34 -0
  48. package/src/typings/workflow-sub-canvas.ts +15 -0
  49. package/src/utils/build-group-json.ts +47 -0
  50. package/src/utils/compose.ts +6 -0
  51. package/src/utils/fit-view.ts +21 -0
  52. package/src/utils/flow-node-form-data.ts +45 -0
  53. package/src/utils/get-anti-overlap-position.ts +44 -0
  54. package/src/utils/get-line-center.ts +22 -0
  55. package/src/utils/get-url-params.ts +50 -0
  56. package/src/utils/index.ts +29 -0
  57. package/src/utils/layout-to-positions.ts +65 -0
  58. package/src/utils/location-config-to-point.ts +40 -0
  59. package/src/utils/nanoid.ts +10 -0
  60. package/src/utils/statics.ts +27 -0
  61. package/src/vue/index.ts +6 -0
  62. package/src/vue/node-render-provider.vue +16 -0
  63. package/src/workflow-commands.ts +14 -0
  64. package/src/workflow-document-container-module.ts +50 -0
  65. package/src/workflow-document-contribution.ts +31 -0
  66. package/src/workflow-document-option.ts +148 -0
  67. package/src/workflow-document.ts +873 -0
  68. package/src/workflow-lines-manager.ts +596 -0
@@ -0,0 +1,52 @@
1
+ /**
2
+ * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
3
+ * SPDX-License-Identifier: MIT
4
+ */
5
+
6
+ import type { IPoint } from '@flowgram-vue/utils';
7
+ import type { FlowNodeJSON, FlowNodeMeta } from '@flowgram-vue/document';
8
+
9
+ import type { WorkflowNodeEntity, WorkflowPorts } from '../entities';
10
+ import type { WorkflowSubCanvas } from './workflow-sub-canvas';
11
+ import type { WorkflowEdgeJSON } from './workflow-edge';
12
+
13
+ /**
14
+ * 节点 meta 信息
15
+ */
16
+ export interface WorkflowNodeMeta extends FlowNodeMeta {
17
+ position?: IPoint;
18
+ canvasPosition?: IPoint; // 子画布位置
19
+ deleteDisable?: boolean; // 是否禁用删除
20
+ copyDisable?: boolean; // 禁用复制
21
+ inputDisable?: boolean; // 禁用输入点
22
+ outputDisable?: boolean; // 禁用输出点
23
+ defaultPorts?: WorkflowPorts; // 默认点位
24
+ useDynamicPort?: boolean; // 使用动态点位,会计算 data-port-key
25
+ subCanvas?: (node: WorkflowNodeEntity) => WorkflowSubCanvas | undefined;
26
+ isContainer?: boolean; // 是否容器节点
27
+ }
28
+
29
+ /**
30
+ * 节点数据
31
+ */
32
+ export interface WorkflowNodeJSON extends FlowNodeJSON {
33
+ id: string;
34
+ type: string | number;
35
+ /**
36
+ * ui 数据
37
+ */
38
+ meta?: WorkflowNodeMeta;
39
+ /**
40
+ * 表单数据
41
+ */
42
+
43
+ data?: any;
44
+ /**
45
+ * 子节点
46
+ */
47
+ blocks?: WorkflowNodeJSON[];
48
+ /**
49
+ * 子节点间连线
50
+ */
51
+ edges?: WorkflowEdgeJSON[];
52
+ }
@@ -0,0 +1,40 @@
1
+ /**
2
+ * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
3
+ * SPDX-License-Identifier: MIT
4
+ */
5
+
6
+ import { IPoint, Event } from '@flowgram-vue/utils';
7
+ import {
8
+ FlowNodeEntity,
9
+ FlowNodeEntityOrId,
10
+ FlowOperationBaseService,
11
+ } from '@flowgram-vue/document';
12
+
13
+ import { WorkflowJSON } from './workflow-json';
14
+
15
+ export interface NodePostionUpdateEvent {
16
+ node: FlowNodeEntity;
17
+ oldPosition: IPoint;
18
+ newPosition: IPoint;
19
+ }
20
+
21
+ export interface WorkflowOperationBaseService extends FlowOperationBaseService {
22
+ /**
23
+ * 节点位置更新事件
24
+ */
25
+ readonly onNodePostionUpdate: Event<NodePostionUpdateEvent>;
26
+ /**
27
+ * 更新节点位置
28
+ * @param nodeOrId
29
+ * @param position
30
+ * @returns
31
+ */
32
+ updateNodePosition(nodeOrId: FlowNodeEntityOrId, position: IPoint): void;
33
+
34
+ /**
35
+ * 更新节点与线条
36
+ */
37
+ fromJSON(json: WorkflowJSON): void;
38
+ }
39
+
40
+ export const WorkflowOperationBaseService = Symbol('WorkflowOperationBaseService');
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
3
+ * SPDX-License-Identifier: MIT
4
+ */
5
+
6
+ import type { FormMeta } from '@flowgram-vue/node';
7
+ import type { FormMetaOrFormMetaGenerator } from '@flowgram-vue/form-core';
8
+ import type { FlowNodeRegistry } from '@flowgram-vue/document';
9
+
10
+ import type { WorkflowNodeEntity, WorkflowPortEntity } from '../entities';
11
+ import type { WorkflowNodeMeta } from './workflow-node';
12
+ import type { WorkflowLinesManager } from '../workflow-lines-manager';
13
+
14
+ /**
15
+ * 节点表单引擎配置
16
+ */
17
+ export type WorkflowNodeFormMeta = FormMetaOrFormMetaGenerator | FormMeta;
18
+
19
+ /**
20
+ * 节点注册
21
+ */
22
+ export interface WorkflowNodeRegistry extends FlowNodeRegistry<WorkflowNodeMeta> {
23
+ formMeta?: WorkflowNodeFormMeta;
24
+ canAddLine?: (
25
+ fromPort: WorkflowPortEntity,
26
+ toPort: WorkflowPortEntity,
27
+ lines: WorkflowLinesManager,
28
+ silent?: boolean
29
+ ) => boolean;
30
+ }
31
+
32
+ export interface WorkflowNodeRenderProps {
33
+ node: WorkflowNodeEntity;
34
+ }
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
3
+ * SPDX-License-Identifier: MIT
4
+ */
5
+
6
+ import type { WorkflowNodeEntity } from '../entities';
7
+
8
+ /**
9
+ * 子画布配置
10
+ */
11
+ export type WorkflowSubCanvas = {
12
+ isCanvas: boolean; // 是否画布节点
13
+ parentNode: WorkflowNodeEntity; // 父节点
14
+ canvasNode: WorkflowNodeEntity; // 画布节点
15
+ };
@@ -0,0 +1,47 @@
1
+ /**
2
+ * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
3
+ * SPDX-License-Identifier: MIT
4
+ */
5
+
6
+ import { FlowNodeBaseType } from '@flowgram-vue/document';
7
+
8
+ import { WorkflowJSON, WorkflowNodeJSON } from '../typings';
9
+
10
+ interface WorkflowGroupJSON extends WorkflowNodeJSON {
11
+ data: {
12
+ parentID?: string;
13
+ blockIDs?: string[];
14
+ };
15
+ }
16
+
17
+ export const buildGroupJSON = (json: WorkflowJSON): WorkflowJSON => {
18
+ const { nodes, edges } = json;
19
+ const groupJSONs = nodes.filter(
20
+ (nodeJSON) => nodeJSON.type === FlowNodeBaseType.GROUP
21
+ ) as WorkflowGroupJSON[];
22
+
23
+ const nodeJSONMap = new Map<string, WorkflowNodeJSON>(nodes.map((n) => [n.id, n]));
24
+ const groupNodeJSONs = groupJSONs.map((groupJSON): WorkflowNodeJSON => {
25
+ const groupBlocks = (groupJSON.data.blockIDs ?? [])
26
+ .map((blockID) => nodeJSONMap.get(blockID))
27
+ .filter(Boolean) as WorkflowNodeJSON[];
28
+ const groupEdges = edges?.filter((edge) =>
29
+ groupBlocks.some((block) => block.id === edge.sourceNodeID || block.id === edge.targetNodeID)
30
+ );
31
+ const groupNodeJSON: WorkflowNodeJSON = {
32
+ ...groupJSON,
33
+ blocks: groupBlocks,
34
+ edges: groupEdges,
35
+ };
36
+ return groupNodeJSON;
37
+ });
38
+
39
+ const groupBlockSet = new Set(groupJSONs.map((groupJSON) => groupJSON.data.blockIDs).flat());
40
+ const processedNodes = nodes
41
+ .filter((nodeJSON) => !groupBlockSet.has(nodeJSON.id))
42
+ .concat(groupNodeJSONs);
43
+ return {
44
+ nodes: processedNodes,
45
+ edges,
46
+ };
47
+ };
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
3
+ * SPDX-License-Identifier: MIT
4
+ */
5
+
6
+ export { compose, composeAsync } from '@flowgram-vue/utils';
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
3
+ * SPDX-License-Identifier: MIT
4
+ */
5
+
6
+ import { Rectangle } from '@flowgram-vue/utils';
7
+ import { type PlaygroundConfigEntity, TransformData } from '@flowgram-vue/core';
8
+
9
+ import { type WorkflowDocument } from '../workflow-document';
10
+
11
+ export const fitView = (
12
+ doc: WorkflowDocument,
13
+ playgroundConfig: PlaygroundConfigEntity,
14
+ easing = true
15
+ ) => {
16
+ const bounds = Rectangle.enlarge(
17
+ doc.getAllNodes().map((node) => node.getData<TransformData>(TransformData).bounds)
18
+ );
19
+ // 留出 30 像素的边界
20
+ return playgroundConfig.fitView(bounds, easing, 30);
21
+ };
@@ -0,0 +1,45 @@
1
+ /**
2
+ * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
3
+ * SPDX-License-Identifier: MIT
4
+ */
5
+
6
+ import { FlowNodeFormData } from '@flowgram-vue/form-core';
7
+ import { FlowNodeEntity, FlowNodeJSON } from '@flowgram-vue/document';
8
+
9
+ import { type WorkflowDocument } from '../workflow-document';
10
+ import { WorkflowContentChangeType, type WorkflowNodeRegistry } from '../typings';
11
+
12
+ export function getFlowNodeFormData(node: FlowNodeEntity) {
13
+ return node.getData(FlowNodeFormData) as FlowNodeFormData;
14
+ }
15
+
16
+ export function toFormJSON(node: FlowNodeEntity) {
17
+ const formData = node.getData(FlowNodeFormData) as FlowNodeFormData;
18
+ if (!formData || !(node.getNodeRegistry() as WorkflowNodeRegistry).formMeta) return undefined;
19
+ return formData.toJSON();
20
+ }
21
+
22
+ export function initFormDataFromJSON(
23
+ node: FlowNodeEntity,
24
+ json: FlowNodeJSON,
25
+ isFirstCreate: boolean
26
+ ) {
27
+ const formData = node.getData(FlowNodeFormData) as FlowNodeFormData;
28
+ const registry = node.getNodeRegistry();
29
+ const { formMeta } = registry;
30
+
31
+ if (formData && formMeta) {
32
+ if (isFirstCreate) {
33
+ formData.createForm(formMeta, json.data);
34
+ formData.onDataChange(() => {
35
+ (node.document as WorkflowDocument).fireContentChange({
36
+ type: WorkflowContentChangeType.NODE_DATA_CHANGE,
37
+ toJSON: () => formData.toJSON(),
38
+ entity: node,
39
+ });
40
+ });
41
+ } else {
42
+ formData.updateFormValues(json.data);
43
+ }
44
+ }
45
+ }
@@ -0,0 +1,44 @@
1
+ /**
2
+ * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
3
+ * SPDX-License-Identifier: MIT
4
+ */
5
+
6
+ import { TransformData } from '@flowgram-vue/core';
7
+ import { type IPoint } from '@flowgram-vue/utils';
8
+
9
+ import { type WorkflowDocument } from '../workflow-document';
10
+ import { WorkflowNodeEntity } from '../entities';
11
+
12
+ /**
13
+ * 获取没有碰撞的位置
14
+ * 距离很小时,xy 各偏移 30
15
+ * @param position
16
+ */
17
+ export function getAntiOverlapPosition(
18
+ doc: WorkflowDocument,
19
+ position: IPoint,
20
+ containerNode?: WorkflowNodeEntity,
21
+ ): IPoint {
22
+ let { x, y } = position;
23
+ const nodes = containerNode ? containerNode.collapsedChildren : doc.getAllNodes();
24
+ const positions = nodes
25
+ .map(n => {
26
+ const transform = n.getData<TransformData>(TransformData)!;
27
+ return { x: transform.position.x, y: transform.position.y };
28
+ })
29
+ .sort((a, b) => a.y - b.y);
30
+ const minDistance = 3;
31
+ for (const pos of positions) {
32
+ const { x: posX, y: posY } = pos;
33
+ if (y - posY < -minDistance) {
34
+ break;
35
+ }
36
+ const deltaX = Math.abs(x - posX);
37
+ const deltaY = Math.abs(y - posY);
38
+ if (deltaX <= minDistance && deltaY <= minDistance) {
39
+ x += 30;
40
+ y += 30;
41
+ }
42
+ }
43
+ return { x, y };
44
+ }
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
3
+ * SPDX-License-Identifier: MIT
4
+ */
5
+
6
+ import { IPoint, Rectangle } from '@flowgram-vue/utils';
7
+
8
+ import { LineCenterPoint } from '../typings';
9
+
10
+ export function getLineCenter(
11
+ from: IPoint,
12
+ to: IPoint,
13
+ bbox: Rectangle,
14
+ linePadding: number
15
+ ): LineCenterPoint {
16
+ return {
17
+ x: bbox.center.x,
18
+ y: bbox.center.y,
19
+ labelX: bbox.center.x - bbox.x + linePadding,
20
+ labelY: bbox.center.y - bbox.y + linePadding,
21
+ };
22
+ }
@@ -0,0 +1,50 @@
1
+ /**
2
+ * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
3
+ * SPDX-License-Identifier: MIT
4
+ */
5
+
6
+ export function getUrlParams(): Record<string, string> {
7
+ const paramsMap = new Map<string, string>();
8
+
9
+ location.search
10
+ .replace(/^\?/, '')
11
+ .split('&')
12
+ .forEach((key) => {
13
+ if (!key) return;
14
+
15
+ const [k, v] = key.split('=');
16
+
17
+ if (k) {
18
+ // Decode URL-encoded parameter names and values
19
+ const decodedKey = decodeURIComponent(k.trim());
20
+ const decodedValue = v ? decodeURIComponent(v.trim()) : '';
21
+
22
+ // Prevent prototype pollution by filtering dangerous property names
23
+ const dangerousProps = [
24
+ '__proto__',
25
+ 'constructor',
26
+ 'prototype',
27
+ '__defineGetter__',
28
+ '__defineSetter__',
29
+ '__lookupGetter__',
30
+ '__lookupSetter__',
31
+ 'hasOwnProperty',
32
+ 'isPrototypeOf',
33
+ 'propertyIsEnumerable',
34
+ 'toString',
35
+ 'valueOf',
36
+ 'toLocaleString',
37
+ ];
38
+
39
+ if (dangerousProps.includes(decodedKey.toLowerCase())) {
40
+ return;
41
+ }
42
+
43
+ // Use Map to prevent prototype pollution
44
+ paramsMap.set(decodedKey, decodedValue);
45
+ }
46
+ });
47
+
48
+ // Convert Map to plain object while maintaining API compatibility
49
+ return Object.fromEntries(paramsMap);
50
+ }
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
3
+ * SPDX-License-Identifier: MIT
4
+ */
5
+
6
+ import { bindConfigEntity } from '@flowgram-vue/core';
7
+ export { delay } from '@flowgram-vue/utils';
8
+
9
+ /**
10
+ * 让 entity 可以注入到类中
11
+ *
12
+ * @example
13
+ * ```
14
+ * class SomeClass {
15
+ * @inject(PlaygroundConfigEntity) playgroundConfig: PlaygroundConfigEntity
16
+ * }
17
+ * ```
18
+ * @param bind
19
+ * @param entityRegistry
20
+ */
21
+ export { bindConfigEntity };
22
+
23
+ export { buildGroupJSON } from './build-group-json';
24
+ export { getLineCenter } from './get-line-center';
25
+ export * from './nanoid';
26
+ export * from './compose';
27
+ export * from './fit-view';
28
+ export * from './get-anti-overlap-position';
29
+ export * from './statics';
@@ -0,0 +1,65 @@
1
+ /**
2
+ * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
3
+ * SPDX-License-Identifier: MIT
4
+ */
5
+
6
+ import { type IPoint } from '@flowgram-vue/utils';
7
+ import { FlowNodeTransformData } from '@flowgram-vue/document';
8
+ import { TransformData, startTween } from '@flowgram-vue/core';
9
+
10
+ import { type WorkflowDocument } from '../workflow-document';
11
+ import { type WorkflowNodeEntity } from '../entities';
12
+
13
+ /**
14
+ * Coze 中节点坐标,以卡片顶部中间为原点。
15
+ * autoLayout 计算出来的对齐的坐标以节点正中为原点,需要上移当前节点一般高度。
16
+ * 即: newPosition.y - transform.bounds.height / 2
17
+ * bounds 的原点坐标为左上角。
18
+ */
19
+ export const layoutToPositions = async (
20
+ nodes: WorkflowNodeEntity[],
21
+ nodePositionMap: Record<string, IPoint>
22
+ ): Promise<Record<string, IPoint>> => {
23
+ // 缓存上次位置,用来还原位置
24
+ const newNodePositionMap: Record<string, IPoint> = {};
25
+ nodes.forEach((node) => {
26
+ const transform = node.getData(TransformData);
27
+ const nodeTransform = node.getData(FlowNodeTransformData);
28
+
29
+ newNodePositionMap[node.id] = {
30
+ x: transform.position.x,
31
+ y: transform.position.y + nodeTransform.bounds.height / 2,
32
+ };
33
+ });
34
+
35
+ return new Promise((resolve) => {
36
+ startTween({
37
+ from: { d: 0 },
38
+ to: { d: 100 },
39
+ duration: 300,
40
+ onUpdate: (v) => {
41
+ nodes.forEach((node) => {
42
+ const transform = node.getData(TransformData);
43
+ const deltaX = ((nodePositionMap[node.id].x - transform.position.x) * v.d) / 100;
44
+ const deltaY =
45
+ ((nodePositionMap[node.id].y - transform.bounds.height / 2 - transform.position.y) *
46
+ v.d) /
47
+ 100;
48
+
49
+ transform.update({
50
+ position: {
51
+ x: transform.position.x + deltaX,
52
+ y: transform.position.y + deltaY,
53
+ },
54
+ });
55
+
56
+ const document = node.document as WorkflowDocument;
57
+ document.layout.updateAffectedTransform(node);
58
+ });
59
+ },
60
+ onComplete: () => {
61
+ resolve(newNodePositionMap);
62
+ },
63
+ });
64
+ });
65
+ };
@@ -0,0 +1,40 @@
1
+ /**
2
+ * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
3
+ * SPDX-License-Identifier: MIT
4
+ */
5
+
6
+ import { Rectangle, IPoint } from '@flowgram-vue/utils';
7
+
8
+ import { WorkflowPort } from '../entities';
9
+
10
+ export function locationConfigToPoint(
11
+ bounds: Rectangle,
12
+ config: Required<WorkflowPort>['locationConfig'],
13
+ _offset: IPoint = { x: 0, y: 0 }
14
+ ): IPoint {
15
+ const offset = { ..._offset };
16
+ if (config.left !== undefined) {
17
+ offset.x +=
18
+ typeof config.left === 'string' ? parseFloat(config.left) * 0.01 * bounds.width : config.left;
19
+ } else if (config.right !== undefined) {
20
+ offset.x +=
21
+ bounds.width -
22
+ (typeof config.right === 'string'
23
+ ? parseFloat(config.right) * 0.01 * bounds.width
24
+ : config.right);
25
+ }
26
+ if (config.top !== undefined) {
27
+ offset.y +=
28
+ typeof config.top === 'string' ? parseFloat(config.top) * 0.01 * bounds.height : config.top;
29
+ } else if (config.bottom !== undefined) {
30
+ offset.y +=
31
+ bounds.height -
32
+ (typeof config.bottom === 'string'
33
+ ? parseFloat(config.bottom) * 0.01 * bounds.height
34
+ : config.bottom);
35
+ }
36
+ return {
37
+ x: bounds.x + offset.x,
38
+ y: bounds.y + offset.y,
39
+ };
40
+ }
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
3
+ * SPDX-License-Identifier: MIT
4
+ */
5
+
6
+ import { nanoid as nanoidOrigin } from 'nanoid';
7
+
8
+ export function nanoid(n?: number): string {
9
+ return nanoidOrigin(n);
10
+ }
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
3
+ * SPDX-License-Identifier: MIT
4
+ */
5
+
6
+ import { Rectangle } from '@flowgram-vue/utils';
7
+
8
+ import { type WorkflowNodeEntity } from '../entities/workflow-node-entity';
9
+ export type WorkflowPortType = 'input' | 'output';
10
+
11
+ export const getPortEntityIdByNodeId = (
12
+ nodeId: string,
13
+ portType: WorkflowPortType,
14
+ portID: string | number = ''
15
+ ): string => `port_${portType}_${nodeId}_${portID}`;
16
+
17
+ export const getPortEntityId = (
18
+ node: WorkflowNodeEntity,
19
+ portType: WorkflowPortType,
20
+ portID: string | number = ''
21
+ ): string => getPortEntityIdByNodeId(node.id, portType, portID);
22
+
23
+ export const WORKFLOW_LINE_ENTITY = 'WorkflowLineEntity';
24
+
25
+ export function domReactToBounds(react: DOMRect): Rectangle {
26
+ return new Rectangle(react.x, react.y, react.width, react.height);
27
+ }
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
3
+ * SPDX-License-Identifier: MIT
4
+ */
5
+
6
+ export { default as NodeRenderProvider } from './node-render-provider.vue';
@@ -0,0 +1,16 @@
1
+ <script setup lang="ts">
2
+ import { provide } from 'vue';
3
+
4
+ import { NodeRenderContextKey } from '../composables/use-node-render-context';
5
+ import type { NodeRenderReturnType } from '../composables/typings';
6
+
7
+ const props = defineProps<{
8
+ value: NodeRenderReturnType;
9
+ }>();
10
+
11
+ provide(NodeRenderContextKey, props.value);
12
+ </script>
13
+
14
+ <template>
15
+ <slot />
16
+ </template>
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
3
+ * SPDX-License-Identifier: MIT
4
+ */
5
+
6
+ export enum WorkflowCommands {
7
+ DELETE_NODES = 'DELETE_NODES',
8
+ COPY_NODES = 'COPY_NODES',
9
+ PASTE_NODES = 'PASTE_NODES',
10
+ ZOOM_IN = 'ZOOM_IN',
11
+ ZOOM_OUT = 'ZOOM_OUT',
12
+ UNDO = 'UNDO',
13
+ REDO = 'REDO',
14
+ }
@@ -0,0 +1,50 @@
1
+ /**
2
+ * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
3
+ * SPDX-License-Identifier: MIT
4
+ */
5
+
6
+ import { ContainerModule } from 'inversify';
7
+ import { bindContributions } from '@flowgram-vue/utils';
8
+ import { FlowDocument, FlowDocumentContribution } from '@flowgram-vue/document';
9
+
10
+ import { WorkflowLinesManager } from './workflow-lines-manager';
11
+ import {
12
+ WorkflowDocumentOptions,
13
+ WorkflowDocumentOptionsDefault,
14
+ } from './workflow-document-option';
15
+ import { WorkflowDocumentContribution } from './workflow-document-contribution';
16
+ import { WorkflowDocument, WorkflowDocumentProvider } from './workflow-document';
17
+ import { getUrlParams } from './utils/get-url-params';
18
+ import { URLParams, WorkflowOperationBaseService } from './typings';
19
+ import {
20
+ WorkflowDragService,
21
+ WorkflowHoverService,
22
+ WorkflowSelectService,
23
+ WorkflowResetLayoutService,
24
+ WorkflowOperationBaseServiceImpl,
25
+ } from './service';
26
+ import { FreeLayout } from './layout';
27
+
28
+ export const WorkflowDocumentContainerModule = new ContainerModule(
29
+ (bind, unbind, isBound, rebind) => {
30
+ bind(WorkflowDocument).toSelf().inSingletonScope();
31
+ bind(WorkflowLinesManager).toSelf().inSingletonScope();
32
+ bind(FreeLayout).toSelf().inSingletonScope();
33
+ bind(WorkflowDragService).toSelf().inSingletonScope();
34
+ bind(WorkflowSelectService).toSelf().inSingletonScope();
35
+ bind(WorkflowHoverService).toSelf().inSingletonScope();
36
+ bind(WorkflowResetLayoutService).toSelf().inSingletonScope();
37
+ bind(WorkflowOperationBaseService).to(WorkflowOperationBaseServiceImpl).inSingletonScope();
38
+ bind(URLParams)
39
+ .toDynamicValue(() => getUrlParams())
40
+ .inSingletonScope();
41
+ bindContributions(bind, WorkflowDocumentContribution, [FlowDocumentContribution]);
42
+ bind(WorkflowDocumentOptions).toConstantValue({
43
+ ...WorkflowDocumentOptionsDefault,
44
+ });
45
+ rebind(FlowDocument).toService(WorkflowDocument);
46
+ bind(WorkflowDocumentProvider)
47
+ .toDynamicValue((ctx) => () => ctx.container.get(WorkflowDocument))
48
+ .inSingletonScope();
49
+ }
50
+ );