@flowgram-vue/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 (133) 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/package.json +63 -0
  8. package/src/common/config-entity.ts +80 -0
  9. package/src/common/entity-data.ts +171 -0
  10. package/src/common/entity-manager-contribution.ts +12 -0
  11. package/src/common/entity-manager.ts +475 -0
  12. package/src/common/entity.ts +482 -0
  13. package/src/common/index.ts +22 -0
  14. package/src/common/playground-context.ts +35 -0
  15. package/src/common/playground-decorator-helper.ts +113 -0
  16. package/src/common/playground-decorators.ts +85 -0
  17. package/src/common/playground-schedule.ts +30 -0
  18. package/src/common/protect-wheel-area.ts +11 -0
  19. package/src/common/schema/index.ts +14 -0
  20. package/src/common/schema/node.ts +15 -0
  21. package/src/common/schema/opacity-schema.ts +19 -0
  22. package/src/common/schema/origin-schema.ts +35 -0
  23. package/src/common/schema/position-schema.ts +35 -0
  24. package/src/common/schema/rotation-schema.ts +19 -0
  25. package/src/common/schema/scale-schema.ts +35 -0
  26. package/src/common/schema/size-schema.ts +42 -0
  27. package/src/common/schema/skew-schema.ts +35 -0
  28. package/src/common/schema/transform-schema.ts +613 -0
  29. package/src/common/utils/bounds.spec.ts +229 -0
  30. package/src/common/utils/bounds.ts +176 -0
  31. package/src/common/utils/index.ts +6 -0
  32. package/src/composables/index.ts +16 -0
  33. package/src/composables/use-config-entity.ts +31 -0
  34. package/src/composables/use-entities.ts +26 -0
  35. package/src/composables/use-entity-data-from-context.ts +34 -0
  36. package/src/composables/use-entity-from-context.ts +31 -0
  37. package/src/composables/use-listen-events.ts +22 -0
  38. package/src/composables/use-playground-container.ts +16 -0
  39. package/src/composables/use-playground-context.ts +15 -0
  40. package/src/composables/use-playground-drag.ts +31 -0
  41. package/src/composables/use-playground.ts +16 -0
  42. package/src/composables/use-refresh.ts +6 -0
  43. package/src/composables/use-service.ts +17 -0
  44. package/src/core/index.ts +8 -0
  45. package/src/core/layer/config/editor-state-config-entity.ts +180 -0
  46. package/src/core/layer/config/index.ts +7 -0
  47. package/src/core/layer/config/playground-config-entity.ts +604 -0
  48. package/src/core/layer/index.ts +8 -0
  49. package/src/core/layer/layer.ts +248 -0
  50. package/src/core/layer/playground-layer.ts +547 -0
  51. package/src/core/pipeline/index.ts +10 -0
  52. package/src/core/pipeline/pipeline-entities-selector.ts +200 -0
  53. package/src/core/pipeline/pipeline-entities.ts +230 -0
  54. package/src/core/pipeline/pipeline-registry.ts +344 -0
  55. package/src/core/pipeline/pipeline-renderer.ts +248 -0
  56. package/src/core/pipeline/pipeline-vue-utils.ts +96 -0
  57. package/src/core/pipeline/pipeline.ts +28 -0
  58. package/src/core/utils/index.ts +12 -0
  59. package/src/core/utils/inject-provider-decorators.ts +27 -0
  60. package/src/core/utils/lazy-inject-decorators.ts +38 -0
  61. package/src/core/utils/mouse-touch-event.ts +120 -0
  62. package/src/core/utils/playground-drag.ts +511 -0
  63. package/src/core/utils/playground-gesture.spec.ts +135 -0
  64. package/src/core/utils/playground-gesture.ts +118 -0
  65. package/src/core/utils/tween.ts +156 -0
  66. package/src/core/utils/use-gesture/core/Controller.ts +212 -0
  67. package/src/core/utils/use-gesture/core/EventStore.ts +46 -0
  68. package/src/core/utils/use-gesture/core/TimeoutStore.ts +28 -0
  69. package/src/core/utils/use-gesture/core/actions.ts +63 -0
  70. package/src/core/utils/use-gesture/core/config/commonConfigResolver.ts +86 -0
  71. package/src/core/utils/use-gesture/core/config/coordinatesConfigResolver.ts +48 -0
  72. package/src/core/utils/use-gesture/core/config/dragConfigResolver.ts +140 -0
  73. package/src/core/utils/use-gesture/core/config/hoverConfigResolver.ts +11 -0
  74. package/src/core/utils/use-gesture/core/config/moveConfigResolver.ts +11 -0
  75. package/src/core/utils/use-gesture/core/config/pinchConfigResolver.ts +59 -0
  76. package/src/core/utils/use-gesture/core/config/resolver.ts +70 -0
  77. package/src/core/utils/use-gesture/core/config/scrollConfigResolver.ts +8 -0
  78. package/src/core/utils/use-gesture/core/config/sharedConfigResolver.ts +28 -0
  79. package/src/core/utils/use-gesture/core/config/support.ts +52 -0
  80. package/src/core/utils/use-gesture/core/config/wheelConfigResolver.ts +8 -0
  81. package/src/core/utils/use-gesture/core/engines/CoordinatesEngine.ts +78 -0
  82. package/src/core/utils/use-gesture/core/engines/DragEngine.ts +403 -0
  83. package/src/core/utils/use-gesture/core/engines/Engine.ts +406 -0
  84. package/src/core/utils/use-gesture/core/engines/HoverEngine.ts +43 -0
  85. package/src/core/utils/use-gesture/core/engines/MoveEngine.ts +52 -0
  86. package/src/core/utils/use-gesture/core/engines/PinchEngine.ts +345 -0
  87. package/src/core/utils/use-gesture/core/engines/ScrollEngine.ts +42 -0
  88. package/src/core/utils/use-gesture/core/engines/WheelEngine.ts +48 -0
  89. package/src/core/utils/use-gesture/core/index.ts +7 -0
  90. package/src/core/utils/use-gesture/core/parser.ts +92 -0
  91. package/src/core/utils/use-gesture/core/types/action.ts +19 -0
  92. package/src/core/utils/use-gesture/core/types/config.ts +255 -0
  93. package/src/core/utils/use-gesture/core/types/handlers.ts +73 -0
  94. package/src/core/utils/use-gesture/core/types/index.ts +11 -0
  95. package/src/core/utils/use-gesture/core/types/internalConfig.ts +80 -0
  96. package/src/core/utils/use-gesture/core/types/state.ts +275 -0
  97. package/src/core/utils/use-gesture/core/types/utils.ts +204 -0
  98. package/src/core/utils/use-gesture/core/types.ts +8 -0
  99. package/src/core/utils/use-gesture/core/utils/events.ts +158 -0
  100. package/src/core/utils/use-gesture/core/utils/fn.ts +32 -0
  101. package/src/core/utils/use-gesture/core/utils/maths.ts +63 -0
  102. package/src/core/utils/use-gesture/core/utils/state.ts +24 -0
  103. package/src/core/utils/use-gesture/core/utils.ts +8 -0
  104. package/src/core/utils/use-gesture/index.ts +6 -0
  105. package/src/core/utils/use-gesture/vanilla/DragGesture.ts +27 -0
  106. package/src/core/utils/use-gesture/vanilla/Gesture.ts +45 -0
  107. package/src/core/utils/use-gesture/vanilla/HoverGesture.ts +27 -0
  108. package/src/core/utils/use-gesture/vanilla/MoveGesture.ts +27 -0
  109. package/src/core/utils/use-gesture/vanilla/PinchGesture.ts +27 -0
  110. package/src/core/utils/use-gesture/vanilla/Recognizer.ts +43 -0
  111. package/src/core/utils/use-gesture/vanilla/ScrollGesture.ts +27 -0
  112. package/src/core/utils/use-gesture/vanilla/WheelGesture.ts +27 -0
  113. package/src/core/utils/use-gesture/vanilla/createGesture.ts +18 -0
  114. package/src/core/utils/use-gesture/vanilla/index.ts +18 -0
  115. package/src/env.d.ts +10 -0
  116. package/src/index.ts +17 -0
  117. package/src/playground-config.ts +70 -0
  118. package/src/playground-container.ts +129 -0
  119. package/src/playground-contribution.ts +81 -0
  120. package/src/playground-mock-tools.ts +143 -0
  121. package/src/playground.ts +401 -0
  122. package/src/plugin/index.ts +6 -0
  123. package/src/plugin/plugin.ts +226 -0
  124. package/src/services/clipboard-service.ts +40 -0
  125. package/src/services/context-menu-service.ts +25 -0
  126. package/src/services/index.ts +10 -0
  127. package/src/services/logger-service.ts +49 -0
  128. package/src/services/selection-service.ts +54 -0
  129. package/src/services/storage-service.ts +65 -0
  130. package/src/vue/index.ts +8 -0
  131. package/src/vue/playground-vue-context.ts +22 -0
  132. package/src/vue/playground-vue-provider.ts +115 -0
  133. package/src/vue/playground-vue-renderer.vue +44 -0
