@netless/window-manager 0.4.0-canary.1 → 0.4.0-canary.10

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 (62) hide show
  1. package/dist/App/Storage/StorageEvent.d.ts +8 -0
  2. package/dist/App/Storage/index.d.ts +26 -0
  3. package/dist/App/Storage/typings.d.ts +21 -0
  4. package/dist/App/Storage/utils.d.ts +5 -0
  5. package/dist/AppContext.d.ts +3 -1
  6. package/dist/AppListener.d.ts +0 -1
  7. package/dist/AppManager.d.ts +7 -7
  8. package/dist/AppProxy.d.ts +2 -3
  9. package/dist/Base/Context.d.ts +0 -1
  10. package/dist/BoxManager.d.ts +2 -1
  11. package/dist/BuiltinApps.d.ts +6 -0
  12. package/dist/ContainerResizeObserver.d.ts +10 -0
  13. package/dist/Cursor/Cursor.d.ts +2 -3
  14. package/dist/Cursor/index.d.ts +7 -4
  15. package/dist/Helper.d.ts +6 -0
  16. package/dist/ReconnectRefresher.d.ts +5 -2
  17. package/dist/Utils/Common.d.ts +3 -1
  18. package/dist/Utils/Reactive.d.ts +1 -1
  19. package/dist/{MainView.d.ts → View/MainView.d.ts} +2 -4
  20. package/dist/View/ViewManager.d.ts +13 -0
  21. package/dist/constants.d.ts +1 -6
  22. package/dist/index.d.ts +13 -13
  23. package/dist/index.es.js +1 -1
  24. package/dist/index.es.js.map +1 -1
  25. package/dist/index.umd.js +1 -1
  26. package/dist/index.umd.js.map +1 -1
  27. package/dist/style.css +1 -1
  28. package/dist/typings.d.ts +1 -0
  29. package/package.json +5 -4
  30. package/src/App/Storage/StorageEvent.ts +21 -0
  31. package/src/App/Storage/index.ts +243 -0
  32. package/src/App/Storage/typings.ts +21 -0
  33. package/src/App/Storage/utils.ts +17 -0
  34. package/src/AppContext.ts +10 -2
  35. package/src/AppListener.ts +1 -8
  36. package/src/AppManager.ts +54 -35
  37. package/src/AppProxy.ts +14 -36
  38. package/src/Base/Context.ts +0 -4
  39. package/src/BoxManager.ts +9 -7
  40. package/src/BuiltinApps.ts +24 -0
  41. package/src/ContainerResizeObserver.ts +62 -0
  42. package/src/Cursor/Cursor.ts +23 -34
  43. package/src/Cursor/index.ts +70 -41
  44. package/src/Helper.ts +30 -0
  45. package/src/ReconnectRefresher.ts +13 -5
  46. package/src/Utils/Common.ts +35 -13
  47. package/src/Utils/Reactive.ts +9 -3
  48. package/src/Utils/RoomHacker.ts +15 -0
  49. package/src/{MainView.ts → View/MainView.ts} +9 -25
  50. package/src/View/ViewManager.ts +53 -0
  51. package/src/constants.ts +1 -3
  52. package/src/index.ts +46 -86
  53. package/src/shim.d.ts +4 -0
  54. package/src/style.css +6 -0
  55. package/src/typings.ts +1 -0
  56. package/vite.config.js +4 -1
  57. package/dist/Utils/CameraStore.d.ts +0 -15
  58. package/dist/ViewManager.d.ts +0 -29
  59. package/dist/sdk.d.ts +0 -14
  60. package/src/Utils/CameraStore.ts +0 -72
  61. package/src/sdk.ts +0 -39
  62. package/src/viewManager.ts +0 -177
package/src/AppProxy.ts CHANGED
@@ -2,16 +2,15 @@ import Emittery from "emittery";
2
2
  import { AppAttributes, AppEvents, Events } from "./constants";
3
3
  import { AppContext } from "./AppContext";
4
4
  import { appRegister } from "./Register";
