@netless/window-manager 1.0.0-canary.8 → 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 (135) 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 -39
  5. package/dist/index.js +62 -0
  6. package/dist/index.js.map +1 -0
  7. package/dist/{index.es.js → index.mjs} +8393 -5913
  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 +104 -71
  35. package/src/App/AppPageStateImpl.ts +6 -25
  36. package/src/App/AppProxy.ts +42 -147
  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 +84 -75
  45. package/src/AttributesDelegate.ts +42 -22
  46. package/src/BoxEmitter.ts +12 -6
  47. package/src/BoxManager.ts +122 -106
  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/PageController.ts +1 -0
  58. package/src/Page/index.ts +1 -1
  59. package/src/PageState.ts +6 -5
  60. package/src/ReconnectRefresher.ts +9 -4
  61. package/src/RedoUndo.ts +3 -3
  62. package/src/Register/index.ts +22 -17
  63. package/src/Register/loader.ts +26 -22
  64. package/src/Register/storage.ts +13 -13
  65. package/src/Utils/Common.ts +18 -14
  66. package/src/Utils/Reactive.ts +26 -25
  67. package/src/Utils/RoomHacker.ts +4 -4
  68. package/src/Utils/error.ts +0 -1
  69. package/src/View/IframeBridge.ts +680 -0
  70. package/src/View/MainView.ts +114 -53
  71. package/src/callback.ts +21 -1
  72. package/src/constants.ts +0 -2
  73. package/src/image/pencil-eraser-1.svg +3 -0
  74. package/src/image/pencil-eraser-2.svg +3 -0
  75. package/src/image/pencil-eraser-3.svg +3 -0
  76. package/src/index.ts +224 -74
  77. package/src/style.css +27 -10
  78. package/src/typings.ts +20 -10
  79. package/.prettierignore +0 -7
  80. package/.prettierrc.json +0 -9
  81. package/CHANGELOG.md +0 -196
  82. package/__mocks__/white-web-sdk.ts +0 -50
  83. package/dist/App/AppContext.d.ts +0 -76
  84. package/dist/App/AppPageStateImpl.d.ts +0 -21
  85. package/dist/App/AppProxy.d.ts +0 -81
  86. package/dist/App/AppViewSync.d.ts +0 -11
  87. package/dist/App/MagixEvent/index.d.ts +0 -29
  88. package/dist/App/Storage/StorageEvent.d.ts +0 -8
  89. package/dist/App/Storage/index.d.ts +0 -39
  90. package/dist/App/Storage/typings.d.ts +0 -22
  91. package/dist/App/Storage/utils.d.ts +0 -5
  92. package/dist/App/WhiteboardView.d.ts +0 -22
  93. package/dist/App/index.d.ts +0 -3
  94. package/dist/AppListener.d.ts +0 -21
  95. package/dist/AppManager.d.ts +0 -107
  96. package/dist/AttributesDelegate.d.ts +0 -80
  97. package/dist/BoxEmitter.d.ts +0 -34
  98. package/dist/BoxManager.d.ts +0 -100
  99. package/dist/BuiltinApps.d.ts +0 -5
  100. package/dist/Cursor/Cursor.d.ts +0 -39
  101. package/dist/Cursor/icons.d.ts +0 -3
  102. package/dist/Cursor/index.d.ts +0 -46
  103. package/dist/Helper.d.ts +0 -17
  104. package/dist/InternalEmitter.d.ts +0 -39
  105. package/dist/Page/PageController.d.ts +0 -20
  106. package/dist/Page/index.d.ts +0 -3
  107. package/dist/PageState.d.ts +0 -9
  108. package/dist/ReconnectRefresher.d.ts +0 -24
  109. package/dist/RedoUndo.d.ts +0 -18
  110. package/dist/Register/index.d.ts +0 -28
  111. package/dist/Register/loader.d.ts +0 -4
  112. package/dist/Register/storage.d.ts +0 -8
  113. package/dist/Utils/AppCreateQueue.d.ts +0 -15
  114. package/dist/Utils/Common.d.ts +0 -23
  115. package/dist/Utils/Reactive.d.ts +0 -6
  116. package/dist/Utils/RoomHacker.d.ts +0 -3
  117. package/dist/Utils/error.d.ts +0 -27
  118. package/dist/Utils/log.d.ts +0 -1
  119. package/dist/View/CameraSynchronizer.d.ts +0 -17
  120. package/dist/View/MainView.d.ts +0 -48
  121. package/dist/View/ViewManager.d.ts +0 -13
  122. package/dist/View/ViewSync.d.ts +0 -7
  123. package/dist/callback.d.ts +0 -24
  124. package/dist/constants.d.ts +0 -49
  125. package/dist/index.cjs.js +0 -46
  126. package/dist/index.umd.js +0 -46
  127. package/dist/typings.d.ts +0 -82
  128. package/jest.config.js +0 -27
  129. package/pnpm-lock.yaml +0 -6302
  130. package/src/App/AppViewSync.ts +0 -68
  131. package/src/App/WhiteboardView.ts +0 -83
  132. package/src/View/CameraSynchronizer.ts +0 -73
  133. package/src/View/ViewSync.ts +0 -10
  134. package/vite.config.js +0 -51
  135. /package/docs/{qickstart.md → cn/quickstart.md} +0 -0
