@netless/window-manager 0.4.32 → 1.0.0-canary.2

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/dist/App/AppContext.d.ts +14 -15
  2. package/dist/App/AppPageStateImpl.d.ts +6 -2
  3. package/dist/App/AppProxy.d.ts +5 -2
  4. package/dist/App/WhiteBoardView.d.ts +16 -0
  5. package/dist/App/index.d.ts +1 -0
  6. package/dist/AppManager.d.ts +2 -0
  7. package/dist/BoxManager.d.ts +7 -5
  8. package/dist/Helper.d.ts +12 -4
  9. package/dist/InternalEmitter.d.ts +4 -1
  10. package/dist/View/CameraSynchronizer.d.ts +17 -0
  11. package/dist/View/MainView.d.ts +4 -5
  12. package/dist/constants.d.ts +1 -0
  13. package/dist/index.cjs.js +21 -22
  14. package/dist/index.d.ts +0 -2
  15. package/dist/index.es.js +2186 -1970
  16. package/dist/index.umd.js +21 -22
  17. package/dist/style.css +1 -1
  18. package/dist/typings.d.ts +4 -0
  19. package/package.json +4 -3
  20. package/pnpm-lock.yaml +86 -97
  21. package/src/App/AppContext.ts +58 -73
  22. package/src/App/AppPageStateImpl.ts +25 -6
  23. package/src/App/AppProxy.ts +39 -15
  24. package/src/App/Storage/index.ts +4 -4
  25. package/src/App/WhiteBoardView.ts +68 -0
  26. package/src/App/index.ts +1 -0
  27. package/src/AppManager.ts +9 -1
  28. package/src/BoxManager.ts +102 -107
  29. package/src/Cursor/index.ts +5 -5
  30. package/src/Helper.ts +12 -16
  31. package/src/InternalEmitter.ts +8 -4
  32. package/src/View/CameraSynchronizer.ts +67 -0
  33. package/src/View/MainView.ts +45 -53
  34. package/src/constants.ts +2 -0
  35. package/src/index.ts +13 -33
  36. package/src/typings.ts +4 -0
  37. package/vite.config.js +0 -1
  38. package/dist/ContainerResizeObserver.d.ts +0 -11
  39. package/dist/index.cjs.js.map +0 -1
  40. package/dist/index.es.js.map +0 -1
  41. package/dist/index.umd.js.map +0 -1
  42. package/src/ContainerResizeObserver.ts +0 -73
@@ -1,9 +1,12 @@
1
1
  import Emittery from "emittery";
2
+ import type { TeleBoxRect } from "@netless/telebox-insider";
2
3
  import type { AppInitState, CursorMovePayload } from "./index";
4
+ import type { Member } from "./Helper";
3
5
 
4
6
  export type RemoveSceneParams = {
5
- scenePath: string, index?: number
6
- }
7
+ scenePath: string;
8
+ index?: number;
9
+ };
7
10
 
