@netless/window-manager 1.0.0-canary.9 → 1.0.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 (132) hide show
  1. package/LICENSE.txt +21 -0
  2. package/README.md +90 -64
  3. package/README.zh-cn.md +224 -0
  4. package/dist/index.d.ts +1133 -40
  5. package/dist/index.js +62 -0
  6. package/dist/index.js.map +1 -0
  7. package/dist/{index.es.js → index.mjs} +9480 -6984
  8. package/dist/index.mjs.map +1 -0
  9. package/dist/style.css +1 -1
  10. package/docs/advanced.md +55 -55
  11. package/docs/api.md +124 -113
  12. package/docs/app-context.md +248 -209
  13. package/docs/basic.md +25 -26
  14. package/docs/camera.md +19 -20
  15. package/docs/cn/advanced.md +137 -0
  16. package/docs/cn/api.md +309 -0
  17. package/docs/cn/app-context.md +369 -0
  18. package/docs/cn/basic.md +64 -0
  19. package/docs/cn/camera.md +53 -0
  20. package/docs/cn/concept.md +9 -0
  21. package/docs/cn/custom-max-bar.md +31 -0
  22. package/docs/cn/develop-app.md +94 -0
  23. package/docs/cn/export-pdf.md +48 -0
  24. package/docs/cn/migrate.md +60 -0
  25. package/docs/cn/replay.md +40 -0
  26. package/docs/concept.md +6 -5
  27. package/docs/custom-max-bar.md +31 -0
  28. package/docs/develop-app.md +22 -19
  29. package/docs/export-pdf.md +48 -0
  30. package/docs/migrate.md +25 -27
  31. package/docs/quickstart.md +50 -0
  32. package/docs/replay.md +20 -20
  33. package/package.json +32 -22
  34. package/src/App/AppContext.ts +105 -73
  35. package/src/App/AppPageStateImpl.ts +6 -25
  36. package/src/App/AppProxy.ts +41 -166
  37. package/src/App/MagixEvent/index.ts +38 -38
  38. package/src/App/Storage/StorageEvent.ts +13 -13
  39. package/src/App/Storage/index.ts +269 -245
  40. package/src/App/Storage/typings.ts +4 -2
  41. package/src/App/Storage/utils.ts +3 -3
  42. package/src/App/index.ts +0 -1
  43. package/src/AppListener.ts +8 -8
  44. package/src/AppManager.ts +88 -77
  45. package/src/AttributesDelegate.ts +42 -22
  46. package/src/BoxEmitter.ts +12 -6
  47. package/src/BoxManager.ts +128 -108
  48. package/src/ContainerResizeObserver.ts +75 -0
  49. package/src/Cursor/Cursor.svelte +16 -5
  50. package/src/Cursor/Cursor.svelte.d.ts +21 -0
  51. package/src/Cursor/Cursor.ts +77 -13
  52. package/src/Cursor/icons.ts +6 -0
  53. package/src/Cursor/icons2.ts +66 -0
  54. package/src/Cursor/index.ts +127 -26
  55. package/src/Helper.ts +94 -14
  56. package/src/InternalEmitter.ts +2 -7
  57. package/src/Page/index.ts +1 -1
  58. package/src/PageState.ts +6 -5
  59. package/src/ReconnectRefresher.ts +9 -4
  60. package/src/RedoUndo.ts +3 -3
  61. package/src/Register/index.ts +22 -17
  62. package/src/Register/loader.ts +26 -22
  63. package/src/Register/storage.ts +13 -13
  64. package/src/Utils/Common.ts +18 -14
  65. package/src/Utils/Reactive.ts +26 -25
  66. package/src/Utils/RoomHacker.ts +4 -4
  67. package/src/Utils/error.ts +0 -1
  68. package/src/View/IframeBridge.ts +680 -0
  69. package/src/View/MainView.ts +127 -53
  70. package/src/callback.ts +21 -1
  71. package/src/constants.ts +0 -2
  72. package/src/image/pencil-eraser-1.svg +3 -0
  73. package/src/image/pencil-eraser-2.svg +3 -0
  74. package/src/image/pencil-eraser-3.svg +3 -0
  75. package/src/index.ts +220 -83
  76. package/src/style.css +27 -10
  77. package/src/typings.ts +20 -10
  78. package/.prettierignore +0 -7
  79. package/.prettierrc.json +0 -9
  80. package/CHANGELOG.md +0 -196
  81. package/__mocks__/white-web-sdk.ts +0 -50
  82. package/dist/App/AppContext.d.ts +0 -76
  83. package/dist/App/AppPageStateImpl.d.ts +0 -21
  84. package/dist/App/AppProxy.d.ts +0 -86
  85. package/dist/App/AppViewSync.d.ts +0 -11
  86. package/dist/App/MagixEvent/index.d.ts +0 -29
  87. package/dist/App/Storage/StorageEvent.d.ts +0 -8
  88. package/dist/App/Storage/index.d.ts +0 -39
  89. package/dist/App/Storage/typings.d.ts +0 -22
  90. package/dist/App/Storage/utils.d.ts +0 -5
  91. package/dist/App/WhiteboardView.d.ts +0 -22
  92. package/dist/App/index.d.ts +0 -3
  93. package/dist/AppListener.d.ts +0 -21
  94. package/dist/AppManager.d.ts +0 -107
  95. package/dist/AttributesDelegate.d.ts +0 -80
  96. package/dist/BoxEmitter.d.ts +0 -34
  97. package/dist/BoxManager.d.ts +0 -99
  98. package/dist/BuiltinApps.d.ts +0 -5
  99. package/dist/Cursor/Cursor.d.ts +0 -39
  100. package/dist/Cursor/icons.d.ts +0 -3
  101. package/dist/Cursor/index.d.ts +0 -46
  102. package/dist/Helper.d.ts +0 -17
  103. package/dist/InternalEmitter.d.ts +0 -39
  104. package/dist/Page/PageController.d.ts +0 -21
  105. package/dist/Page/index.d.ts +0 -3
  106. package/dist/PageState.d.ts +0 -9
  107. package/dist/ReconnectRefresher.d.ts +0 -24
  108. package/dist/RedoUndo.d.ts +0 -18
  109. package/dist/Register/index.d.ts +0 -28
  110. package/dist/Register/loader.d.ts +0 -4
  111. package/dist/Register/storage.d.ts +0 -8
  112. package/dist/Utils/AppCreateQueue.d.ts +0 -15
  113. package/dist/Utils/Common.d.ts +0 -23
  114. package/dist/Utils/Reactive.d.ts +0 -6
  115. package/dist/Utils/RoomHacker.d.ts +0 -3
  116. package/dist/Utils/error.d.ts +0 -27
  117. package/dist/Utils/log.d.ts +0 -1
  118. package/dist/View/CameraSynchronizer.d.ts +0 -16
  119. package/dist/View/MainView.d.ts +0 -47
  120. package/dist/View/ViewManager.d.ts +0 -13
  121. package/dist/callback.d.ts +0 -24
  122. package/dist/constants.d.ts +0 -49
  123. package/dist/index.cjs.js +0 -46
  124. package/dist/index.umd.js +0 -46
  125. package/dist/typings.d.ts +0 -82
  126. package/jest.config.js +0 -27
  127. package/pnpm-lock.yaml +0 -6302
  128. package/src/App/AppViewSync.ts +0 -68
  129. package/src/App/WhiteboardView.ts +0 -83
  130. package/src/View/CameraSynchronizer.ts +0 -56
  131. package/vite.config.js +0 -51
  132. /package/docs/{qickstart.md → cn/quickstart.md} +0 -0