5
- import { autorun, ViewVisionMode } from "white-web-sdk";
6
- import { callbacks, emitter } from "./index";
5
+ import { autorun } from "white-web-sdk";
6
+ import { emitter } from "./index";
7
7
  import { Fields } from "./AttributesDelegate";
8
8
  import { get } from "lodash";
9
9
  import { log } from "./Utils/log";
10
10
  import {
11
- notifyMainViewModeChange,
12
11
  setScenePath,
13
12
  setViewFocusScenePath,
14
- setViewMode,
13
+ getScenePath
15
14
  } from "./Utils/Common";
16
15
  import type {
17
16
  AppEmitterEvent,
@@ -37,7 +36,6 @@ export class AppProxy extends Base {
37
36
  private boxManager = this.manager.boxManager;
38
37
  private appProxies = this.manager.appProxies;
39
38
  private viewManager = this.manager.viewManager;
40
- private cameraStore = this.manager.cameraStore;
41
39
  private kind: string;
42
40
  public isAddApp: boolean;
43
41
  private status: "normal" | "destroyed" = "normal";
@@ -98,17 +96,25 @@ export class AppProxy extends Base {
98
96
 
99
97
  public getFullScenePath(): string | undefined {
100
98
  if (this.scenePath) {
101
- return get(this.appAttributes, [Fields.FullPath], this.scenePath);
99
+ return get(this.appAttributes, [Fields.FullPath], this.getFullScenePathFromScenes());
102
100
  }
103
101
  }
104
102
 
103
+ private getFullScenePathFromScenes() {
104
+ const sceneIndex = get(this.appAttributes, ["state", "SceneIndex"], 0);
105
+ const fullPath = getScenePath(this.manager.room, this.scenePath, sceneIndex);
106
+ if (fullPath) {
107
+ this.setFullPath(fullPath);
108
+ }
109
+ return fullPath;
110
+ }
111
+
105
112
  public setFullPath(path: string) {
106
113
  this.manager.safeUpdateAttributes(["apps", this.id, Fields.FullPath], path);
107
114
  }
108
115
 
109
116
  public async baseInsertApp(
110
117
  skipUpdate = false,
111
- focus?: boolean
112
118
  ): Promise<{ appId: string; app: NetlessApp }> {
113
119
  const params = this.params;
114
120
  if (!params.kind) {
@@ -122,9 +128,6 @@ export class AppProxy extends Base {
122
128
  throw new Error(`[WindowManager]: app load failed ${params.kind} ${params.src}`);
123
129
  }
124
130
  this.context.updateManagerRect();
125
- if (focus) {
126
- this.focusApp();
127
- }
128
131
  return {
129
132
  appId: this.id,
130
133
  app: appImpl,
@@ -133,7 +136,6 @@ export class AppProxy extends Base {
133
136
 
134
137
  private focusApp() {
135
138
  this.focusBox();
136
- this.context.switchAppToWriter(this.id);
137
139
  this.store.setMainViewFocusPath(this.manager.mainView);
138
140
  }
139
141
 
@@ -205,9 +207,6 @@ export class AppProxy extends Base {
205
207
 
206
208
  private afterSetupApp(boxInitState: AppInitState | undefined): void {
207
209
  if (boxInitState) {
208
- if (boxInitState.focus && this.scenePath) {
209
- this.context.switchAppToWriter(this.id);
210
- }
211
210
  if (!boxInitState?.x || !boxInitState.y) {
212
211
  this.boxManager?.setBoxInitState(this.id);
213
212
  }
@@ -226,29 +225,10 @@ export class AppProxy extends Base {
226
225
  await this.destroy(true, false, true);
227
226
  const params = this.params;
228
227
  const appProxy = new AppProxy(params, this.manager, this.id, this.isAddApp);
229
- await appProxy.baseInsertApp(true, this.store.focus === this.id);
228
+ await appProxy.baseInsertApp(true);
230
229
  this.boxManager?.updateBoxState(currentAppState);
231
230
  }
232
231
 
233
- public switchToWritable() {
234
- appRegister.notifyApp(this.kind, "focus", { appId: this.id });
235
- this.cameraStore.switchView(this.id, this.view, () => {
236
- if (this.view) {
237
- if (this.view.mode === ViewVisionMode.Writable) return;
238
- try {
239
- if (this.manager.mainView.mode === ViewVisionMode.Writable) {
240
- this.store.setMainViewFocusPath(this.manager.mainView);
241
- notifyMainViewModeChange(callbacks, ViewVisionMode.Freedom);
242
- setViewMode(this.manager.mainView, ViewVisionMode.Freedom);
243
- }
244
- setViewMode(this.view, ViewVisionMode.Writable);
245
- } catch (error) {
246
- log("switch view failed", error);
247
- }
248
- }
249
- });
250
- }
251
-
252
232
  public getAppInitState = (id: string) => {
253
233
  const attrs = this.store.getAppState(id);
254
234
  if (!attrs) return;
@@ -364,7 +344,6 @@ export class AppProxy extends Base {
364
344
 
365
345
  private async createView(): Promise<View> {
366
346
  const view = await this.viewManager.createView(this.id);
367
- this.cameraStore.register(this.id, view);
368
347
  this.setViewFocusScenePath();
369
348
  return view;
370
349
  }
@@ -388,7 +367,6 @@ export class AppProxy extends Base {
388
367
  this.store.cleanAppAttributes(this.id);
389
368
  }
390
369
  this.appProxies.delete(this.id);
391
- this.cameraStore.unregister(this.id, this.view);
392
370
 
393
371
  this.viewManager.destroyView(this.id);
394
372
  this.manager.appStatus.delete(this.id);
@@ -33,10 +33,6 @@ export class Context {
33
33
  public blurFocusBox() {
34
34
  this.manager.boxManager?.blurAllBox();
35
35
  }
36
-
37
- public switchAppToWriter(id: string) {
38
- this.manager.viewManager.switchAppToWriter(id);
39
- }
40
36
  }
41
37
 
42
38
  let context: Context;
package/src/BoxManager.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { AppAttributes, DEFAULT_COLLECTOR_STYLE, Events, MIN_HEIGHT, MIN_WIDTH } from "./constants";
1
+ import { AppAttributes, Events, MIN_HEIGHT, MIN_WIDTH } from "./constants";
2
2
  import { debounce, maxBy } from "lodash";
3
3
  import {
4
4
  TELE_BOX_MANAGER_EVENT,
@@ -6,7 +6,7 @@ import {
6
6
  TeleBoxCollector,
7
7
  TeleBoxManager,
8
8
  } from "@netless/telebox-insider";
9
- import { WindowManager } from "./index";
9
+ import { emitter, WindowManager } from "./index";
10
10
  import type { AddAppOptions, AppInitState, EmitterType, CallbacksType } from "./index";
11
11
  import type {
12
12
  TeleBoxManagerUpdateConfig,
@@ -145,6 +145,11 @@ export class BoxManager {
145
145
  this.teleBoxManager.events.on("z_index", box => {
146
146
  this.context.updateAppState(box.id, AppAttributes.ZIndex, box.zIndex);
147
147
  });
148
+ emitter.on("playgroundSizeChange", this.playgroundSizeChangeListener);
149
+ }
150
+
151
+ private playgroundSizeChangeListener = () => {
152
+ this.updateManagerRect();
148
153
  }
149
154
 
150
155
  private get mainView() {
@@ -251,12 +256,8 @@ export class BoxManager {
251
256
  }
252
257
 
253
258
  public setCollectorContainer(container: HTMLElement) {
254
- const styles = {
255
- ...DEFAULT_COLLECTOR_STYLE,
256
- ...this.createTeleBoxManagerConfig?.collectorStyles,
257
- };
258
259
  const collector = new TeleBoxCollector({
259
- styles
260
+ styles: this.createTeleBoxManagerConfig?.collectorStyles,
260
261
  }).mount(container);
261
262
  this.teleBoxManager.setCollector(collector);
262
263
  }
@@ -391,6 +392,7 @@ export class BoxManager {
391
392
  }
392
393
 
393
394
  public destroy() {
395
+ emitter.off("playgroundSizeChange", this.playgroundSizeChangeListener);
394
396
  this.teleBoxManager.destroy();
395
397
  }
396
398
  }
@@ -0,0 +1,24 @@
1
+ import AppDocsViewer from "@netless/app-docs-viewer";
2
+ import AppMediaPlayer, { setOptions } from "@netless/app-media-player";
3
+ import { WindowManager } from "./index";
4
+ import "@netless/app-docs-viewer/dist/style.css";
5
+
6
+ export const setupBuiltin = () => {
7
+ if (WindowManager.debug) {
8
+ setOptions({ verbose: true });
9
+ }
10
+
11
+ WindowManager.register({
12
+ kind: AppDocsViewer.kind,
13
+ src: AppDocsViewer,
14
+ });
15
+ WindowManager.register({
16
+ kind: AppMediaPlayer.kind,
17
+ src: AppMediaPlayer,
18
+ });
19
+ };
20
+
21
+ export const BuiltinApps = {
22
+ DocsViewer: AppDocsViewer.kind as string,
23
+ MediaPlayer: AppMediaPlayer.kind as string,
24
+ };
@@ -0,0 +1,62 @@
1
+ import { ResizeObserver as ResizeObserverPolyfill } from "@juggle/resize-observer";
2
+ import { WindowManager } from "./index";
3
+ import type { EmitterType} from "./index";
4
+
5
+ const ResizeObserver = window.ResizeObserver || ResizeObserverPolyfill;
6
+
7
+ export class ContainerResizeObserver {
8
+ private containerResizeObserver?: ResizeObserver;
9
+
10
+ constructor(private emitter: EmitterType) {}
11
+
12
+ public static create(
13
+ container: HTMLElement,
14
+ sizer: HTMLElement,
15
+ wrapper: HTMLDivElement,
16
+ emitter: EmitterType,
17
+ ) {
18
+ const containerResizeObserver = new ContainerResizeObserver(emitter);
19
+ containerResizeObserver.observePlaygroundSize(container, sizer, wrapper);
20
+ return containerResizeObserver;
21
+ }
22
+
23
+ public observePlaygroundSize(
24
+ container: HTMLElement,
25
+ sizer: HTMLElement,
26
+ wrapper: HTMLDivElement
27
+ ) {
28
+ this.updateSizer(container.getBoundingClientRect(), sizer, wrapper);
29
+
30
+ this.containerResizeObserver = new ResizeObserver(entries => {
31
+ const containerRect = entries[0]?.contentRect;
32
+ if (containerRect) {
33
+ this.updateSizer(containerRect, sizer, wrapper);
34
+ this.emitter.emit("playgroundSizeChange", containerRect)
35
+ }
36
+ });
37
+
38
+ this.containerResizeObserver.observe(container);
39
+ }
40
+
41
+ private updateSizer(
42
+ { width, height }: DOMRectReadOnly,
43
+ sizer: HTMLElement,
44
+ wrapper: HTMLDivElement
45
+ ) {
46
+ if (width && height) {
47
+ if (height / width > WindowManager.containerSizeRatio) {
48
+ height = width * WindowManager.containerSizeRatio;
49
+ sizer.classList.toggle("netless-window-manager-sizer-horizontal", true);
50
+ } else {
51
+ width = height / WindowManager.containerSizeRatio;
52
+ sizer.classList.toggle("netless-window-manager-sizer-horizontal", false);
53
+ }
54
+ wrapper.style.width = `${width}px`;
55
+ wrapper.style.height = `${height}px`;
56
+ }
57
+ }
58
+
59
+ public disconnect() {
60
+ this.containerResizeObserver?.disconnect();
61
+ }
62
+ }
@@ -1,7 +1,6 @@
1
1
  import App from './Cursor.svelte';
2
- import pRetry from 'p-retry';
3
2
  import { ApplianceMap } from './icons';
4
- import { ApplianceNames, autorun } from 'white-web-sdk';
3
+ import { ApplianceNames } from 'white-web-sdk';
5
4
  import { CursorState } from '../constants';
6
5
  import { Fields } from '../AttributesDelegate';
7
6
  import { get, omit } from 'lodash';
@@ -19,54 +18,44 @@ export type Payload = {
19
18
 
20
19
  export class Cursor extends Base {
21
20
  private member?: RoomMember;
22
- private disposer: any;
23
21
  private timer?: number;
24
22
  private component?: SvelteComponent;
25
23
 
26
24
  constructor(
27
25
  manager: AppManager,
26
+ addCursorChangeListener: (uid: string, callback: (position: Position, state: CursorState) => void) => void,
28
27
  private cursors: any,
29
28
  private memberId: string,
30
29
  private cursorManager: CursorManager,
31
- private wrapper?: HTMLElement
30
+ private wrapper?: HTMLElement,
32
31
  ) {
33
32
  super(manager);
34
33
  this.setMember();
35
34
  this.createCursor();
36
- pRetry(() => {
37
- this.disposer && this.disposer();
38
- if (!this.cursorPosition) {
39
- console.warn(`${memberId} not exist`);
40
- }
41
- this.startReaction();
42
- }, { retries: 3 });
35
+ addCursorChangeListener(this.memberId, this.onCursorChange);
43
36
  this.autoHidden();
44
37
  }
45
38
 
46
- private startReaction() {
47
- this.disposer = autorun(() => {
48
- const cursor = this.cursorPosition;
49
- const state = this.cursorState;
50
- if (!cursor) return;
51
- if (cursor.type === "main") {
52
- const rect = this.cursorManager.wrapperRect;
53
- if (this.component && rect) {
54
- this.autoHidden();
55
- this.moveCursor(cursor, rect, this.manager.mainView);
56
- }
57
- } else {
58
- const focusView = this.cursorManager.focusView;
59
- const viewRect = focusView?.divElement?.getBoundingClientRect();
60
- const viewCamera = focusView?.camera;
61
- if (focusView && viewRect && viewCamera && this.component) {
62
- this.autoHidden();
63
- this.moveCursor(cursor, viewRect, focusView);
64
- }
39
+ private onCursorChange = (position: Position, state: CursorState) => {
40
+ if (position.type === "main") {
41
+ const rect = this.cursorManager.wrapperRect;
42
+ if (this.component && rect) {
43
+ this.autoHidden();
44
+ this.moveCursor(position, rect, this.manager.mainView);
65
45
  }
66
- if (state && state === CursorState.Leave) {
67
- this.hide();
46
+ } else {
47
+ const focusView = this.cursorManager.focusView;
48
+ // TODO 可以存一个当前 focusView 的 Rect 这样只有 focus 切换的时候才调用 getBoundingClientRect
49
+ const viewRect = focusView?.divElement?.getBoundingClientRect();
50
+ const viewCamera = focusView?.camera;
51
+ if (focusView && viewRect && viewCamera && this.component) {
52
+ this.autoHidden();
53
+ this.moveCursor(position, viewRect, focusView);
68
54
  }
69
- });
55
+ }
56
+ if (state && state === CursorState.Leave) {
57
+ this.hide();
58
+ }
70
59
  }
71
60
 
72
61
  private moveCursor(cursor: Position, rect: DOMRect, view: any) {
@@ -196,10 +185,10 @@ export class Cursor extends Base {
196
185
  }
197
186
 
198
187
  public destroy() {
199
- this.disposer && this.disposer();
200
188
  if (this.component) {
201
189
  this.component.$destroy();
202
190
  }
191
+ this.manager.refresher?.remove(this.memberId);
203
192
  this.cursorManager.cursorInstances.delete(this.memberId);
204
193
  }
205
194
 
@@ -1,11 +1,13 @@
1
- import { Base } from '../Base';
2
- import { Cursor } from './Cursor';
3
- import { CursorState } from '../constants';
4
- import { compact, debounce, uniq } from 'lodash';
5
- import { Fields } from '../AttributesDelegate';
6
- import { onObjectInserted } from '../Utils/Reactive';
7
- import { WindowManager } from '../index';
8
- import type { PositionType } from "../AttributesDelegate";
1
+ import { autorun } from "white-web-sdk";
2
+ import { Base } from "../Base";
3
+ import { compact, debounce, get, uniq } from "lodash";
4
+ import { Cursor } from "./Cursor";
5
+ import { CursorState } from "../constants";
6
+ import { emitter, WindowManager } from "../index";
7
+ import { Fields } from "../AttributesDelegate";
8
+ import { onObjectInserted } from "../Utils/Reactive";
9
+ import { SideEffectManager } from "side-effect-manager";
10
+ import type { PositionType, Position } from "../AttributesDelegate";
9
11
  import type { Point, RoomMember, View } from "white-web-sdk";
10
12
  import type { AppManager } from "../AppManager";
11
13
 
@@ -18,32 +20,42 @@ export type MoveCursorParams = {
18
20
  uid: string;
19
21
  x: number;
20
22
  y: number;
21
- }
23
+ };
22
24
  export class CursorManager extends Base {
23
25
  public containerRect?: DOMRect;
24
26
  public wrapperRect?: DOMRect;
25
27
  public cursorInstances: Map<string, Cursor> = new Map();
26
28
  public roomMembers?: readonly RoomMember[];
27
29
  private mainViewElement?: HTMLDivElement;
30
+ private sideEffectManager = new SideEffectManager();
28
31
 
29
32
  constructor(private appManager: AppManager) {
30
33
  super(appManager);
31
34
  this.roomMembers = this.appManager.room?.state.roomMembers;
32
35
  const wrapper = WindowManager.wrapper;
33
36
  if (wrapper) {
34
- this.setupWrapper(wrapper);
37
+ this.setupWrapper(wrapper);
35
38
  }
39
+ emitter.on("onReconnected", () => {
40
+ this.onReconnect();
41
+ });
36
42
  }
37
43
 
38
44
  public setupWrapper(wrapper: HTMLElement) {
39
45
  if (this.manager.refresher?.hasReactor("cursors")) {
40
46
  this.destroy();
41
47
  }
42
- wrapper.addEventListener("mousemove", this.mouseMoveListener);
43
- wrapper.addEventListener("touchstart", this.touchMoveListener);
44
- wrapper.addEventListener("touchmove", this.touchMoveListener);
45
- wrapper.addEventListener("mouseleave", this.mouseLeaveListener);
46
- wrapper.addEventListener("touchend", this.mouseLeaveListener);
48
+ this.sideEffectManager.add(() => {
49
+ wrapper.addEventListener("pointerenter", this.mouseMoveListener);
50
+ wrapper.addEventListener("pointermove", this.mouseMoveListener);
51
+ wrapper.addEventListener("pointerleave", this.mouseLeaveListener);
52
+ return () => {
53
+ wrapper.removeEventListener("pointerenter", this.mouseMoveListener);
54
+ wrapper.removeEventListener("pointermove", this.mouseMoveListener);
55
+ wrapper.removeEventListener("pointerleave", this.mouseLeaveListener);
56
+ };
57
+ });
58
+
47
59
  this.initCursorAttributes();
48
60
  this.wrapperRect = wrapper.getBoundingClientRect();
49
61
  this.startReaction(wrapper);
@@ -58,27 +70,25 @@ export class CursorManager extends Base {
58
70
  return onObjectInserted(this.cursors, () => {
59
71
  this.handleRoomMembersChange(wrapper);
60
72
  });
61
- })
73
+ });
62
74
  }
63
75
 
64
76
  private getUids = (members: readonly RoomMember[] | undefined) => {
65
77
  return compact(uniq(members?.map(member => member.payload?.uid)));
66
- }
78
+ };
67
79
 
68
80
  private handleRoomMembersChange = debounce((wrapper: HTMLElement) => {
69
81
  const uids = this.getUids(this.roomMembers);
70
82
  const cursors = Object.keys(this.cursors);
71
83
  if (uids?.length) {
72
84
  cursors.map(uid => {
73
- if (
74
- uids.includes(uid) &&
75
- !this.cursorInstances.has(uid)
76
- ) {
85
+ if (uids.includes(uid) && !this.cursorInstances.has(uid)) {
77
86
  if (uid === this.context.uid) {
78
87
  return;
79
88
  }
80
89
  const component = new Cursor(
81
90
  this.appManager,
91
+ this.addCursorChangeListener,
82
92
  this.cursors,
83
93
  uid,
84
94
  this,
@@ -86,7 +96,7 @@ export class CursorManager extends Base {
86
96
  );
87
97
  this.cursorInstances.set(uid, component);
88
98
  }
89
- })
99
+ });
90
100
  }
91
101
  }, 100);
92
102
 
@@ -106,13 +116,6 @@ export class CursorManager extends Base {
106
116
  this.updateCursor(this.getType(event), event.clientX, event.clientY);
107
117
  }, 5);
108
118
 
109
- private touchMoveListener = debounce((event: TouchEvent) => {
110
- if (event.touches.length === 1) {
111
- const touchEvent = event.touches[0];
112
- this.updateCursor(this.getType(touchEvent), touchEvent.clientX, touchEvent.clientY);
113
- }
114
- }, 5);
115
-
116
119
  private updateCursor(event: EventType, clientX: number, clientY: number) {
117
120
  if (this.wrapperRect && this.manager.canOperate) {
118
121
  const view = event.type === "main" ? this.appManager.mainView : this.focusView;
@@ -128,7 +131,11 @@ export class CursorManager extends Base {
128
131
  }
129
132
  }
130
133
 
131
- private getPoint = (view: View | undefined, clientX: number, clientY: number): Point | undefined => {
134
+ private getPoint = (
135
+ view: View | undefined,
136
+ clientX: number,
137
+ clientY: number
138
+ ): Point | undefined => {
132
139
  const rect = view?.divElement?.getBoundingClientRect();
133
140
  if (rect) {
134
141
  const point = view?.convertToPointInWorld({
@@ -137,7 +144,7 @@ export class CursorManager extends Base {
137
144
  });
138
145
  return point;
139
146
  }
140
- }
147
+ };
141
148
 
142
149
  /**
143
150
  * 因为窗口内框在不同分辨率下的大小不一样,所以这里通过来鼠标事件的 target 来判断是在主白板还是在 APP 中
@@ -147,7 +154,7 @@ export class CursorManager extends Base {
147
154
  const focusApp = this.appManager.focusApp;
148
155
  switch (target.parentElement) {
149
156
  case this.mainViewElement: {
150
- return { type: "main" };
157
+ return { type: "main" };
151
158
  }
152
159
  case focusApp?.view?.divElement: {
153
160
  return { type: "app" };
@@ -224,19 +231,41 @@ export class CursorManager extends Base {
224
231
  });
225
232
  }
226
233
 
227
- public destroy() {
228
- const wrapper = WindowManager.wrapper;
229
- if (wrapper) {
230
- wrapper.removeEventListener("mousemove", this.mouseMoveListener);
231
- wrapper.removeEventListener("touchstart", this.touchMoveListener);
232
- wrapper.removeEventListener("touchmove", this.touchMoveListener);
233
- wrapper.removeEventListener("mouseleave", this.mouseLeaveListener);
234
- wrapper.removeEventListener("touchend", this.mouseLeaveListener);
235
- }
234
+ public onReconnect() {
236
235
  if (this.cursorInstances.size) {
237
236
  this.cursorInstances.forEach(cursor => cursor.destroy());
238
237
  this.cursorInstances.clear();
239
238
  }
239
+ this.roomMembers = this.appManager.room?.state.roomMembers;
240
+ if (WindowManager.wrapper) {
241
+ this.handleRoomMembersChange(WindowManager.wrapper);
242
+ }
243
+ }
244
+
245
+ public addCursorChangeListener = (
246
+ uid: string,
247
+ callback: (position: Position, state: CursorState) => void
248
+ ) => {
249
+ this.manager.refresher?.add(uid, () => {
250
+ const disposer = autorun(() => {
251
+ const position = get(this.cursors, [uid, Fields.Position]);
252
+ const state = get(this.cursors, [uid, Fields.CursorState]);
253
+ if (position) {
254
+ callback(position, state);
255
+ }
256
+ });
257
+ return disposer;
258
+ });
259
+ };
260
+
261
+ public destroy() {
262
+ this.sideEffectManager.flushAll();
263
+ if (this.cursorInstances.size) {
264
+ this.cursorInstances.forEach(cursor => {
265
+ cursor.destroy();
266
+ });
267
+ this.cursorInstances.clear();
268
+ }
240
269
  this.manager.refresher?.remove("cursors");
241
270
  }
242
271
  }
package/src/Helper.ts ADDED
@@ -0,0 +1,30 @@
1
+ import { WindowManager } from "./index";
2
+
3
+ export const setupWrapper = (
4
+ root: HTMLElement
5
+ ): {
6
+ playground: HTMLDivElement;
7
+ wrapper: HTMLDivElement;
8
+ sizer: HTMLDivElement;
9
+ mainViewElement: HTMLDivElement;
10
+ } => {
11
+ const playground = document.createElement("div");
12
+ playground.className = "netless-window-manager-playground";
13
+
14
+ const sizer = document.createElement("div");
15
+ sizer.className = "netless-window-manager-sizer";
16
+
17
+ const wrapper = document.createElement("div");
18
+ wrapper.className = "netless-window-manager-wrapper";
19
+
20
+ const mainViewElement = document.createElement("div");
21
+ mainViewElement.className = "netless-window-manager-main-view";
22
+
23
+ playground.appendChild(sizer);
24
+ sizer.appendChild(wrapper);
25
+ wrapper.appendChild(mainViewElement);
26
+ root.appendChild(playground);
27
+ WindowManager.wrapper = wrapper;
28
+
29
+ return { playground, wrapper, sizer, mainViewElement };
30
+ };
@@ -1,11 +1,12 @@
1
- import { isFunction, debounce } from "lodash";
1
+ import { debounce, isFunction } from "lodash";
2
2
  import { log } from "./Utils/log";
3
3
  import { RoomPhase } from "white-web-sdk";
4
4
  import type { Room } from "white-web-sdk";
5
+ import type { EmitterType } from "./index";
5
6
 
6
7
  export type ReconnectRefresherContext = {
7
- notifyReconnected: () => void;
8
- }
8
+ emitter: EmitterType;
9
+ };
9
10
 
10
11
  // 白板重连之后会刷新所有的对象,导致 listener 失效, 所以这里在重连之后重新对所有对象进行监听
11
12
  export class ReconnectRefresher {
@@ -14,12 +15,19 @@ export class ReconnectRefresher {
14
15
  private reactors: Map<string, any> = new Map();
15
16
  private disposers: Map<string, any> = new Map();
16
17
 
17
- constructor(room: Room | undefined, private ctx: ReconnectRefresherContext) {
18
+ constructor(private ctx: ReconnectRefresherContext) {}
19
+
20
+ public setRoom(room: Room | undefined) {
18
21
  this.room = room;
19
22
  this.phase = room?.phase;
23
+ room?.callbacks.off("onPhaseChanged", this.onPhaseChanged);
20
24
  room?.callbacks.on("onPhaseChanged", this.onPhaseChanged);
21
25
  }
22
26
 
27
+ public setContext(ctx: ReconnectRefresherContext) {
28
+ this.ctx = ctx;
29
+ }
30
+
23
31
  private onPhaseChanged = (phase: RoomPhase) => {
24
32
  if (phase === RoomPhase.Connected && this.phase === RoomPhase.Reconnecting) {
25
33
  this.onReconnected();
@@ -35,7 +43,7 @@ export class ReconnectRefresher {
35
43
  this.disposers.set(id, func());
36
44
  }
37
45
  });
38
- this.ctx.notifyReconnected();
46
+ this.ctx.emitter.emit("onReconnected", undefined);
39
47
  }, 3000);
40
48
 
41
49
  private releaseDisposers() {