8
11
  export type EmitterEvent = {
9
12
  onCreated: undefined;
@@ -14,19 +17,20 @@ export type EmitterEvent = {
14
17
  mainViewMounted: undefined;
15
18
  observerIdChange: number;
16
19
  boxStateChange: string;
17
- playgroundSizeChange: DOMRect;
20
+ playgroundSizeChange: TeleBoxRect;
18
21
  startReconnect: undefined;
19
22
  onReconnected: undefined;
20
23
  removeScenes: RemoveSceneParams;
21
24
  cursorMove: CursorMovePayload;
22
25
  updateManagerRect: undefined;
23
26
  focusedChange: { focused: string | undefined; prev: string | undefined };
24
- rootDirRemoved: undefined; // 根目录整个被删除
27
+ rootDirRemoved: undefined; // 根目录整个被删除
25
28
  rootDirSceneRemoved: string; // 根目录下的场景被删除
26
29
  setReadonly: boolean;
27
30
  changePageState: undefined;
28
31
  writableChange: boolean;
29
32
  containerSizeRatioUpdate: number;
33
+ roomMembersChange: Member[];
30
34
  };
31
35
 
32
36
  export type EmitterType = Emittery<EmitterEvent>;
@@ -0,0 +1,67 @@
1
+ import { AnimationMode } from "white-web-sdk";
2
+ import { delay, throttle } from "lodash";
3
+ import type { TeleBoxRect } from "@netless/telebox-insider";
4
+ import type { Camera, View, Size } from "white-web-sdk";
5
+ import type { MainViewSize } from "../AttributesDelegate";
6
+
7
+ export type SaveCamera = (camera: Camera) => void;
8
+
9
+ export class CameraSynchronizer {
10
+ protected remoteCamera?: Camera;
11
+ protected remoteSize?: MainViewSize;
12
+ protected rect?: TeleBoxRect;
13
+ protected view?: View;
14
+
15
+ constructor(protected saveCamera: SaveCamera) {}
16
+
17
+ public setRect(rect: TeleBoxRect) {
18
+ this.rect = rect;
19
+ if (this.remoteCamera && this.remoteSize) {
20
+ this.onRemoteUpdate(this.remoteCamera, this.remoteSize);
21
+ }
22
+ }
23
+
24
+ public setView(view: View) {
25
+ this.view = view;
26
+ }
27
+
28
+ // 远端 Camera 或者 size 更新
29
+ public onRemoteUpdate = throttle((camera: Camera, size: MainViewSize) => {
30
+ this.remoteCamera = camera;
31
+ this.remoteSize = size;
32
+ if (this.remoteSize && this.rect) {
33
+ let scale: number;
34
+ if (size.width < size.height) {
35
+ scale = this.rect.width / size.width;
36
+ } else {
37
+ scale = this.rect.height / size.height;
38
+ }
39
+ const nextScale = camera.scale * scale;
40
+ const moveCamera = () => this.view?.moveCamera({
41
+ centerX: camera.centerX,
42
+ centerY: camera.centerY,
43
+ scale: nextScale,
44
+ animationMode: AnimationMode.Immediately,
45
+ });
46
+ // TODO 直接调用 moveCamera 依然会出现 camera 错误的情况,这里暂时加一个 delay 保证 camera 是对的, 后续需要 SDK 进行修改
47
+ delay(moveCamera, 10);
48
+ }
49
+ }, 50);
50
+
51
+
52
+ public onLocalCameraUpdate(camera: Camera) {
53
+ this.saveCamera(camera);
54
+ }
55
+
56
+ // 本地 Size 更新, 先匹配 camera 到新的 size 然后再发送 camera 数据到远端
57
+ public onLocalSizeUpdate(size: Size) {
58
+ if (this.rect && this.view) {
59
+ const scale = this.rect.width / size.width;
60
+ const nextScale = this.view.camera.scale * scale;
61
+ this.view.moveCamera({
62
+ scale: nextScale,
63
+ animationMode: AnimationMode.Immediately
64
+ });
65
+ }
66
+ }
67
+ }
@@ -1,25 +1,29 @@
1
- import { AnimationMode, reaction } from "white-web-sdk";
1
+ import { reaction } from "white-web-sdk";
2
2
  import { callbacks } from "../callback";
3
3
  import { createView } from "./ViewManager";
4
- import { debounce, get, isEmpty, isEqual } from "lodash";
4
+ import { debounce, get, isEqual } from "lodash";
5
5
  import { emitter } from "../InternalEmitter";
6
+ import { Events } from "../constants";
6
7
  import { Fields } from "../AttributesDelegate";
7
8
  import { setViewFocusScenePath } from "../Utils/Common";
8
9
  import { SideEffectManager } from "side-effect-manager";
9
10
  import type { Camera, Size, View } from "white-web-sdk";
10
11
  import type { AppManager } from "../AppManager";
11
- import { Events } from "../constants";
12
+ import { CameraSynchronizer } from "./CameraSynchronizer";
12
13
 
13
14
  export class MainViewProxy {
14
- private scale?: number;
15
15
  private started = false;
16
16
  private mainViewIsAddListener = false;
17
17
  private mainView: View;
18
18
  private store = this.manager.store;
19
+ private synchronizer: CameraSynchronizer;
19
20
 
20
21
  private sideEffectManager = new SideEffectManager();
21
22
 
22
23
  constructor(private manager: AppManager) {
24
+ this.synchronizer = new CameraSynchronizer(
25
+ camera => this.store.setMainViewCamera({ ...camera, id: this.manager.uid })
26
+ );
23
27
  this.mainView = this.createMainView();
24
28
  this.moveCameraSizeByAttributes();
25
29
  emitter.once("mainViewMounted").then(() => {
@@ -28,18 +32,24 @@ export class MainViewProxy {
28
32
  this.ensureCameraAndSize();
29
33
  this.startListenWritableChange();
30
34
  });
31
- const playgroundSizeChangeListener = () => {
32
- this.sizeChangeHandler(this.mainViewSize);
33
- };
34
- this.sideEffectManager.add(() => {
35
- return emitter.on("playgroundSizeChange", playgroundSizeChangeListener);
36
- });
37
35
  this.sideEffectManager.add(() => {
38
36
  return emitter.on("containerSizeRatioUpdate", this.onUpdateContainerSizeRatio);
39
37
  });
40
38
  this.sideEffectManager.add(() => {
41
39
  return emitter.on("startReconnect", () => {
42
- this.mainView.release();
40
+ if (!(this.mainView as any).didRelease) {
41
+ this.mainView.release();
42
+ }
43
+ });
44
+ });
45
+ const rect = this.manager.boxManager?.stageRect;
46
+ if (rect) {
47
+ this.synchronizer.setRect(rect);
48
+ }
49
+ this.sideEffectManager.add(() => {
50
+ return emitter.on("playgroundSizeChange", rect => {
51
+ this.synchronizer.setRect(rect);
52
+ this.synchronizer.onLocalSizeUpdate(rect);
43
53
  });
44
54
  });
45
55
  }
@@ -52,7 +62,7 @@ export class MainViewProxy {
52
62
  }
53
63
  });
54
64
  });