@@ -1,63 +1,78 @@
1
+ import { AnimationMode, reaction, ViewMode } from "white-web-sdk";
1
2
  import { callbacks } from "../callback";
2
- import { CameraSynchronizer } from "./CameraSynchronizer";
3
3
  import { createView } from "./ViewManager";
4
- import { debounce, get, isEqual } from "lodash";
5
- import { emitter } from "../InternalEmitter";
6
- import { Events } from "../constants";
4
+ import { debounce, get, isEmpty, isEqual } from "lodash";
5
+ import { internalEmitter } from "../InternalEmitter";
7
6
  import { Fields } from "../AttributesDelegate";
8
- import { reaction } from "white-web-sdk";
9
- import { releaseView, setViewFocusScenePath } from "../Utils/Common";
7
+ import { setViewFocusScenePath } from "../Utils/Common";
10
8
  import { SideEffectManager } from "side-effect-manager";
11
- import type { Camera, Size, View } from "white-web-sdk";
9
+ import type { Camera, Room, Size, View } from "white-web-sdk";
12
10
  import type { AppManager } from "../AppManager";
11
+ import { Events } from "../constants";
13
12
 
14
13
  export class MainViewProxy {
14
+ /** Refresh the view's camera in an interval of 1.5s. */
15
+ public polling = false;
16
+
17
+ private scale?: number;
15
18
  private started = false;
16
19
  private mainViewIsAddListener = false;
17
20
  private mainView: View;
18
21
  private store = this.manager.store;
19
- private synchronizer: CameraSynchronizer;
22
+ private viewMode = this.manager.windowManger.viewMode;
20
23
 
21
24
  private sideEffectManager = new SideEffectManager();
22
25
 
23
26
  constructor(private manager: AppManager) {
24
- this.synchronizer = new CameraSynchronizer(camera =>
25
- this.store.setMainViewCamera({ ...camera, id: this.manager.uid })
26
- );
27
27
  this.mainView = this.createMainView();
28
28
  this.moveCameraSizeByAttributes();
29
- emitter.once("mainViewMounted").then(() => {
29
+ internalEmitter.once("mainViewMounted").then(() => {
30
30
  this.addMainViewListener();
31
31
  this.start();
32
32
  this.ensureCameraAndSize();
33
33
  this.startListenWritableChange();
34
34
  });
35
- this.sideEffectManager.add(() => [
36
- emitter.on("containerSizeRatioUpdate", this.onUpdateContainerSizeRatio),
37
- emitter.on("startReconnect", () => {
38
- releaseView(this.mainView);
39
- }),
40
- emitter.on("playgroundSizeChange", rect => {
41
- this.synchronizer.setRect(rect);
42
- })
43
- ]);
44
- const rect = this.manager.boxManager?.stageRect;
45
- if (rect) {
46
- this.synchronizer.setRect(rect);
47
- }
35
+ const playgroundSizeChangeListener = () => {
36
+ this.sizeChangeHandler(this.mainViewSize);
37
+ };
38
+ this.sideEffectManager.add(() => {
39
+ return internalEmitter.on("playgroundSizeChange", playgroundSizeChangeListener);
40
+ });
41
+ this.sideEffectManager.add(() => {
42
+ return internalEmitter.on("containerSizeRatioUpdate", this.onUpdateContainerSizeRatio);
43
+ });
44
+ this.sideEffectManager.add(() => {
45
+ return internalEmitter.on("startReconnect", () => {
46
+ if (!this.didRelease) {
47
+ this.mainView.release();
48
+ }
49
+ });
50
+ });
51
+ this.sideEffectManager.setInterval(this.syncCamera, 1500);
48
52
  }
49
53
 
54
+ // Guard function when the camera is not synced
55
+ private syncCamera = () => {
56
+ if (!this.polling || this.viewMode !== ViewMode.Broadcaster) return;
57
+ const { mainViewCamera } = this;
58
+ if (mainViewCamera && mainViewCamera.id !== this.manager.uid) {
59
+ this.moveCameraSizeByAttributes();
60
+ }
61
+ };
62
+
50
63
  private startListenWritableChange = () => {
51
- this.sideEffectManager.add(() =>
52
- emitter.on("writableChange", isWritable => {
64
+ this.sideEffectManager.add(() => {
65
+ return internalEmitter.on("writableChange", isWritable => {
53
66
  if (isWritable) {
54
67
  this.ensureCameraAndSize();
55
68
  }
56
- })
57
- );
69
+ if (this.manager.room) this.syncMainView(this.manager.room);
70
+ });
71
+ });
58
72
  };
59
73
 
60
74
  public ensureCameraAndSize() {
75
+ if (this.viewMode !== ViewMode.Broadcaster) return;
61
76
  if (!this.mainViewCamera || !this.mainViewSize) {
62
77
  this.manager.dispatchInternalEvent(Events.InitMainViewCamera);
63
78
  this.setCameraAndSize();
@@ -77,13 +92,16 @@ export class MainViewProxy {
77
92
  }
78
93
 
79
94
  private moveCameraSizeByAttributes() {
80
- this.synchronizer.onRemoteUpdate(this.mainViewCamera, this.mainViewSize);
95
+ this.moveCameraToContian(this.mainViewSize);
96
+ this.moveCamera(this.mainViewCamera);
81
97
  }
82
98
 
83
99
  public start() {
100
+ this.sizeChangeHandler(this.mainViewSize);
84
101
  if (this.started) return;
85
102
  this.addCameraListener();
86
103
  this.addCameraReaction();
104
+ if (this.manager.room) this.syncMainView(this.manager.room);
87
105
  this.started = true;
88
106
  }
89
107
 
@@ -92,12 +110,9 @@ export class MainViewProxy {
92
110
  };
93
111
 
94
112
  public setCameraAndSize(): void {
95
- const stageSize = this.getStageSize();
96
- if (stageSize) {
97
- const camera = { ...this.mainView.camera, id: this.manager.uid };
98
- const size = { ...stageSize, id: this.manager.uid };
99
- this.store.setMainViewCameraAndSize(camera, size);
100
- }
113
+ const camera = { ...this.mainView.camera, id: this.manager.uid };
114
+ const size = { ...this.mainView.size, id: this.manager.uid };
115
+ this.store.setMainViewCameraAndSize(camera, size);
101
116
  }
102
117
 
103
118
  private cameraReaction = () => {
@@ -105,18 +120,25 @@ export class MainViewProxy {
105
120
  () => this.mainViewCamera,
106
121
  camera => {
107
122
  if (camera && camera.id !== this.manager.uid) {
108
- this.synchronizer.onRemoteUpdate(camera, this.mainViewSize);
123
+ this.moveCameraToContian(this.mainViewSize);
124
+ this.moveCamera(camera);
109
125
  }
110
126
  },
111
127
  { fireImmediately: true }
112
128
  );
113
129
  };
114
130
 
131
+ public sizeChangeHandler = debounce((size: Size) => {
132
+ if (size) {
133
+ this.moveCameraToContian(size);
134
+ this.moveCamera(this.mainViewCamera);
135
+ }
136
+ this.ensureMainViewSize();
137
+ }, 30);
138
+
115
139
  public onUpdateContainerSizeRatio = () => {
116
140
  const size = this.store.getMainViewSize();
117
- if (size.id === this.manager.uid) {
118
- this.setCameraAndSize();
119
- }
141
+ this.sizeChangeHandler(size);
120
142
  };
121
143
 
122
144
  public get view(): View {
@@ -133,7 +155,6 @@ export class MainViewProxy {
133
155
  if (mainViewScenePath) {
134
156
  setViewFocusScenePath(mainView, mainViewScenePath);
135
157
  }
136
- this.synchronizer.setView(mainView);
137
158
  return mainView;
138
159
  }
139
160
 
@@ -156,30 +177,26 @@ export class MainViewProxy {
156
177
  const divElement = this.mainView.divElement;
157
178
  const disableCameraTransform = this.mainView.disableCameraTransform;
158
179
  this.stop();
159
- releaseView(this.mainView);
180
+ if (!this.didRelease) {
181
+ this.mainView.release();
182
+ }
160
183
  this.removeMainViewListener();
161
184
  this.mainView = this.createMainView();
162
185
  this.mainView.disableCameraTransform = disableCameraTransform;
163
186
  this.mainView.divElement = divElement;
164
187
  this.addMainViewListener();
165
188
  this.start();
189
+ callbacks.emit("onMainViewRebind", this.mainView);
166
190
  }
167
191
 
168
192
  private onCameraUpdatedByDevice = (camera: Camera) => {
169
- this.synchronizer.onLocalCameraUpdate(camera);
170
- const size = this.getStageSize();
171
- if (size && !isEqual(size, this.mainViewSize)) {
172
- this.setMainViewSize(size);
193
+ if (this.viewMode === ViewMode.Follower) return;
194
+ this.store.setMainViewCamera({ ...camera, id: this.manager.uid });
195
+ if (!isEqual(this.mainViewSize, { ...this.mainView.size, id: this.manager.uid })) {
196
+ this.setMainViewSize(this.view.size);
173
197
  }
174
198
  };
175
199
 
176
- private getStageSize(): Size | undefined {
177
- const stage = this.manager.boxManager?.stageRect;
178
- if (stage) {
179
- return { width: stage.width, height: stage.height };
180
- }
181
- }
182
-
183
200
  public addMainViewListener(): void {
184
201
  if (this.mainViewIsAddListener) return;
185
202
  if (this.view.divElement) {
@@ -223,10 +240,63 @@ export class MainViewProxy {
223
240
  this.view.callbacks.off("onSizeUpdated", this.onCameraOrSizeUpdated);
224
241
  }
225
242
 
243
+ private _syncMainViewTimer = 0;
226
244
  private onCameraOrSizeUpdated = () => {
227
245
  callbacks.emit("cameraStateChange", this.cameraState);
246
+ // sdk >= 2.16.43 的 syncMainView() 可以写入当前 main view 的 camera, 以修复复制粘贴元素的位置
247
+ // 注意到这个操作会发送信令,应当避免频繁调用
248
+ if (this.manager.room && (this.manager.room as any).syncMainView) {
249
+ clearTimeout(this._syncMainViewTimer);
250
+ this._syncMainViewTimer = setTimeout(this.syncMainView, 100, this.manager.room);
251
+ }
252
+ this.ensureMainViewSize();
228
253
  };
229
254
 
255
+ private ensureMainViewSize() {
256
+ if (
257
+ (!this.mainViewSize ||
258
+ this.mainViewSize.width === 0 ||
259
+ this.mainViewSize.height === 0) &&
260
+ this.mainView.size.width > 0 &&
261
+ this.mainView.size.height > 0
262
+ ) {
263
+ this.setMainViewSize(this.mainView.size);
264
+ }
265
+ }
266
+
267
+ private syncMainView = (room: Room) => {
268
+ if (room.isWritable) {
269
+ room.syncMainView(this.mainView);
270
+ }
271
+ };
272
+
273
+ public moveCameraToContian(size: Size): void {
274
+ if (!isEmpty(size)) {
275
+ this.view.moveCameraToContain({
276
+ width: size.width,
277
+ height: size.height,
278
+ originX: -size.width / 2,
279
+ originY: -size.height / 2,
280
+ animationMode: AnimationMode.Immediately,
281
+ });
282
+ this.scale = this.view.camera.scale;
283
+ }
284
+ }
285
+
286
+ public moveCamera(camera: Camera): void {
287
+ if (!isEmpty(camera)) {
288
+ if (isEqual(camera, this.view.camera)) return;
289
+ const { centerX, centerY, scale } = camera;
290
+ const needScale = scale * (this.scale || 1);
291
+ this.view.moveCamera({
292
+ centerX: centerX,
293
+ centerY: centerY,
294
+ scale: needScale,
295
+ animationMode: AnimationMode.Immediately,
296
+ });
297
+ }
298
+ }
299
+
230
300
  public stop() {
231
301
  this.removeCameraListener();
232
302
  this.manager.refresher.remove(Fields.MainViewCamera);
@@ -234,6 +304,10 @@ export class MainViewProxy {
234
304
  this.started = false;
235
305
  }
236
306
 
307
+ public setViewMode = (mode: ViewMode) => {
308
+ this.viewMode = mode;
309
+ };
310
+
237
311
  public destroy() {
238
312
  this.removeMainViewListener();
239
313
  this.stop();
package/src/callback.ts CHANGED
@@ -1,8 +1,16 @@
1
1
  import Emittery from "emittery";
2
2
  import type { TeleBoxColorScheme, TELE_BOX_STATE } from "@netless/telebox-insider";
3
- import type { CameraState, SceneState, ViewVisionMode } from "white-web-sdk";
3
+ import type { CameraState, SceneState, View, ViewVisionMode } from "white-web-sdk";
4
4
  import type { LoadAppEvent } from "./Register";
5
5
  import type { PageState } from "./Page";
6
+ import type {
7
+ BoxClosePayload,
8
+ BoxFocusPayload,
9
+ BoxMovePayload,
10
+ BoxResizePayload,
11
+ BoxStateChangePayload,
12
+ } from "./BoxEmitter";
13
+ import type { AppPayload } from "./typings";
6
14
 
7
15
  export type PublicEvent = {
8
16
  mainViewModeChange: ViewVisionMode;
@@ -20,6 +28,18 @@ export type PublicEvent = {
20
28
  ready: undefined; // 所有 APP 创建完毕时触发
21
29
  sceneStateChange: SceneState;
22
30
  pageStateChange: PageState;
31
+ fullscreenChange: boolean;
32
+ appsChange: string[]; // APP 列表变化时触发
33
+ onBoxMove: BoxMovePayload;
34
+ onBoxResize: BoxResizePayload;
35
+ onBoxFocus: BoxFocusPayload;
36
+ onBoxClose: BoxClosePayload;
37
+ onBoxStateChange: BoxStateChangePayload;
38
+ onMainViewMounted: View;
39
+ onMainViewRebind: View;
40
+ onAppViewMounted: AppPayload;
41
+ onAppSetup: string;
42
+ onAppScenePathChange: AppPayload;
23
43
  };
24
44
 
25
45
  export type CallbacksType = Emittery<PublicEvent>;
package/src/constants.ts CHANGED
@@ -57,5 +57,3 @@ export const ROOT_DIR = "/";
57
57
  export const INIT_DIR = "/init";
58
58
 
59
59
  export const SETUP_APP_DELAY = 50;
60
-
61
- export const MAX_PAGE_SIZE = 500;
@@ -0,0 +1,3 @@
1
+ <svg width="18" height="26" viewBox="0 0 18 26" fill="none" xmlns="http://www.w3.org/2000/svg">
2
+ <rect x="0.5" y="0.5" width="17" height="25" rx="3.5" fill="black" fill-opacity="0.35" stroke="white"/>
3
+ </svg>
@@ -0,0 +1,3 @@
1
+ <svg width="26" height="34" viewBox="0 0 26 34" fill="none" xmlns="http://www.w3.org/2000/svg">
2
+ <rect x="0.5" y="0.5" width="25" height="33" rx="3.5" fill="black" fill-opacity="0.35" stroke="white"/>
3
+ </svg>
@@ -0,0 +1,3 @@
1
+ <svg width="34" height="50" viewBox="0 0 34 50" fill="none" xmlns="http://www.w3.org/2000/svg">
2
+ <rect x="0.5" y="0.5" width="33" height="49" rx="3.5" fill="black" fill-opacity="0.35" stroke="white"/>
3
+ </svg>