@@ -0,0 +1,43 @@
1
+ /**
2
+ * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
3
+ * SPDX-License-Identifier: MIT
4
+ */
5
+
6
+ import { GestureKey, InternalHandlers, NativeHandlers, UserGestureConfig } from '../core/types';
7
+ import { Controller } from '../core';
8
+
9
+ export class Recognizer<GK extends GestureKey | undefined = undefined> {
10
+ private _gestureKey?: GK;
11
+
12
+ private _ctrl: Controller;
13
+
14
+ private _target: EventTarget;
15
+
16
+ constructor(
17
+ target: EventTarget,
18
+ handlers: InternalHandlers,
19
+ config: GK extends keyof UserGestureConfig ? UserGestureConfig[GK] : UserGestureConfig,
20
+ gestureKey?: GK,
21
+ nativeHandlers?: NativeHandlers,
22
+ ) {
23
+ this._target = target;
24
+ this._gestureKey = gestureKey;
25
+ this._ctrl = new Controller(handlers);
26
+ this._ctrl.applyHandlers(handlers, nativeHandlers);
27
+ this._ctrl.applyConfig({ ...config, target }, gestureKey);
28
+
29
+ this._ctrl.effect();
30
+ }
31
+
32
+ destroy() {
33
+ this._ctrl.clean();
34
+ }
35
+
36
+ setConfig(
37
+ config: GK extends keyof UserGestureConfig ? UserGestureConfig[GK] : UserGestureConfig,
38
+ ) {
39
+ this._ctrl.clean();
40
+ this._ctrl.applyConfig({ ...config, target: this._target }, this._gestureKey);
41
+ this._ctrl.effect();
42
+ }
43
+ }
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
3
+ * SPDX-License-Identifier: MIT
4
+ */
5
+
6
+ import { UserScrollConfig, Handler, EventTypes } from '../core/types';
7
+ import { registerAction, scrollAction } from '../core/actions';
8
+ import { Recognizer } from './Recognizer';
9
+
10
+ interface ScrollGestureConstructor {
11
+ new <EventType = EventTypes['scroll']>(
12
+ target: EventTarget,
13
+ handler: Handler<'scroll', EventType>,
14
+ config?: UserScrollConfig,
15
+ ): ScrollGesture;
16
+ }
17
+
18
+ export interface ScrollGesture extends Recognizer<'scroll'> {}
19
+
20
+ export const ScrollGesture: ScrollGestureConstructor = function <EventType = EventTypes['scroll']>(
21
+ target: EventTarget,
22
+ handler: Handler<'scroll', EventType>,
23
+ config?: UserScrollConfig,
24
+ ) {
25
+ registerAction(scrollAction);
26
+ return new Recognizer(target, { scroll: handler }, config || {}, 'scroll');
27
+ } as any;
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
3
+ * SPDX-License-Identifier: MIT
4
+ */
5
+
6
+ import { UserWheelConfig, Handler, EventTypes } from '../core/types';
7
+ import { registerAction, wheelAction } from '../core/actions';
8
+ import { Recognizer } from './Recognizer';
9
+
10
+ interface WheelGestureConstructor {
11
+ new <EventType = EventTypes['wheel']>(
12
+ target: EventTarget,
13
+ handler: Handler<'wheel', EventType>,
14
+ config?: UserWheelConfig,
15
+ ): WheelGesture;
16
+ }
17
+
18
+ export interface WheelGesture extends Recognizer<'wheel'> {}
19
+
20
+ export const WheelGesture: WheelGestureConstructor = function <EventType = EventTypes['wheel']>(
21
+ target: EventTarget,
22
+ handler: Handler<'wheel', EventType>,
23
+ config?: UserWheelConfig,
24
+ ) {
25
+ registerAction(wheelAction);
26
+ return new Recognizer(target, { wheel: handler }, config || {}, 'wheel');
27
+ } as any;
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
3
+ * SPDX-License-Identifier: MIT
4
+ */
5
+
6
+ import { Action, GestureHandlers, UserGestureConfig } from '../core/types';
7
+ import { registerAction } from '../core/actions';
8
+ import { parseMergedHandlers } from '../core';
9
+ import { Recognizer } from './Recognizer';
10
+
11
+ export function createGesture(actions: Action[]) {
12
+ actions.forEach(registerAction);
13
+
14
+ return function (target: EventTarget, _handlers: GestureHandlers, _config?: UserGestureConfig) {
15
+ const { handlers, nativeHandlers, config } = parseMergedHandlers(_handlers, _config || {});
16
+ return new Recognizer(target, handlers, config, undefined, nativeHandlers);
17
+ };
18
+ }
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
3
+ * SPDX-License-Identifier: MIT
4
+ */
5
+
6
+ export { DragGesture } from './DragGesture';
7
+ export { PinchGesture } from './PinchGesture';
8
+ export { WheelGesture } from './WheelGesture';
9
+ export { ScrollGesture } from './ScrollGesture';
10
+ export { MoveGesture } from './MoveGesture';
11
+ export { HoverGesture } from './HoverGesture';
12
+ export { Gesture } from './Gesture';
13
+
14
+ export { createGesture } from './createGesture';
15
+
16
+ export * from '../core/utils';
17
+ export * from '../core/types';
18
+ export * from '../core/actions';
package/src/env.d.ts ADDED
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
3
+ * SPDX-License-Identifier: MIT
4
+ */
5
+
6
+ declare module '*.vue' {
7
+ import type { DefineComponent } from 'vue';
8
+ const component: DefineComponent<object, object, unknown>;
9
+ export default component;
10
+ }
package/src/index.ts ADDED
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
3
+ * SPDX-License-Identifier: MIT
4
+ */
5
+
6
+ export * from './common';
7
+ export * from './core';
8
+ export * from './vue';
9
+ export * from './composables';
10
+ export * from './services';
11
+ export * from './plugin';
12
+ export * from './playground';
13
+ export * from './playground-config';
14
+ export * from './playground-contribution';
15
+ export * from './playground-container';
16
+ export * from './playground-mock-tools';
17
+ export { CommandService, CommandRegistry, Command } from '@flowgram-vue/command';
@@ -0,0 +1,70 @@
1
+ /**
2
+ * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
3
+ * SPDX-License-Identifier: MIT
4
+ */
5
+
6
+ // import {
7
+ // PlaygroundConfigEntity,
8
+ // SelectorBoxConfigEntity,
9
+ // SnaplineConfigEntity,
10
+ // EditorStateConfigEntity,
11
+ // } from './core/layer/config';
12
+ import {
13
+ // AlignLayer,
14
+ type EditorState,
15
+ type LayerRegistry,
16
+ // SelectorBoxLayer,
17
+ // SelectorLayer,
18
+ // SnaplineLayer,
19
+ } from './core/layer';
20
+ // import { SelectableEntity } from './core/entity';
21
+ // import { Selectable } from './core/able/selectable';
22
+ // import { Dragable, Resizable } from './core/able';
23
+ import { type ConfigEntity, type EntityRegistry } from './common';
24
+
25
+ export const PlaygroundConfig = Symbol('PlaygroundConfig');
26
+
27
+ /**
28
+ * 画布配置
29
+ */
30
+ export interface PlaygroundConfig {
31
+ layers?: LayerRegistry[]; // 渲染分层
32
+ // ables?: AbleRegistry[]; // 能力
33
+ // entities?: EntityRegistry[]; // 数据实体
34
+ editorStates?: EditorState[]; // 编辑态切换
35
+ width?: number; // 画布的初始宽度
36
+ height?: number; // 画布的初始高度
37
+ node?: HTMLElement; // 画布的容器节点
38
+ autoFocus?: boolean; // 自动 focus 及 blur,默认 true
39
+ autoResize?: boolean; // 监听变化
40
+ zoomEnable?: boolean; // 是否支持缩放,默认 true
41
+ contextMenuPath?: string[]; // 右键菜单路径
42
+ entityConfigs?: Map<EntityRegistry<ConfigEntity>, any>;
43
+ context?: any; // 注入到 layer 中的上下文数据
44
+ }
45
+
46
+ /**
47
+ * 默认配置
48
+ */
49
+ export function createDefaultPlaygroundConfig(): PlaygroundConfig {
50
+ return {
51
+ autoFocus: true,
52
+ autoResize: true,
53
+ zoomEnable: true,
54
+ layers: [
55
+ // PlaygroundLayer, // 基础配置
56
+ // SelectorLayer, // 节点选择器
57
+ // SelectorBoxLayer, // 选择框
58
+ // SnaplineLayer, // 参考线
59
+ // AlignLayer, // 对齐线
60
+ ],
61
+ // ables: [Dragable, Selectable, Resizable],
62
+ // entities: [
63
+ // SelectableEntity,
64
+ // SnaplineConfigEntity,
65
+ // PlaygroundConfigEntity,
66
+ // SelectorBoxConfigEntity,
67
+ // EditorStateConfigEntity,
68
+ // ],
69
+ };
70
+ }
@@ -0,0 +1,129 @@
1
+ /**
2
+ * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
3
+ * SPDX-License-Identifier: MIT
4
+ */
5
+
6
+ import { Container, ContainerModule, type interfaces } from 'inversify';
7
+ import { CommandService, CommandContainerModule } from '@flowgram-vue/command';
8
+
9
+ import { ContextMenuService } from './services/context-menu-service';
10
+ import {
11
+ ClipboardService,
12
+ DefaultClipboardService,
13
+ LocalStorageService,
14
+ SelectionService,
15
+ StorageService,
16
+ LoggerService,
17
+ } from './services';
18
+ import { PluginContext } from './plugin';
19
+ import { PlaygroundContribution, PlaygroundRegistry } from './playground-contribution';
20
+ import { createDefaultPlaygroundConfig, PlaygroundConfig } from './playground-config';
21
+ import { Playground } from './playground';
22
+ import {
23
+ type LayerRegistry,
24
+ LayerOptions,
25
+ // PipelineDispatcher,
26
+ PipelineEntitiesSelector,
27
+ PipelineLayerFactory,
28
+ PipelineRegistry,
29
+ PipelineRenderer,
30
+ PlaygroundConfigEntity,
31
+ LazyInjectContext,
32
+ } from './core';
33
+ import {
34
+ // AbleManager,
35
+ bindConfigEntity,
36
+ bindContributionProvider,
37
+ bindPlaygroundContextProvider,
38
+ EntityManager,
39
+ PlaygroundContainerFactory,
40
+ PlaygroundContext,
41
+ removeInjectedProperties,
42
+ } from './common';
43
+
44
+ export function createPluginContextDefault(container: interfaces.Container): PluginContext {
45
+ return {
46
+ container,
47
+ playground: container.get(Playground),
48
+ get<T>(identifier: interfaces.ServiceIdentifier): T {
49
+ return container.get(identifier) as T;
50
+ },
51
+ getAll<T>(identifier: interfaces.ServiceIdentifier): T[] {
52
+ return container.getAll(identifier) as T[];
53
+ },
54
+ };
55
+ }
56
+
57
+ export function createPlaygroundLayerDefault(
58
+ container: interfaces.Container,
59
+ layerRegistry: LayerRegistry,
60
+ options: any = {},
61
+ ) {
62
+ const layerContainer = container.createChild();
63
+ layerContainer.bind(layerRegistry).toSelf().inSingletonScope();
64
+ layerContainer.bind(LayerOptions).toConstantValue(options);
65
+ const layerInstance = layerContainer.get(layerRegistry);
66
+ removeInjectedProperties(layerInstance);
67
+ return layerInstance;
68
+ }
69
+
70
+ export const PlaygroundContainerModule = new ContainerModule(bind => {
71
+ // bind(AbleManager).toSelf().inSingletonScope();
72
+ bind(EntityManager).toSelf().inSingletonScope();
73
+ bind(PipelineRenderer).toSelf().inSingletonScope();
74
+ bind(PlaygroundRegistry).toSelf().inSingletonScope();
75
+ bind(Playground).toSelf().inSingletonScope();
76
+ bind(PipelineEntitiesSelector).toSelf().inSingletonScope();
77
+ bind(PipelineLayerFactory)
78
+ .toDynamicValue(
79
+ (context: interfaces.Context) => (layerRegistry: LayerRegistry, options?: any) =>
80
+ createPlaygroundLayerDefault(context.container, layerRegistry, options),
81
+ )
82
+ .inSingletonScope();
83
+ // bind(PipelineDispatcher).toSelf().inSingletonScope();
84
+ bind(PipelineRegistry).toSelf().inSingletonScope();
85
+ bind(PlaygroundContainerFactory)
86
+ .toDynamicValue(ctx => ctx.container)
87
+ .inSingletonScope();
88
+ bind(PlaygroundConfig).toConstantValue(createDefaultPlaygroundConfig());
89
+ bind(PlaygroundContext).toConstantValue({});
90
+ bindPlaygroundContextProvider(bind);
91
+
92
+ bind(LoggerService).toSelf().inSingletonScope();
93
+
94
+ bind(ContextMenuService).toSelf().inSingletonScope();
95
+ bind(SelectionService).toSelf().inSingletonScope();
96
+
97
+ // 默认采用 LocalStorageService
98
+ bind(StorageService).to(LocalStorageService).inSingletonScope();
99
+ bind(ClipboardService).to(DefaultClipboardService).inSingletonScope();
100
+ bindConfigEntity(bind, PlaygroundConfigEntity);
101
+ bindContributionProvider(bind, PlaygroundContribution);
102
+ bind(PluginContext)
103
+ .toDynamicValue(ctx => createPluginContextDefault(ctx.container))
104
+ .inSingletonScope();
105
+
106
+ bind(LazyInjectContext).toService(PluginContext);
107
+ });
108
+
109
+ export function createPlaygroundContainer(
110
+ config?: PlaygroundConfig,
111
+ parent?: interfaces.Container,
112
+ container?: interfaces.Container,
113
+ ): interfaces.Container {
114
+ const child = container || new Container({ defaultScope: 'Singleton' });
115
+ if (parent) {
116
+ child.parent = parent;
117
+ }
118
+ child.load(PlaygroundContainerModule);
119
+ if (!child.isBound(CommandService)) {
120
+ child.load(CommandContainerModule);
121
+ }
122
+ if (config) {
123
+ child.rebind(PlaygroundConfig).toConstantValue(config);
124
+ if (config.context) {
125
+ child.rebind(PlaygroundContext).toConstantValue(config.context);
126
+ }
127
+ }
128
+ return child;
129
+ }
@@ -0,0 +1,81 @@
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
+
8
+ import { PlaygroundConfig } from './playground-config';
9
+ import { type Playground } from './playground';
10
+ import {
11
+ PipelineRegistry,
12
+ type EditorState,
13
+ EditorStateConfigEntity,
14
+ type LayerRegistry,
15
+ } from './core';
16
+ import { EntityManager, type EntityRegistry } from './common';
17
+
18
+ export const PlaygroundContribution = Symbol('PlaygroundContribution');
19
+
20
+ export interface PlaygroundContribution {
21
+ /**
22
+ * 注册 Layer/Entity/Able 相关
23
+ * @param registry
24
+ * @deprecated
25
+ */
26
+ registerPlayground?(registry: PlaygroundRegistry): void;
27
+ /**
28
+ * 初始化画布 (onReady 之前)
29
+ * @param playground
30
+ */
31
+ onInit?(playground: Playground): void;
32
+ /**
33
+ * 初始化 entity 完毕后触发
34
+ * @param playground
35
+ */
36
+ onReady?(playground: Playground): void;
37
+ /**
38
+ * 销毁
39
+ * @param playground
40
+ */
41
+ onDispose?(playground: Playground): void;
42
+
43
+ /**
44
+ * 所有 Layer 第一次渲染完毕后触发
45
+ * @param playground
46
+ */
47
+ onAllLayersRendered?(playground: Playground): void;
48
+ }
49
+
50
+ @injectable()
51
+ export class PlaygroundRegistry {
52
+ @inject(PipelineRegistry) protected readonly pipeline: PipelineRegistry;
53
+
54
+ // @inject(AbleManager) readonly ableManager: AbleManager;
55
+
56
+ @inject(EntityManager) readonly entityManager: EntityManager;
57
+
58
+ @inject(PlaygroundConfig) readonly playgroundConfig: PlaygroundConfig;
59
+
60
+ config(config: Partial<PlaygroundConfig>): void {
61
+ Object.assign(this.playgroundConfig, config);
62
+ }
63
+
64
+ registerLayer(layerRegistry: LayerRegistry): void {
65
+ this.pipeline.registerLayer(layerRegistry);
66
+ }
67
+
68
+ registerEntity(entityRegistry: EntityRegistry): void {
69
+ this.entityManager.registerEntity(entityRegistry);
70
+ }
71
+
72
+ // registerAble(ableRegistry: AbleRegistry): void {
73
+ // this.ableManager.registerAble(ableRegistry);
74
+ // }
75
+
76
+ registerEditorState(state: EditorState): void {
77
+ const stateConfig =
78
+ this.entityManager.getEntity<EditorStateConfigEntity>(EditorStateConfigEntity);
79
+ stateConfig?.registerState(state);
80
+ }
81
+ }
@@ -0,0 +1,143 @@
1
+ /**
2
+ * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
3
+ * SPDX-License-Identifier: MIT
4
+ */
5
+
6
+ import { interfaces } from 'inversify';
7
+
8
+ import { createPlaygroundContainer, createPlaygroundLayerDefault } from './playground-container';
9
+ import { Playground } from './playground';
10
+ import { LayerRegistry, Layer, PipelineLayerFactory } from './core';
11
+
12
+ /**
13
+ * 画布测试工具
14
+ *
15
+ * @example
16
+ *
17
+ * 监听 layer 的执行
18
+ * const layerState = PlaygroundMockTools.createLayerTestState(PlaygroundLayer)
19
+ * layerState.playground.ready()
20
+ * expect(layerState.onReady.mock.calls.length).toEqual(1)
21
+ * expect(layerState.autorun.mock.calls.length).toEqual(1)
22
+ * layerState.playground.config.updateConfig({
23
+ * scrollX: 100
24
+ * })
25
+ * expect(layerState.onReady.mock.calls.length).toEqual(1)
26
+ * expect(layerState.autorun.mock.calls.length).toEqual(2)
27
+ */
28
+ export namespace PlaygroundMockTools {
29
+ const LayerStateProvider = Symbol('LayerStateProvider');
30
+ type LayerStateProvider = WeakMap<LayerRegistry, LayerTestState>;
31
+
32
+ interface SpyInstance {
33
+ mock: {
34
+ calls: any[][];
35
+ instances: any[];
36
+ invocationCallOrder: any;
37
+ results: { type: string; value: any }[];
38
+ lastCall: any[];
39
+ };
40
+ }
41
+ export class LayerTestState<T extends Layer = Layer> {
42
+ autorun: SpyInstance;
43
+
44
+ render: SpyInstance;
45
+
46
+ onReady: SpyInstance;
47
+
48
+ onResize: SpyInstance;
49
+
50
+ onFocus: SpyInstance;
51
+
52
+ onBlur: SpyInstance;
53
+
54
+ onZoom: SpyInstance;
55
+
56
+ onScroll: SpyInstance;
57
+
58
+ onViewportChange: SpyInstance;
59
+
60
+ onReadonlyOrDisabledChange: SpyInstance;
61
+
62
+ constructor(
63
+ readonly instance: T,
64
+ readonly playground: Playground,
65
+ readonly container: interfaces.Container
66
+ ) {
67
+ this.hijackMethod(instance, 'autorun');
68
+ this.hijackMethod(instance, 'render');
69
+ this.hijackMethod(instance, 'onReady');
70
+ this.hijackMethod(instance, 'onResize');
71
+ this.hijackMethod(instance, 'onFocus');
72
+ this.hijackMethod(instance, 'onBlur');
73
+ this.hijackMethod(instance, 'onZoom');
74
+ this.hijackMethod(instance, 'onScroll');
75
+ this.hijackMethod(instance, 'onViewportChange');
76
+ this.hijackMethod(instance, 'onReadonlyOrDisabledChange');
77
+ }
78
+
79
+ private hijackMethod(layer: Layer, layerMethod: keyof Layer & keyof LayerTestState): void {
80
+ if (typeof layer[layerMethod] === 'function') {
81
+ // vi should be global
82
+ // @ts-ignore
83
+ (this as any)[layerMethod] = vi.spyOn(layer as any, layerMethod);
84
+ }
85
+ }
86
+ }
87
+
88
+ export function createContainer(modules?: interfaces.ContainerModule[]): interfaces.Container {
89
+ const container = createPlaygroundContainer();
90
+ container.bind(LayerStateProvider).toConstantValue(new WeakMap());
91
+ container
92
+ .rebind(PipelineLayerFactory)
93
+ .toDynamicValue((context) => (layerRegistry: LayerRegistry, options?: any) => {
94
+ const layerInstance = createPlaygroundLayerDefault(
95
+ context.container,
96
+ layerRegistry,
97
+ options
98
+ );
99
+ context.container
100
+ .get<LayerStateProvider>(LayerStateProvider)
101
+ .set(
102
+ layerRegistry,
103
+ new LayerTestState(layerInstance, container.get<Playground>(Playground), container)
104
+ );
105
+ return layerInstance;
106
+ });
107
+ if (modules) {
108
+ modules.forEach((module) => container.load(module));
109
+ }
110
+ return container;
111
+ }
112
+
113
+ export function createPlayground(modules?: interfaces.ContainerModule[]): Playground {
114
+ return createContainer(modules).get(Playground);
115
+ }
116
+
117
+ export function getLayerTestState<T extends Layer = Layer>(
118
+ container: interfaces.Container,
119
+ layerRegistry: LayerRegistry<T>
120
+ ): LayerTestState<T> {
121
+ return container
122
+ .get<LayerStateProvider>(LayerStateProvider)
123
+ .get(layerRegistry) as LayerTestState<T>;
124
+ }
125
+
126
+ /**
127
+ * 创建layer, 并记录layer的回调数据
128
+ * @param Layer
129
+ * @param opts
130
+ */
131
+ export function createLayerTestState<T extends Layer = Layer>(
132
+ layerRegistry: LayerRegistry<T>,
133
+ opts?: any,
134
+ modules?: interfaces.ContainerModule[]
135
+ ): LayerTestState<T> {
136
+ const container = createContainer(modules);
137
+ const playground = container.get<Playground>(Playground);
138
+ playground.registerLayer(layerRegistry, opts);
139
+ playground.init();
140
+ playground.ready();
141
+ return getLayerTestState(container, layerRegistry);
142
+ }
143
+ }