@flowgram-vue/document 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 (42) hide show
  1. package/LICENSE +22 -0
  2. package/dist/index.cjs +3233 -0
  3. package/dist/index.cjs.map +1 -0
  4. package/dist/index.d.ts +1728 -0
  5. package/dist/index.js +3199 -0
  6. package/dist/index.js.map +1 -0
  7. package/package.json +61 -0
  8. package/src/datas/flow-node-render-data.ts +227 -0
  9. package/src/datas/flow-node-transform-data.ts +337 -0
  10. package/src/datas/flow-node-transition-data.ts +182 -0
  11. package/src/datas/index.ts +8 -0
  12. package/src/entities/flow-document-transformer-entity.ts +125 -0
  13. package/src/entities/flow-node-entity.ts +415 -0
  14. package/src/entities/flow-renderer-state-entity.ts +127 -0
  15. package/src/entities/index.ts +8 -0
  16. package/src/flow-document-config.ts +42 -0
  17. package/src/flow-document-container-module.ts +33 -0
  18. package/src/flow-document-contribution.ts +22 -0
  19. package/src/flow-document-options.ts +79 -0
  20. package/src/flow-document.ts +766 -0
  21. package/src/flow-render-tree.ts +236 -0
  22. package/src/flow-virtual-tree.ts +244 -0
  23. package/src/index.ts +16 -0
  24. package/src/layout/horizontal-fixed-layout.ts +198 -0
  25. package/src/layout/index.ts +7 -0
  26. package/src/layout/vertical-fixed-layout.ts +198 -0
  27. package/src/services/flow-drag-service.ts +211 -0
  28. package/src/services/flow-group-service/flow-group-controller.ts +120 -0
  29. package/src/services/flow-group-service/flow-group-service.ts +107 -0
  30. package/src/services/flow-group-service/flow-group-utils.ts +104 -0
  31. package/src/services/flow-group-service/index.ts +7 -0
  32. package/src/services/flow-operation-base-service.ts +333 -0
  33. package/src/services/index.ts +8 -0
  34. package/src/typings/flow-group.ts +8 -0
  35. package/src/typings/flow-layout.ts +72 -0
  36. package/src/typings/flow-node-register.ts +356 -0
  37. package/src/typings/flow-operation.ts +312 -0
  38. package/src/typings/flow-transition.ts +104 -0
  39. package/src/typings/flow.ts +70 -0
  40. package/src/typings/index.ts +11 -0
  41. package/src/utils/get-default-spacing.ts +21 -0
  42. package/src/utils/index.ts +6 -0