55
- }
65
+ };
56
66
 
57
67
  public ensureCameraAndSize() {
58
68
  if (!this.mainViewCamera || !this.mainViewSize) {
@@ -74,8 +84,7 @@ export class MainViewProxy {
74
84
  }
75
85
 
76
86
  private moveCameraSizeByAttributes() {
77
- this.moveCameraToContian(this.mainViewSize);
78
- this.moveCamera(this.mainViewCamera);
87
+ this.synchronizer.onRemoteUpdate(this.mainViewCamera, this.mainViewSize);
79
88
  }
80
89
 
81
90
  public start() {
@@ -91,9 +100,12 @@ export class MainViewProxy {
91
100
  };
92
101
 
93
102
  public setCameraAndSize(): void {
94
- const camera = { ...this.mainView.camera, id: this.manager.uid };
95
- const size = { ...this.mainView.size, id: this.manager.uid };
96
- this.store.setMainViewCameraAndSize(camera, size);
103
+ const stageSize = this.getStageSize();
104
+ if (stageSize) {
105
+ const camera = { ...this.mainView.camera, id: this.manager.uid };
106
+ const size = { ...stageSize, id: this.manager.uid };
107
+ this.store.setMainViewCameraAndSize(camera, size);
108
+ }
97
109
  }
98
110
 
99
111
  private cameraReaction = () => {
@@ -101,8 +113,7 @@ export class MainViewProxy {
101
113
  () => this.mainViewCamera,
102
114
  camera => {
103
115
  if (camera && camera.id !== this.manager.uid) {
104
- this.moveCameraToContian(this.mainViewSize);
105
- this.moveCamera(camera);
116
+ this.synchronizer.onRemoteUpdate(camera, this.mainViewSize);
106
117
  }
107
118
  },
108
119
  { fireImmediately: true }
@@ -111,8 +122,7 @@ export class MainViewProxy {
111
122
 
112
123
  public sizeChangeHandler = debounce((size: Size) => {
113
124
  if (size) {
114
- this.moveCameraToContian(size);
115
- this.moveCamera(this.mainViewCamera);
125
+ this.synchronizer.onLocalSizeUpdate(size);
116
126
  }
117
127
  }, 30);
118
128
 
@@ -122,7 +132,7 @@ export class MainViewProxy {
122
132
  if (size.id === this.manager.uid) {
123
133
  this.setCameraAndSize();
124
134
  }
125
- }
135
+ };
126
136
 
127
137
  public get view(): View {
128
138
  return this.mainView;
@@ -138,6 +148,7 @@ export class MainViewProxy {
138
148
  if (mainViewScenePath) {
139
149
  setViewFocusScenePath(mainView, mainViewScenePath);
140
150
  }
151
+ this.synchronizer.setView(mainView);
141
152
  return mainView;
142
153
  }
143
154
 
@@ -172,12 +183,20 @@ export class MainViewProxy {
172
183
  }
173
184
 
174
185
  private onCameraUpdatedByDevice = (camera: Camera) => {
175
- this.store.setMainViewCamera({ ...camera, id: this.manager.uid });
176
- if (!isEqual(this.mainViewSize, { ...this.mainView.size, id: this.manager.uid })) {
177
- this.setMainViewSize(this.view.size);
186
+ this.synchronizer.onLocalCameraUpdate(camera);
187
+ const size = this.getStageSize();
188
+ if (size && !isEqual(size, this.mainViewSize)) {
189
+ this.setMainViewSize(size);
178
190
  }
179
191
  };
180
192
 
193
+ private getStageSize(): Size | undefined {
194
+ const stage = this.manager.boxManager?.stageRect;
195
+ if (stage) {
196
+ return { width: stage.width, height: stage.height };
197
+ }
198
+ }
199
+
181
200
  public addMainViewListener(): void {
182
201
  if (this.mainViewIsAddListener) return;
183
202
  if (this.view.divElement) {
@@ -205,7 +224,7 @@ export class MainViewProxy {
205
224
  this.manager.boxManager?.blurAllBox();
206
225
  }
207
226
 
208
- public setMainViewSize = debounce(size => {
227
+ public setMainViewSize = debounce((size: Size) => {
209
228
  this.store.setMainViewSize({ ...size, id: this.manager.uid });
210
229
  }, 50);
211
230
 
@@ -225,33 +244,6 @@ export class MainViewProxy {
225
244
  callbacks.emit("cameraStateChange", this.cameraState);
226
245
  };
227
246
 
228
- public moveCameraToContian(size: Size): void {
229
- if (!isEmpty(size)) {
230
- this.view.moveCameraToContain({
231
- width: size.width,
232
- height: size.height,
233
- originX: -size.width / 2,
234
- originY: -size.height / 2,
235
- animationMode: AnimationMode.Immediately,
236
- });
237
- this.scale = this.view.camera.scale;
238
- }
239
- }
240
-
241
- public moveCamera(camera: Camera): void {
242
- if (!isEmpty(camera)) {
243
- if (isEqual(camera, this.view.camera)) return;
244
- const { centerX, centerY, scale } = camera;
245
- const needScale = scale * (this.scale || 1);
246
- this.view.moveCamera({
247
- centerX: centerX,
248
- centerY: centerY,
249
- scale: needScale,
250
- animationMode: AnimationMode.Immediately,
251
- });
252
- }
253
- }
254
-
255
247
  public stop() {
256
248
  this.removeCameraListener();
257
249
  this.manager.refresher?.remove(Fields.MainViewCamera);
package/src/constants.ts CHANGED
@@ -57,3 +57,5 @@ 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;
package/src/index.ts CHANGED
@@ -3,7 +3,6 @@ import { AppManager } from "./AppManager";
3
3
  import { appRegister } from "./Register";
4
4
  import { callbacks } from "./callback";
5
5
  import { checkVersion, setupWrapper } from "./Helper";
6
- import { ContainerResizeObserver } from "./ContainerResizeObserver";
7
6
  import { createBoxManager } from "./BoxManager";
8
7
  import { CursorManager } from "./Cursor";
9
8
  import { DEFAULT_CONTAINER_RATIO, Events, INIT_DIR, ROOT_DIR } from "./constants";
@@ -145,7 +144,6 @@ export const reconnectRefresher = new ReconnectRefresher({ emitter });
145
144
  export class WindowManager extends InvisiblePlugin<WindowMangerAttributes> implements PageController {
146
145
  public static kind = "WindowManager";
147
146
  public static displayer: Displayer;
148
- public static wrapper?: HTMLElement;
149
147
  public static playground?: HTMLElement;
150
148
  public static container?: HTMLElement;
151
149
  public static debug = false;
@@ -168,7 +166,6 @@ export class WindowManager extends InvisiblePlugin<WindowMangerAttributes> imple
168
166
  private boxManager?: BoxManager;
169
167
  private static params?: MountParams;
170
168
 
171
- private containerResizeObserver?: ContainerResizeObserver;
172
169
  public containerSizeRatio = WindowManager.containerSizeRatio;
173
170
 
174
171
  constructor(context: InvisiblePluginContext) {
@@ -237,7 +234,13 @@ export class WindowManager extends InvisiblePlugin<WindowMangerAttributes> imple
237
234
  if (containerSizeRatio) {
238
235
  manager.containerSizeRatio = containerSizeRatio;
239
236
  }
240
-
237
+ manager.boxManager = createBoxManager(manager, callbacks, emitter, boxEmitter, {
238
+ collectorContainer: params.collectorContainer,
239
+ collectorStyles: params.collectorStyles,
240
+ prefersColorScheme: params.prefersColorScheme,
241
+ stageRatio: params.containerSizeRatio,
242
+ });
243
+ manager.appManager?.setBoxManager(manager.boxManager);
241
244
  if (params.container) {
242
245
  manager.bindContainer(params.container);
243
246
  }
@@ -283,31 +286,19 @@ export class WindowManager extends InvisiblePlugin<WindowMangerAttributes> imple
283
286
  }
284
287
 
285
288
  private static initContainer(
286
- manager: WindowManager,
287
289
  container: HTMLElement,
288
- chessboard: boolean | undefined,
289
290
  overwriteStyles: string | undefined
290
291
  ) {
291
292
  if (!WindowManager.container) {
292
293
  WindowManager.container = container;
293
294
  }
294
- const { playground, wrapper, sizer, mainViewElement } = setupWrapper(container);
295
+ const { playground, mainViewElement } = setupWrapper(container);
295
296
  WindowManager.playground = playground;
296
- if (chessboard) {
297
- sizer.classList.add("netless-window-manager-chess-sizer");
298
- }
299
297
  if (overwriteStyles) {
300
298
  const style = document.createElement("style");
301
299
  style.textContent = overwriteStyles;
302
300
  playground.appendChild(style);
303
301
  }
304
- manager.containerResizeObserver = ContainerResizeObserver.create(
305
- playground,
306
- sizer,
307
- wrapper,
308
- emitter
309
- );
310
- WindowManager.wrapper = wrapper;
311
302
  return mainViewElement;
312
303
  }
313
304
 
@@ -327,24 +318,15 @@ export class WindowManager extends InvisiblePlugin<WindowMangerAttributes> imple
327
318
  if (WindowManager.params) {
328
319
  const params = WindowManager.params;
329
320
  const mainViewElement = WindowManager.initContainer(
330
- this,
331
321
  container,
332
- params.chessboard,
333
322
  params.overwriteStyles
334
323
  );
335
- if (this.boxManager) {
336
- this.boxManager.destroy();
324
+ if (this.boxManager && WindowManager.playground) {
325
+ this.boxManager.setRoot(WindowManager.playground);
337
326
  }
338
- const boxManager = createBoxManager(this, callbacks, emitter, boxEmitter, {
339
- collectorContainer: params.collectorContainer,
340
- collectorStyles: params.collectorStyles,
341
- prefersColorScheme: params.prefersColorScheme,
342
- });
343
- this.boxManager = boxManager;
344
- this.appManager?.setBoxManager(boxManager);
345
327
  this.bindMainView(mainViewElement, params.disableCameraTransform);
346
- if (WindowManager.wrapper) {
347
- this.cursorManager?.setupWrapper(WindowManager.wrapper);
328
+ if (WindowManager.playground) {
329
+ this.cursorManager?.setupWrapper(WindowManager.playground);
348
330
  }
349
331
  }
350
332
  }
@@ -358,7 +340,7 @@ export class WindowManager extends InvisiblePlugin<WindowMangerAttributes> imple
358
340
 
359
341
  public bindCollectorContainer(container: HTMLElement) {
360
342
  if (WindowManager.isCreated && this.boxManager) {
361
- this.boxManager.setCollectorContainer(container);
343
+ this.boxManager.setCollector(container);
362
344
  } else {
363
345
  if (WindowManager.params) {
364
346
  WindowManager.params.collectorContainer = container;
@@ -802,11 +784,9 @@ export class WindowManager extends InvisiblePlugin<WindowMangerAttributes> imple
802
784
  }
803
785
 
804
786
  private _destroy() {
805
- this.containerResizeObserver?.disconnect();
806
787
  this.appManager?.destroy();
807
788
  this.cursorManager?.destroy();
808
789
  WindowManager.container = undefined;
809
- WindowManager.wrapper = undefined;
810
790
  WindowManager.isCreated = false;
811
791
  if (WindowManager.playground) {
812
792
  WindowManager.playground.parentNode?.removeChild(WindowManager.playground);
package/src/typings.ts CHANGED
@@ -13,6 +13,7 @@ import type {
13
13
  import type { AppContext } from "./App";
14
14
  import type { ReadonlyTeleBox, TeleBoxRect } from "@netless/telebox-insider";
15
15
  import type { PageState } from "./Page";
16
+ import type { Member } from "./Helper";
16
17
 
17
18
  export interface NetlessApp<Attributes = any, MagixEventPayloads = any, AppOptions = any, SetupResult = any> {
18
19
  kind: string;
@@ -53,6 +54,7 @@ export type AppEmitterEvent<T = any> = {
53
54
  reconnected: void;
54
55
  seek: number;
55
56
  pageStateChange: PageState,
57
+ roomMembersChange: Member[];
56
58
  };
57
59
 
58
60
  export type RegisterEventData = {
@@ -79,8 +81,10 @@ export type AppListenerKeys = keyof AppEmitterEvent;
79
81
  export type ApplianceIcons = Partial<Record<ApplianceNames, string>>;
80
82
 
81
83
  export type { AppContext } from "./App/AppContext";
84
+ export type { WhiteBoardView } from "./App";
82
85
  export type { ReadonlyTeleBox, TeleBoxRect };
83
86
  export type { SceneState, SceneDefinition, View, AnimationMode, Displayer, Room, Player };
84
87
  export type { Storage, StorageStateChangedEvent, StorageStateChangedListener } from "./App/Storage";
85
88
  export * from "./Page";
86
89
  export * from "./Utils/error";
90
+ export type { Member } from "./Helper";
package/vite.config.js CHANGED
@@ -39,7 +39,6 @@ export default defineConfig(({ mode }) => {
39
39
  fileName: "index"
40
40
  },
41
41
  outDir: "dist",
42
- sourcemap: true,
43
42
  rollupOptions: {
44
43
  external: Object.keys({
45
44
  ...omit(dependencies, ["@netless/telebox-insider"]),
@@ -1,11 +0,0 @@
1
- import type { EmitterType } from "./InternalEmitter";
2
- export declare class ContainerResizeObserver {
3
- private emitter;
4
- private containerResizeObserver?;
5
- private disposer?;
6
- constructor(emitter: EmitterType);
7
- static create(container: HTMLElement, sizer: HTMLElement, wrapper: HTMLDivElement, emitter: EmitterType): ContainerResizeObserver;
8
- observePlaygroundSize(container: HTMLElement, sizer: HTMLElement, wrapper: HTMLDivElement): void;
9
- updateSizer({ width, height }: DOMRectReadOnly, sizer: HTMLElement, wrapper: HTMLDivElement): void;
10
- disconnect(): void;
11
- }