@@ -1,68 +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
+ const playgroundSizeChangeListener = () => {
36
+ this.sizeChangeHandler(this.mainViewSize);
37
+ };
35
38
  this.sideEffectManager.add(() => {
36
- return emitter.on("containerSizeRatioUpdate", this.onUpdateContainerSizeRatio);
39
+ return internalEmitter.on("playgroundSizeChange", playgroundSizeChangeListener);
37
40
  });
38
41
  this.sideEffectManager.add(() => {
39
- return emitter.on("startReconnect", () => {
40
- releaseView(this.mainView);
41
- });
42
+ return internalEmitter.on("containerSizeRatioUpdate", this.onUpdateContainerSizeRatio);
42
43
  });
43
- const rect = this.manager.boxManager?.stageRect;
44
- if (rect) {
45
- this.synchronizer.setRect(rect);
46
- }
47
44
  this.sideEffectManager.add(() => {
48
- return emitter.on("playgroundSizeChange", rect => {
49
- this.synchronizer.setRect(rect);
50
- // this.synchronizer.onLocalSizeUpdate(rect);
45
+ return internalEmitter.on("startReconnect", () => {
46
+ if (!this.didRelease) {
47
+ this.mainView.release();
48
+ }
51
49
  });
52
50
  });
51
+ this.sideEffectManager.setInterval(this.syncCamera, 1500);
53
52
  }
54
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
+
55
63
  private startListenWritableChange = () => {
56
64
  this.sideEffectManager.add(() => {
57
- return emitter.on("writableChange", isWritable => {
65
+ return internalEmitter.on("writableChange", isWritable => {
58
66
  if (isWritable) {
59
67
  this.ensureCameraAndSize();
60
68
  }
69
+ if (this.manager.room) this.syncMainView(this.manager.room);
61
70
  });
62
71
  });
63
72
  };
64
73
 
65
74
  public ensureCameraAndSize() {
75
+ if (this.viewMode !== ViewMode.Broadcaster) return;
66
76
  if (!this.mainViewCamera || !this.mainViewSize) {
67
77
  this.manager.dispatchInternalEvent(Events.InitMainViewCamera);
68
78
  this.setCameraAndSize();
@@ -82,28 +92,27 @@ export class MainViewProxy {
82
92
  }
83
93
 
84
94
  private moveCameraSizeByAttributes() {
85
- this.synchronizer.onRemoteUpdate(this.mainViewCamera, this.mainViewSize);
95
+ this.moveCameraToContian(this.mainViewSize);
96
+ this.moveCamera(this.mainViewCamera);
86
97
  }
87
98
 
88
99
  public start() {
89
- if (this.started) return;
90
100
  this.sizeChangeHandler(this.mainViewSize);
101
+ if (this.started) return;
91
102
  this.addCameraListener();
92
103
  this.addCameraReaction();
104
+ if (this.manager.room) this.syncMainView(this.manager.room);
93
105
  this.started = true;
94
106
  }
95
107
 
96
108
  public addCameraReaction = () => {
97
- this.manager.refresher?.add(Fields.MainViewCamera, this.cameraReaction);
109
+ this.manager.refresher.add(Fields.MainViewCamera, this.cameraReaction);
98
110
  };
99
111
 
100
112
  public setCameraAndSize(): void {
101
- const stageSize = this.getStageSize();
102
- if (stageSize) {
103
- const camera = { ...this.mainView.camera, id: this.manager.uid };
104
- const size = { ...stageSize, id: this.manager.uid };
105
- this.store.setMainViewCameraAndSize(camera, size);
106
- }
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);
107
116
  }
108
117
 
109
118
  private cameraReaction = () => {
@@ -111,7 +120,8 @@ export class MainViewProxy {
111
120
  () => this.mainViewCamera,
112
121
  camera => {
113
122
  if (camera && camera.id !== this.manager.uid) {
114
- this.synchronizer.onRemoteUpdate(camera, this.mainViewSize);
123
+ this.moveCameraToContian(this.mainViewSize);
124
+ this.moveCamera(camera);
115
125
  }
116
126
  },
117
127
  { fireImmediately: true }
@@ -120,16 +130,15 @@ export class MainViewProxy {
120
130
 
121
131
  public sizeChangeHandler = debounce((size: Size) => {
122
132
  if (size) {
123
- // this.synchronizer.onLocalSizeUpdate(size);
133
+ this.moveCameraToContian(size);
134
+ this.moveCamera(this.mainViewCamera);
124
135
  }
136
+ this.ensureMainViewSize();
125
137
  }, 30);
126
138
 
127
139
  public onUpdateContainerSizeRatio = () => {
128
140
  const size = this.store.getMainViewSize();
129
141
  this.sizeChangeHandler(size);
130
- if (size.id === this.manager.uid) {
131
- this.setCameraAndSize();
132
- }
133
142
  };
134
143
 
135
144
  public get view(): View {
@@ -146,7 +155,6 @@ export class MainViewProxy {
146
155
  if (mainViewScenePath) {
147
156
  setViewFocusScenePath(mainView, mainViewScenePath);
148
157
  }
149
- this.synchronizer.setView(mainView);
150
158
  return mainView;
151
159
  }
152
160
 
@@ -169,30 +177,26 @@ export class MainViewProxy {
169
177
  const divElement = this.mainView.divElement;
170
178
  const disableCameraTransform = this.mainView.disableCameraTransform;
171
179
  this.stop();
172
- releaseView(this.mainView);
180
+ if (!this.didRelease) {
181
+ this.mainView.release();
182
+ }
173
183
  this.removeMainViewListener();
174
184
  this.mainView = this.createMainView();
175
185
  this.mainView.disableCameraTransform = disableCameraTransform;
176
186
  this.mainView.divElement = divElement;
177
187
  this.addMainViewListener();
178
188
  this.start();
189
+ callbacks.emit("onMainViewRebind", this.mainView);
179
190
  }
180
191
 
181
192
  private onCameraUpdatedByDevice = (camera: Camera) => {
182
- this.synchronizer.onLocalCameraUpdate(camera);
183
- const size = this.getStageSize();
184
- if (size && !isEqual(size, this.mainViewSize)) {
185
- 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);
186
197
  }
187
198
  };
188
199
 
189
- private getStageSize(): Size | undefined {
190
- const stage = this.manager.boxManager?.stageRect;
191
- if (stage) {
192
- return { width: stage.width, height: stage.height };
193
- }
194
- }
195
-
196
200
  public addMainViewListener(): void {
197
201
  if (this.mainViewIsAddListener) return;
198
202
  if (this.view.divElement) {
@@ -236,17 +240,74 @@ export class MainViewProxy {
236
240
  this.view.callbacks.off("onSizeUpdated", this.onCameraOrSizeUpdated);
237
241
  }
238
242
 
243
+ private _syncMainViewTimer = 0;
239
244
  private onCameraOrSizeUpdated = () => {
240
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();
241
253
  };
242
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
+
243
300
  public stop() {
244
301
  this.removeCameraListener();
245
- this.manager.refresher?.remove(Fields.MainViewCamera);
246
- this.manager.refresher?.remove(Fields.MainViewSize);
302
+ this.manager.refresher.remove(Fields.MainViewCamera);
303
+ this.manager.refresher.remove(Fields.MainViewSize);
247
304
  this.started = false;
248
305
  }
249
306
 
307
+ public setViewMode = (mode: ViewMode) => {
308
+ this.viewMode = mode;
309
+ };
310
+
250
311
  public destroy() {
251
312
  this.removeMainViewListener();
252
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>