@@ -0,0 +1,415 @@
1
+ /**
2
+ * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
3
+ * SPDX-License-Identifier: MIT
4
+ */
5
+
6
+ import { Event, type Rectangle } from '@flowgram-vue/utils';
7
+ import { Entity, type EntityOpts } from '@flowgram-vue/core';
8
+
9
+ import {
10
+ FlowLayoutDefault,
11
+ FlowNodeJSON,
12
+ FlowNodeMeta,
13
+ FlowNodeRegistry,
14
+ FlowNodeType,
15
+ } from '../typings';
16
+ import type { FlowDocument } from '../flow-document';
17
+ import { FlowNodeRenderData, FlowNodeTransformData } from '../datas';
18
+
19
+ export interface FlowNodeEntityConfig extends EntityOpts {
20
+ document: FlowDocument;
21
+ flowNodeType: FlowNodeType;
22
+ originParent?: FlowNodeEntity;
23
+ meta?: FlowNodeMeta;
24
+ }
25
+
26
+ export interface FlowNodeInitData {
27
+ originParent?: FlowNodeEntity;
28
+ parent?: FlowNodeEntity;
29
+ hidden?: boolean;
30
+ meta?: FlowNodeMeta;
31
+ index?: number;
32
+ }
33
+
34
+ export class FlowNodeEntity extends Entity<FlowNodeEntityConfig> {
35
+ private _memoLocalCache = new Map<string, any>();
36
+
37
+ private _memoGlobalCache = new Map<string, any>();
38
+
39
+ static type = 'FlowNodeEntity';
40
+
41
+ private _registerCache?: FlowNodeRegistry;
42
+
43
+ private _metaCache?: Required<FlowNodeMeta>;
44
+
45
+ metaFromJSON?: FlowNodeMeta;
46
+
47
+ /**
48
+ * 真实的父节点,条件块在内部会创建一些空的块节点,这些块需要关联它真实的父亲节点
49
+ */
50
+ originParent?: FlowNodeEntity;
51
+
52
+ flowNodeType: FlowNodeType = 'unknown'; // 流程类型
53
+
54
+ /**
55
+ * 是否隐藏
56
+ */
57
+ private _hidden = false;
58
+
59
+ index = -1;
60
+
61
+ /**
62
+ * 文档引用
63
+ */
64
+ document: FlowDocument;
65
+
66
+ constructor(conf: FlowNodeEntityConfig) {
67
+ super(conf);
68
+ this.document = conf.document;
69
+ this.flowNodeType = conf.flowNodeType;
70
+ this.originParent = conf.originParent;
71
+ this.metaFromJSON = conf.meta;
72
+ this.onDispose(() => {
73
+ this.document.originTree
74
+ .getChildren(this)
75
+ .slice()
76
+ .forEach((child) => {
77
+ child.dispose();
78
+ });
79
+ this.document.originTree.remove(this, false);
80
+ this.originParent = undefined;
81
+ });
82
+ }
83
+
84
+ initData(initConf: FlowNodeInitData): void {
85
+ if (initConf.originParent !== this.originParent) {
86
+ this.originParent = initConf.originParent;
87
+ this._registerCache = undefined;
88
+ }
89
+ if (initConf.parent) {
90
+ initConf.parent.addChild(this, initConf.index);
91
+ }
92
+ // TODO 这个 meta 不会触发 data 数据更新
93
+ if (initConf.meta !== this.metaFromJSON) {
94
+ this._metaCache = undefined;
95
+ this.metaFromJSON = initConf.meta;
96
+ }
97
+ this._hidden = !!(this.getNodeMeta().hidden || initConf.hidden);
98
+ }
99
+
100
+ get isStart(): boolean {
101
+ return this.getNodeMeta().isStart;
102
+ }
103
+
104
+ get isFirst(): boolean {
105
+ return !this.pre;
106
+ }
107
+
108
+ get isLast(): boolean {
109
+ return !this.next;
110
+ }
111
+
112
+ /**
113
+ * 子节点采用水平布局
114
+ */
115
+ get isInlineBlocks(): boolean {
116
+ const originIsInlineBlocks = this.getNodeMeta().isInlineBlocks;
117
+ return typeof originIsInlineBlocks === 'function'
118
+ ? originIsInlineBlocks(this)
119
+ : originIsInlineBlocks;
120
+ }
121
+
122
+ /**
123
+ * 水平节点
124
+ */
125
+ get isInlineBlock(): boolean {
126
+ const parent = this.document.renderTree.getParent(this);
127
+ return !!(parent && parent.isInlineBlocks);
128
+ }
129
+
130
+ /**
131
+ * 节点结束标记
132
+ * - 当前节点是结束节点
133
+ * - 当前节点最后一个节点包含结束标记
134
+ * - 当前节点为 inlineBlock,每一个 block 包含结束标记
135
+ *
136
+ * 由子元素确定,因此使用 memoLocal
137
+ */
138
+ get isNodeEnd(): boolean {
139
+ return this.memoLocal<boolean>('isNodeEnd', () => {
140
+ if (this.getNodeMeta().isNodeEnd) {
141
+ return true;
142
+ }
143
+
144
+ if (this.isInlineBlocks && this.collapsedChildren.length) {
145
+ return this.collapsedChildren.every((child) => child.isNodeEnd);
146
+ }
147
+
148
+ if (this.lastCollapsedChild) {
149
+ return this.lastCollapsedChild.isNodeEnd;
150
+ }
151
+
152
+ return false;
153
+ });
154
+ }
155
+
156
+ /**
157
+ * 添加 子节点
158
+ *
159
+ * @param child 插入节点
160
+ */
161
+ addChild(child: FlowNodeEntity, index?: number) {
162
+ if (child.parent === this) return;
163
+ this.document.originTree.addChild(this, child, index);
164
+ }
165
+
166
+ get hasChild(): boolean {
167
+ return this.children.length > 0;
168
+ }
169
+
170
+ get pre(): FlowNodeEntity | undefined {
171
+ return this.document.renderTree.getPre(this);
172
+ }
173
+
174
+ get next(): FlowNodeEntity | undefined {
175
+ return this.document.renderTree.getNext(this);
176
+ }
177
+
178
+ get parent(): FlowNodeEntity | undefined {
179
+ return this.document.renderTree.getParent(this);
180
+ }
181
+
182
+ getNodeRegistry<M extends FlowNodeRegistry = FlowNodeRegistry & { meta: FlowNodeMeta }>(): M {
183
+ if (this._registerCache) return this._registerCache as M;
184
+ this._registerCache = this.document.getNodeRegistry(this.flowNodeType, this.originParent);
185
+ return this._registerCache as M;
186
+ }
187
+
188
+ /**
189
+ * @deprecated
190
+ * use getNodeRegistry instead
191
+ */
192
+ getNodeRegister<M extends FlowNodeRegistry = FlowNodeRegistry>(): M {
193
+ return this.getNodeRegistry<M>();
194
+ }
195
+
196
+ getNodeMeta<M extends FlowNodeMeta = FlowNodeMeta>(): M & Required<FlowNodeMeta> {
197
+ if (this._metaCache) return this._metaCache as M & Required<FlowNodeMeta>;
198
+ if (this.metaFromJSON) {
199
+ this._metaCache = {
200
+ ...this.getNodeRegistry().meta,
201
+ ...this.metaFromJSON,
202
+ } as M & Required<FlowNodeMeta>;
203
+ } else {
204
+ this._metaCache = this.getNodeRegistry().meta as M & Required<FlowNodeMeta>;
205
+ }
206
+ return this._metaCache as M & Required<FlowNodeMeta>;
207
+ }
208
+
209
+ /**
210
+ * 获取所有子节点,包含 child 及其所有兄弟节点
211
+ */
212
+ get allChildren(): FlowNodeEntity[] {
213
+ const children: FlowNodeEntity[] = [];
214
+ for (const child of this.children) {
215
+ children.push(child);
216
+ children.push(...child.allChildren);
217
+ }
218
+ return children;
219
+ }
220
+
221
+ /**
222
+ * 获取所有收起的子节点,包含 child 及其所有兄弟节点
223
+ */
224
+ get allCollapsedChildren(): FlowNodeEntity[] {
225
+ const children: FlowNodeEntity[] = [];
226
+ for (const child of this.collapsedChildren) {
227
+ children.push(child);
228
+ children.push(...child.allCollapsedChildren);
229
+ }
230
+ return children;
231
+ }
232
+
233
+ /**
234
+ *
235
+ * Get child blocks
236
+ *
237
+ * use `blocks` instead
238
+ * @deprecated
239
+ */
240
+
241
+ get collapsedChildren(): FlowNodeEntity[] {
242
+ return this.document.renderTree.getCollapsedChildren(this);
243
+ }
244
+
245
+ /**
246
+ * Get child blocks
247
+ */
248
+ get blocks(): FlowNodeEntity[] {
249
+ return this.collapsedChildren;
250
+ }
251
+
252
+ /**
253
+ * Get last block
254
+ */
255
+ get lastBlock(): FlowNodeEntity | undefined {
256
+ return this.lastCollapsedChild;
257
+ }
258
+
259
+ /**
260
+ * use `lastBlock` instead
261
+ */
262
+ get lastCollapsedChild(): FlowNodeEntity | undefined {
263
+ const { collapsedChildren } = this;
264
+ return collapsedChildren[collapsedChildren.length - 1];
265
+ }
266
+
267
+ /**
268
+ * 获取子节点,如果子节点收起来,则会返回 空数组
269
+ */
270
+ get children(): FlowNodeEntity[] {
271
+ return this.document.renderTree.getChildren(this);
272
+ }
273
+
274
+ get lastChild(): FlowNodeEntity | undefined {
275
+ const { children } = this;
276
+ return children[children.length - 1];
277
+ }
278
+
279
+ get firstChild(): FlowNodeEntity | undefined {
280
+ return this.children[0];
281
+ }
282
+
283
+ memoLocal<T>(key: string, fn: () => T): T {
284
+ if (this._memoLocalCache.has(key)) {
285
+ return this._memoLocalCache.get(key) as T;
286
+ }
287
+ const data = fn();
288
+ this._memoLocalCache.set(key, data);
289
+ return data as T;
290
+ }
291
+
292
+ memoGlobal<T>(key: string, fn: () => T): T {
293
+ if (this._memoGlobalCache.has(key)) {
294
+ return this._memoGlobalCache.get(key) as T;
295
+ }
296
+ const data = fn();
297
+ this._memoGlobalCache.set(key, data);
298
+ return data as T;
299
+ }
300
+
301
+ clearMemoGlobal() {
302
+ this._memoGlobalCache.clear();
303
+ }
304
+
305
+ clearMemoLocal() {
306
+ this._memoLocalCache.clear();
307
+ }
308
+
309
+ get childrenLength() {
310
+ return this.children.length;
311
+ }
312
+
313
+ get collapsed(): boolean {
314
+ if (this.document.renderTree.isCollapsed(this)) return true;
315
+ return !!this.parent?.collapsed;
316
+ }
317
+
318
+ set collapsed(collapsed) {
319
+ this.document.renderTree.setCollapsed(this, collapsed);
320
+ this.clearMemoGlobal();
321
+ this.clearMemoLocal();
322
+ }
323
+
324
+ get hidden(): boolean {
325
+ return this._hidden;
326
+ }
327
+
328
+ // 展开该节点
329
+ openInsideCollapsed() {
330
+ this.document.renderTree.openNodeInsideCollapsed(this);
331
+ }
332
+
333
+ /**
334
+ * 可以重载
335
+ */
336
+ getJSONData(): any {
337
+ return this.getExtInfo();
338
+ }
339
+
340
+ /**
341
+ * 生成 JSON
342
+ * @param newId
343
+ */
344
+ toJSON(): FlowNodeJSON {
345
+ return this.document.toNodeJSON(this);
346
+ }
347
+
348
+ get isVertical(): boolean {
349
+ return this.document.layout.name === FlowLayoutDefault.VERTICAL_FIXED_LAYOUT;
350
+ }
351
+
352
+ /**
353
+ * 修改节点扩展信息
354
+ * @param info
355
+ */
356
+ updateExtInfo<T extends Record<string, any> = Record<string, any>>(
357
+ extInfo: T,
358
+ fullUpdate?: boolean
359
+ ): void {
360
+ this.getData(FlowNodeRenderData).updateExtInfo(extInfo, fullUpdate);
361
+ }
362
+
363
+ /**
364
+ * 获取节点扩展信息
365
+ */
366
+ getExtInfo<T extends Record<string, any> = Record<string, any>>(): T {
367
+ return this.getData<FlowNodeRenderData>(FlowNodeRenderData).getExtInfo() as T;
368
+ }
369
+
370
+ get onExtInfoChange(): Event<{ newInfo: any; oldInfo: any }> {
371
+ return this.renderData.onExtInfoChange;
372
+ }
373
+
374
+ /**
375
+ * 获取渲染数据
376
+ */
377
+ get renderData(): FlowNodeRenderData {
378
+ return this.getData(FlowNodeRenderData);
379
+ }
380
+
381
+ /**
382
+ * 获取位置大小数据
383
+ */
384
+ get transform(): FlowNodeTransformData {
385
+ return this.getData(FlowNodeTransformData);
386
+ }
387
+
388
+ /**
389
+ * 获取节点的位置及大小矩形
390
+ */
391
+ get bounds(): Rectangle {
392
+ return this.transform.bounds;
393
+ }
394
+
395
+ /**
396
+ * Check node extend type
397
+ */
398
+ isExtend(parentType: FlowNodeType): boolean {
399
+ return this.document.isExtend(this.flowNodeType, parentType);
400
+ }
401
+
402
+ /**
403
+ * Check node type
404
+ * @param parentType
405
+ */
406
+ isTypeOrExtendType(parentType: FlowNodeType): boolean {
407
+ return this.document.isTypeOrExtendType(this.flowNodeType, parentType);
408
+ }
409
+ }
410
+
411
+ export namespace FlowNodeEntity {
412
+ export function is(obj: Entity): obj is FlowNodeEntity {
413
+ return obj instanceof FlowNodeEntity;
414
+ }
415
+ }
@@ -0,0 +1,127 @@
1
+ /**
2
+ * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
3
+ * SPDX-License-Identifier: MIT
4
+ */
5
+
6
+ import { debounce } from 'lodash-es';
7
+ import { type Disposable } from '@flowgram-vue/utils';
8
+ import { ConfigEntity, type EntityOpts } from '@flowgram-vue/core';
9
+
10
+ import { LABEL_SIDE_TYPE } from '../typings';
11
+ import { type FlowNodeEntity } from './flow-node-entity';
12
+
13
+ interface FlowRendererStateEntityConfig extends EntityOpts {}
14
+
15
+ interface FlowRendererState {
16
+ nodeHoveredId?: string;
17
+ nodeDroppingId?: string;
18
+ nodeDragStartId?: string;
19
+ nodeDragIds?: string[]; // 框选批量拖拽
20
+ nodeDragIdsWithChildren?: string[]; // 批量拖拽(含子节点)
21
+ dragLabelSide?: LABEL_SIDE_TYPE;
22
+ dragging?: boolean;
23
+ isBranch?: boolean;
24
+ }
25
+ /**
26
+ * 渲染相关的全局状态管理
27
+ */
28
+ export class FlowRendererStateEntity extends ConfigEntity<
29
+ FlowRendererState,
30
+ FlowRendererStateEntityConfig
31
+ > {
32
+ static type = 'FlowRendererStateEntity';
33
+
34
+ getDefaultConfig() {
35
+ return {};
36
+ }
37
+
38
+ constructor(conf: FlowRendererStateEntityConfig) {
39
+ super(conf);
40
+ }
41
+
42
+ getNodeHovered(): FlowNodeEntity | undefined {
43
+ return this.config.nodeHoveredId
44
+ ? this.entityManager.getEntityById(this.config.nodeHoveredId)
45
+ : undefined;
46
+ }
47
+
48
+ setNodeHovered(node: FlowNodeEntity | undefined): void {
49
+ this.updateConfig({
50
+ nodeHoveredId: node?.id,
51
+ });
52
+ }
53
+
54
+ get dragging() {
55
+ return this.config.dragging;
56
+ }
57
+
58
+ setDragging(dragging: boolean) {
59
+ this.updateConfig({
60
+ dragging,
61
+ });
62
+ }
63
+
64
+ get isBranch() {
65
+ return this.config.isBranch;
66
+ }
67
+
68
+ setIsBranch(isBranch: boolean) {
69
+ this.updateConfig({
70
+ isBranch,
71
+ });
72
+ }
73
+
74
+ getDragLabelSide(): LABEL_SIDE_TYPE | undefined {
75
+ return this.config.dragLabelSide;
76
+ }
77
+
78
+ setDragLabelSide(dragLabelSide?: LABEL_SIDE_TYPE): void {
79
+ this.updateConfig({
80
+ dragLabelSide,
81
+ });
82
+ }
83
+
84
+ getNodeDroppingId(): string | undefined {
85
+ return this.config.nodeDroppingId;
86
+ }
87
+
88
+ setNodeDroppingId(nodeDroppingId?: string): void {
89
+ this.updateConfig({
90
+ nodeDroppingId,
91
+ });
92
+ }
93
+
94
+ getDragStartEntity(): FlowNodeEntity | undefined {
95
+ const { nodeDragStartId } = this.config;
96
+ return this.entityManager.getEntityById(nodeDragStartId!);
97
+ }
98
+
99
+ setDragStartEntity(node?: FlowNodeEntity): void {
100
+ this.updateConfig({
101
+ nodeDragStartId: node?.id,
102
+ });
103
+ }
104
+
105
+ // 拖拽多个节点时
106
+ getDragEntities(): FlowNodeEntity[] {
107
+ const { nodeDragIds } = this.config;
108
+ return (nodeDragIds || []).map((_id) => this.entityManager.getEntityById(_id)!);
109
+ }
110
+
111
+ // 设置拖拽的节点
112
+ setDragEntities(nodes: FlowNodeEntity[]): void {
113
+ this.updateConfig({
114
+ nodeDragIds: nodes.map((_node) => _node.id),
115
+ nodeDragIdsWithChildren: nodes
116
+ .map((_node) => [_node.id, ..._node.allCollapsedChildren.map((_n) => _n.id)])
117
+ .flat(),
118
+ });
119
+ }
120
+
121
+ onNodeHoveredChange(
122
+ fn: (hoveredNode: FlowNodeEntity | undefined) => void,
123
+ debounceTime = 100 // 延迟执行避免频繁 hover
124
+ ): Disposable {
125
+ return this.onConfigChanged(debounce(() => fn(this.getNodeHovered()), debounceTime));
126
+ }
127
+ }
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
3
+ * SPDX-License-Identifier: MIT
4
+ */
5
+
6
+ export * from './flow-node-entity';
7
+ export * from './flow-document-transformer-entity';
8
+ export * from './flow-renderer-state-entity';
@@ -0,0 +1,42 @@
1
+ /**
2
+ * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
3
+ * SPDX-License-Identifier: MIT
4
+ */
5
+
6
+ import { inject, injectable, optional } from 'inversify';
7
+ import { Emitter } from '@flowgram-vue/utils';
8
+
9
+ export const FlowDocumentConfigDefaultData = Symbol('FlowDocumentConfigDefaultData');
10
+
11
+ /**
12
+ * 用于文档扩展配置
13
+ */
14
+ @injectable()
15
+ export class FlowDocumentConfig {
16
+ private onDataChangeEmitter = new Emitter<string>();
17
+
18
+ readonly onChange = this.onDataChangeEmitter.event;
19
+
20
+ constructor(
21
+ @inject(FlowDocumentConfigDefaultData)
22
+ @optional()
23
+ private _data: Record<string, any> = {},
24
+ ) {}
25
+
26
+ get(key: string): any {
27
+ return this._data[key];
28
+ }
29
+
30
+ set(key: string, value: any): void {
31
+ if (this.get(key) !== value) {
32
+ this._data[key] = value;
33
+ this.onDataChangeEmitter.fire(key);
34
+ }
35
+ }
36
+
37
+ registerConfigs(config: Record<string, any>) {
38
+ Object.keys(config).forEach(key => {
39
+ this.set(key, config[key]);
40
+ });
41
+ }
42
+ }
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
3
+ * SPDX-License-Identifier: MIT
4
+ */
5
+
6
+ import { ContainerModule } from 'inversify';
7
+
8
+ import { FlowOperationBaseService } from './typings/flow-operation';
9
+ import { FlowDragService } from './services/flow-drag-service';
10
+ import { FlowGroupService, FlowOperationBaseServiceImpl } from './services';
11
+ import { HorizontalFixedLayout, VerticalFixedLayout } from './layout';
12
+ import { FlowDocumentContribution } from './flow-document-contribution';
13
+ import { FlowDocumentConfig } from './flow-document-config';
14
+ import { FlowDocument, FlowDocumentProvider } from './flow-document';
15
+
16
+ export const FlowDocumentContainerModule = new ContainerModule((bind) => {
17
+ bind(FlowDocument).toSelf().inSingletonScope();
18
+ bind(FlowDocumentProvider)
19
+ .toDynamicValue((ctx) => () => ctx.container.get(FlowDocument))
20
+ .inSingletonScope();
21
+ bind(FlowDocumentConfig).toSelf().inSingletonScope();
22
+ bind(VerticalFixedLayout).toSelf().inSingletonScope();
23
+ bind(HorizontalFixedLayout).toSelf().inSingletonScope();
24
+ bind(FlowDragService).toSelf().inSingletonScope();
25
+ bind(FlowOperationBaseService).to(FlowOperationBaseServiceImpl).inSingletonScope();
26
+ bind(FlowGroupService).toSelf().inSingletonScope();
27
+ bind(FlowDocumentContribution).toDynamicValue((ctx) => ({
28
+ registerDocument: (document: FlowDocument) => {
29
+ document.registerLayout(ctx.container.get(VerticalFixedLayout));
30
+ document.registerLayout(ctx.container.get(HorizontalFixedLayout));
31
+ },
32
+ }));
33
+ });
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
3
+ * SPDX-License-Identifier: MIT
4
+ */
5
+
6
+ import { type FlowDocument } from './flow-document';
7
+
8
+ export const FlowDocumentContribution = Symbol('FlowDocumentContribution');
9
+
10
+ export interface FlowDocumentContribution<T extends FlowDocument = FlowDocument> {
11
+ /**
12
+ * 注册
13
+ * @param document
14
+ */
15
+ registerDocument?(document: T): void;
16
+
17
+ /**
18
+ * 加载数据
19
+ * @param document
20
+ */
21
+ loadDocument?(document: T): Promise<void>;
22
+ }