@netless/window-manager 0.4.0-canary.2 → 0.4.0-canary.23

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 (82) hide show
  1. package/.idea/inspectionProfiles/Project_Default.xml +7 -0
  2. package/.idea/modules.xml +8 -0
  3. package/.idea/vcs.xml +6 -0
  4. package/.idea/window-manager.iml +12 -0
  5. package/.vscode/settings.json +1 -0
  6. package/CHANGELOG.md +29 -1
  7. package/README.md +1 -0
  8. package/dist/App/MagixEvent/index.d.ts +29 -0
  9. package/dist/App/Storage/StorageEvent.d.ts +8 -0
  10. package/dist/App/Storage/index.d.ts +39 -0
  11. package/dist/App/Storage/typings.d.ts +22 -0
  12. package/dist/App/Storage/utils.d.ts +5 -0
  13. package/dist/AppContext.d.ts +40 -16
  14. package/dist/AppListener.d.ts +1 -1
  15. package/dist/AppManager.d.ts +15 -11
  16. package/dist/AppProxy.d.ts +7 -6
  17. package/dist/AttributesDelegate.d.ts +2 -2
  18. package/dist/BoxManager.d.ts +6 -3
  19. package/dist/BuiltinApps.d.ts +5 -0
  20. package/dist/ContainerResizeObserver.d.ts +10 -0
  21. package/dist/Cursor/Cursor.d.ts +8 -11
  22. package/dist/Cursor/index.d.ts +5 -16
  23. package/dist/Helper.d.ts +6 -0
  24. package/dist/ReconnectRefresher.d.ts +0 -1
  25. package/dist/Register/storage.d.ts +5 -1
  26. package/dist/Utils/Common.d.ts +7 -2
  27. package/dist/Utils/Reactive.d.ts +1 -1
  28. package/dist/Utils/RoomHacker.d.ts +1 -1
  29. package/dist/{MainView.d.ts → View/MainView.d.ts} +5 -6
  30. package/dist/View/ViewManager.d.ts +13 -0
  31. package/dist/constants.d.ts +3 -7
  32. package/dist/index.d.ts +25 -10
  33. package/dist/index.es.js +41 -1
  34. package/dist/index.es.js.map +1 -1
  35. package/dist/index.umd.js +41 -1
  36. package/dist/index.umd.js.map +1 -1
  37. package/dist/style.css +1 -1
  38. package/dist/typings.d.ts +3 -2
  39. package/docs/api.md +36 -6
  40. package/docs/concept.md +9 -0
  41. package/package.json +7 -6
  42. package/src/App/MagixEvent/index.ts +68 -0
  43. package/src/App/Storage/StorageEvent.ts +21 -0
  44. package/src/App/Storage/index.ts +289 -0
  45. package/src/App/Storage/typings.ts +23 -0
  46. package/src/App/Storage/utils.ts +17 -0
  47. package/src/AppContext.ts +66 -24
  48. package/src/AppListener.ts +15 -14
  49. package/src/AppManager.ts +146 -63
  50. package/src/AppProxy.ts +52 -53
  51. package/src/AttributesDelegate.ts +2 -2
  52. package/src/BoxManager.ts +40 -24
  53. package/src/BuiltinApps.ts +23 -0
  54. package/src/ContainerResizeObserver.ts +62 -0
  55. package/src/Cursor/Cursor.ts +22 -36
  56. package/src/Cursor/index.ts +39 -139
  57. package/src/Helper.ts +30 -0
  58. package/src/ReconnectRefresher.ts +0 -5
  59. package/src/Register/index.ts +25 -16
  60. package/src/Register/loader.ts +2 -2
  61. package/src/Register/storage.ts +6 -1
  62. package/src/Utils/Common.ts +66 -13
  63. package/src/Utils/Reactive.ts +9 -3
  64. package/src/Utils/RoomHacker.ts +42 -13
  65. package/src/{MainView.ts → View/MainView.ts} +25 -36
  66. package/src/View/ViewManager.ts +52 -0
  67. package/src/constants.ts +3 -4
  68. package/src/index.ts +96 -72
  69. package/src/shim.d.ts +5 -0
  70. package/src/style.css +7 -1
  71. package/src/typings.ts +3 -2
  72. package/vite.config.js +8 -2
  73. package/dist/Base/Context.d.ts +0 -13
  74. package/dist/Base/index.d.ts +0 -7
  75. package/dist/Utils/CameraStore.d.ts +0 -15
  76. package/dist/ViewManager.d.ts +0 -29
  77. package/dist/sdk.d.ts +0 -14
  78. package/src/Base/Context.ts +0 -49
  79. package/src/Base/index.ts +0 -10
  80. package/src/Utils/CameraStore.ts +0 -72
  81. package/src/sdk.ts +0 -39
  82. package/src/viewManager.ts +0 -177
package/src/AppProxy.ts CHANGED
@@ -2,17 +2,13 @@ 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 { BoxManagerNotFoundError } from "./Utils/error";
7
+ import { debounce, get } from "lodash";
8
+ import { emitter } from "./index";
7
9
  import { Fields } from "./AttributesDelegate";
8
- import { get } from "lodash";
10
+ import { getScenePath, removeScenes, setScenePath, setViewFocusScenePath } from "./Utils/Common";
9
11
  import { log } from "./Utils/log";
10
- import {
11
- notifyMainViewModeChange,
12
- setScenePath,
13
- setViewFocusScenePath,
14
- setViewMode,
15
- } from "./Utils/Common";
16
12
  import type {
17
13
  AppEmitterEvent,
18
14
  AppInitState,
@@ -24,10 +20,9 @@ import type { SceneState, View, SceneDefinition } from "white-web-sdk";
24
20
  import type { AppManager } from "./AppManager";
25
21
  import type { NetlessApp } from "./typings";
26
22
  import type { ReadonlyTeleBox } from "@netless/telebox-insider";
27
- import { Base } from "./Base";
28
- import { BoxManagerNotFoundError } from "./Utils/error";
29
23
 
30
- export class AppProxy extends Base {
24
+ export class AppProxy {
25
+ public kind: string;
31
26
  public id: string;
32
27
  public scenePath?: string;
33
28
  public appEmitter: Emittery<AppEmitterEvent>;
@@ -37,8 +32,8 @@ export class AppProxy extends Base {
37
32
  private boxManager = this.manager.boxManager;
38
33
  private appProxies = this.manager.appProxies;
39
34
  private viewManager = this.manager.viewManager;
40
- private cameraStore = this.manager.cameraStore;
41
- private kind: string;
35
+ private store = this.manager.store;
36
+
42
37
  public isAddApp: boolean;
43
38
  private status: "normal" | "destroyed" = "normal";
44
39
  private stateKey: string;
@@ -47,11 +42,10 @@ export class AppProxy extends Base {
47
42
 
48
43
  constructor(
49
44
  private params: BaseInsertParams,
50
- manager: AppManager,
45
+ private manager: AppManager,
51
46
  appId: string,
52
47
  isAddApp: boolean
53
48
  ) {
54
- super(manager);
55
49
  this.kind = params.kind;
56
50
  this.id = appId;
57
51
  this.stateKey = `${this.id}_state`;
@@ -98,18 +92,24 @@ export class AppProxy extends Base {
98
92
 
99
93
  public getFullScenePath(): string | undefined {
100
94
  if (this.scenePath) {
101
- return get(this.appAttributes, [Fields.FullPath], this.scenePath);
95
+ return get(this.appAttributes, [Fields.FullPath], this.getFullScenePathFromScenes());
96
+ }
97
+ }
98
+
99
+ private getFullScenePathFromScenes() {
100
+ const sceneIndex = get(this.appAttributes, ["state", "SceneIndex"], 0);
101
+ const fullPath = getScenePath(this.manager.room, this.scenePath, sceneIndex);
102
+ if (fullPath) {
103
+ this.setFullPath(fullPath);
102
104
  }
105
+ return fullPath;
103
106
  }
104
107
 
105
108
  public setFullPath(path: string) {
106
109
  this.manager.safeUpdateAttributes(["apps", this.id, Fields.FullPath], path);
107
110
  }
108
111
 
109
- public async baseInsertApp(
110
- skipUpdate = false,
111
- focus?: boolean
112
- ): Promise<{ appId: string; app: NetlessApp }> {
112
+ public async baseInsertApp(skipUpdate = false): Promise<{ appId: string; app: NetlessApp }> {
113
113
  const params = this.params;
114
114
  if (!params.kind) {
115
115
  throw new Error("[WindowManager]: kind require");
@@ -117,14 +117,17 @@ export class AppProxy extends Base {
117
117
  const appImpl = await appRegister.appClasses.get(params.kind)?.();
118
118
  const appParams = appRegister.registered.get(params.kind);
119
119
  if (appImpl) {
120
- await this.setupApp(this.id, skipUpdate, appImpl, params.options, appParams?.appOptions);
120
+ await this.setupApp(
121
+ this.id,
122
+ skipUpdate,
123
+ appImpl,
124
+ params.options,
125
+ appParams?.appOptions
126
+ );
121
127
  } else {
122
128
  throw new Error(`[WindowManager]: app load failed ${params.kind} ${params.src}`);
123
129
  }
124
- this.context.updateManagerRect();
125
- if (focus) {
126
- this.focusApp();
127
- }
130
+ this.boxManager?.updateManagerRect();
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
 
@@ -184,6 +186,11 @@ export class AppProxy extends Base {
184
186
  canOperate: this.manager.canOperate,
185
187
  smartPosition: this.isAddApp,
186
188
  });
189
+ if (this.isAddApp && this.box) {
190
+ this.store.updateAppState(appId, AppAttributes.ZIndex, this.box.zIndex);
191
+ this.store.setAppFocus(appId, true);
192
+ this.focusBox();
193
+ }
187
194
  } catch (error: any) {
188
195
  console.error(error);
189
196
  throw new Error(`[WindowManager]: app setup error: ${error.message}`);
@@ -205,9 +212,6 @@ export class AppProxy extends Base {
205
212
 
206
213
  private afterSetupApp(boxInitState: AppInitState | undefined): void {
207
214
  if (boxInitState) {
208
- if (boxInitState.focus && this.scenePath) {
209
- this.context.switchAppToWriter(this.id);
210
- }
211
215
  if (!boxInitState?.x || !boxInitState.y) {
212
216
  this.boxManager?.setBoxInitState(this.id);
213
217
  }
@@ -226,29 +230,10 @@ export class AppProxy extends Base {
226
230
  await this.destroy(true, false, true);
227
231
  const params = this.params;
228
232
  const appProxy = new AppProxy(params, this.manager, this.id, this.isAddApp);
229
- await appProxy.baseInsertApp(true, this.store.focus === this.id);
233
+ await appProxy.baseInsertApp(true);
230
234
  this.boxManager?.updateBoxState(currentAppState);
231
235
  }
232
236
 
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
237
  public getAppInitState = (id: string) => {
253
238
  const attrs = this.store.getAppState(id);
254
239
  if (!attrs) return;
@@ -337,7 +322,7 @@ export class AppProxy extends Base {
337
322
  }
338
323
  });
339
324
  });
340
- this.manager.refresher?.add(this.stateKey,() => {
325
+ this.manager.refresher?.add(this.stateKey, () => {
341
326
  return autorun(() => {
342
327
  const appState = this.appAttributes?.state;
343
328
  if (appState?.zIndex > 0 && appState.zIndex !== this.box?.zIndex) {
@@ -345,8 +330,20 @@ export class AppProxy extends Base {
345
330
  }
346
331
  });
347
332
  });
333
+ this.manager.refresher?.add(`${appId}-fullPath`, () => {
334
+ return autorun(() => {
335
+ const fullPath = this.appAttributes?.fullPath;
336
+ this.setFocusScenePathHandler(fullPath);
337
+ });
338
+ });
348
339
  };
349
340
 
341
+ private setFocusScenePathHandler = debounce((fullPath: string | undefined) => {
342
+ if (this.view && fullPath && fullPath !== this.view?.focusScenePath) {
343
+ setViewFocusScenePath(this.view, fullPath);
344
+ }
345
+ }, 50);
346
+
350
347
  public setScenePath(): void {
351
348
  if (!this.manager.canOperate) return;
352
349
  const fullScenePath = this.getFullScenePath();
@@ -364,7 +361,6 @@ export class AppProxy extends Base {
364
361
 
365
362
  private async createView(): Promise<View> {
366
363
  const view = await this.viewManager.createView(this.id);
367
- this.cameraStore.register(this.id, view);
368
364
  this.setViewFocusScenePath();
369
365
  return view;
370
366
  }
@@ -386,14 +382,17 @@ export class AppProxy extends Base {
386
382
  }
387
383
  if (cleanAttrs) {
388
384
  this.store.cleanAppAttributes(this.id);
385
+ if (this.scenePath) {
386
+ removeScenes(this.manager.room, this.scenePath);
387
+ }
389
388
  }
390
389
  this.appProxies.delete(this.id);
391
- this.cameraStore.unregister(this.id, this.view);
392
390
 
393
391
  this.viewManager.destroyView(this.id);
394
392
  this.manager.appStatus.delete(this.id);
395
393
  this.manager.refresher?.remove(this.id);
396
394
  this.manager.refresher?.remove(this.stateKey);
395
+ this.manager.refresher?.remove(`${this.id}-fullPath`);
397
396
  }
398
397
 
399
398
  public close(): Promise<void> {
@@ -123,7 +123,7 @@ export class AttributesDelegate {
123
123
  return this.getAppAttributes(id)?.options?.scenePath;
124
124
  }
125
125
 
126
- public getMainViewScenePath() {
126
+ public getMainViewScenePath(): string | undefined {
127
127
  return this.attributes["_mainScenePath"];
128
128
  }
129
129
 
@@ -159,7 +159,7 @@ export class AttributesDelegate {
159
159
  this.context.safeSetAttributes({ [Fields.MainViewSize]: { ...size } });
160
160
  }
161
161
 
162
- public setAppFocus(appId: string, focus: boolean) {
162
+ public setAppFocus = (appId: string, focus: boolean) => {
163
163
  if (focus) {
164
164
  this.context.safeSetAttributes({ [Fields.Focus]: appId });
165
165
  } else {
package/src/BoxManager.ts CHANGED
@@ -1,12 +1,11 @@
1
- import { AppAttributes, DEFAULT_COLLECTOR_STYLE, Events, MIN_HEIGHT, MIN_WIDTH } from "./constants";
2
- import { debounce, maxBy } from "lodash";
1
+ import { AppAttributes, Events, MIN_HEIGHT, MIN_WIDTH } from "./constants";
2
+ import { debounce } from "lodash";
3
+ import { emitter, WindowManager } from "./index";
3
4
  import {
4
- TELE_BOX_MANAGER_EVENT,
5
5
  TELE_BOX_STATE,
6
6
  TeleBoxCollector,
7
7
  TeleBoxManager,
8
8
  } from "@netless/telebox-insider";
9
- import { WindowManager } from "./index";
10
9
  import type { AddAppOptions, AppInitState, EmitterType, CallbacksType } from "./index";
11
10
  import type {
12
11
  TeleBoxManagerUpdateConfig,
@@ -15,6 +14,7 @@ import type {
15
14
  TeleBoxManagerConfig,
16
15
  TeleBoxColorScheme,
17
16
  TeleBoxRect,
17
+ TeleBoxConfig,
18
18
  } from "@netless/telebox-insider";
19
19
  import type Emittery from "emittery";
20
20
  import type { NetlessApp } from "./typings";
@@ -57,6 +57,7 @@ export type BoxManagerContext = {
57
57
  canOperate: () => boolean;
58
58
  notifyContainerRectUpdate: (rect: TeleBoxRect) => void;
59
59
  cleanFocus: () => void;
60
+ setAppFocus: (appId: string) => void;
60
61
  };
61
62
 
62
63
  export const createBoxManager = (
@@ -74,6 +75,7 @@ export const createBoxManager = (
74
75
  notifyContainerRectUpdate: (rect: TeleBoxRect) =>
75
76
  manager.appManager?.notifyContainerRectUpdate(rect),
76
77
  cleanFocus: () => manager.appManager?.store.cleanFocus(),
78
+ setAppFocus: (appId: string) => manager.appManager?.store.setAppFocus(appId, true),
77
79
  callbacks,
78
80
  emitter,
79
81
  },
@@ -90,17 +92,32 @@ export class BoxManager {
90
92
  ) {
91
93
  const { emitter, callbacks } = context;
92
94
  this.teleBoxManager = this.setupBoxManager(createTeleBoxManagerConfig);
93
- this.teleBoxManager.events.on(TELE_BOX_MANAGER_EVENT.State, state => {
94
- if (state) {
95
- this.context.callbacks.emit("boxStateChange", state);
96
- this.context.emitter.emit("boxStateChange", state);
97
- }
95
+
96
+ // 使用 _xxx$.reaction 订阅修改的值, 不管有没有 skipUpdate, 修改值都会触发回调
97
+ this.teleBoxManager._state$.reaction(state => {
98
+ callbacks.emit("boxStateChange", state);
99
+ emitter.emit("boxStateChange", state);
100
+ });
101
+
102
+ this.teleBoxManager._darkMode$.reaction(darkMode => {
103
+ callbacks.emit("darkModeChange", darkMode);
98
104
  });
105
+ this.teleBoxManager._prefersColorScheme$.reaction(colorScheme => {
106
+ callbacks.emit("prefersColorSchemeChange", colorScheme);
107
+ });
108
+
109
+ // events.on 的值则会根据 skipUpdate 来决定是否触发回调
99
110
  this.teleBoxManager.events.on("minimized", minimized => {
100
111
  this.context.safeSetAttributes({ minimized });
101
112
  if (minimized) {
102
113
  this.context.cleanFocus();
103
114
  this.blurAllBox();
115
+ } else {
116
+ const topBox = this.getTopBox();
117
+ if (topBox) {
118
+ this.context.setAppFocus(topBox.id);
119
+ this.focusBox({ appId: topBox.id }, false);
120
+ }
104
121
  }
105
122
  });
106
123
  this.teleBoxManager.events.on("maximized", maximized => {
@@ -136,17 +153,16 @@ export class BoxManager {
136
153
  }
137
154
  }
138
155
  });
139
- this.teleBoxManager.events.on("dark_mode", darkMode => {
140
- callbacks.emit("darkModeChange", darkMode);
141
- });
142
- this.teleBoxManager.events.on("prefers_color_scheme", colorScheme => {
143
- callbacks.emit("prefersColorSchemeChange", colorScheme);
144
- });
145
156
  this.teleBoxManager.events.on("z_index", box => {
146
157
  this.context.updateAppState(box.id, AppAttributes.ZIndex, box.zIndex);
147
158
  });
159
+ emitter.on("playgroundSizeChange", this.playgroundSizeChangeListener);
148
160
  }
149
161
 
162
+ private playgroundSizeChangeListener = () => {
163
+ this.updateManagerRect();
164
+ };
165
+
150
166
  private get mainView() {
151
167
  return this.context.getMainView();
152
168
  }
@@ -251,12 +267,8 @@ export class BoxManager {
251
267
  }
252
268
 
253
269
  public setCollectorContainer(container: HTMLElement) {
254
- const styles = {
255
- ...DEFAULT_COLLECTOR_STYLE,
256
- ...this.createTeleBoxManagerConfig?.collectorStyles,
257
- };
258
270
  const collector = new TeleBoxCollector({
259
- styles
271
+ styles: this.createTeleBoxManagerConfig?.collectorStyles,
260
272
  }).mount(container);
261
273
  this.teleBoxManager.setCollector(collector);
262
274
  }
@@ -280,8 +292,7 @@ export class BoxManager {
280
292
  }
281
293
 
282
294
  public getTopBox(): ReadonlyTeleBox | undefined {
283
- const boxes = this.teleBoxManager.query();
284
- return maxBy(boxes, "zIndex");
295
+ return this.teleBoxManager.topBox;
285
296
  }
286
297
 
287
298
  public updateBoxState(state?: AppInitState): void {
@@ -358,9 +369,9 @@ export class BoxManager {
358
369
  this.teleBoxManager.updateAll(config);
359
370
  }
360
371
 
361
- public setMaximized(maximized: boolean) {
372
+ public setMaximized(maximized: boolean, skipUpdate = true): void {
362
373
  if (maximized !== this.maximized) {
363
- this.teleBoxManager.setMaximized(maximized, true);
374
+ this.teleBoxManager.setMaximized(maximized, skipUpdate);
364
375
  }
365
376
  }
366
377
 
@@ -378,6 +389,10 @@ export class BoxManager {
378
389
  }
379
390
  }
380
391
 
392
+ public updateBox(id: string, payload: TeleBoxConfig, skipUpdate = true): void {
393
+ this.teleBoxManager.update(id, payload, skipUpdate);
394
+ }
395
+
381
396
  public setReadonly(readonly: boolean) {
382
397
  this.teleBoxManager.setReadonly(readonly);
383
398
  }
@@ -391,6 +406,7 @@ export class BoxManager {
391
406
  }
392
407
 
393
408
  public destroy() {
409
+ emitter.off("playgroundSizeChange", this.playgroundSizeChangeListener);
394
410
  this.teleBoxManager.destroy();
395
411
  }
396
412
  }
@@ -0,0 +1,23 @@
1
+ import AppDocsViewer from "@netless/app-docs-viewer";
2
+ import AppMediaPlayer, { setOptions } from "@netless/app-media-player";
3
+ import { WindowManager } from "./index";
4
+
5
+ export const setupBuiltin = () => {
6
+ if (WindowManager.debug) {
7
+ setOptions({ verbose: true });
8
+ }
9
+
10
+ WindowManager.register({
11
+ kind: AppDocsViewer.kind,
12
+ src: AppDocsViewer,
13
+ });
14
+ WindowManager.register({
15
+ kind: AppMediaPlayer.kind,
16
+ src: AppMediaPlayer,
17
+ });
18
+ };
19
+
20
+ export const BuiltinApps = {
21
+ DocsViewer: AppDocsViewer.kind as string,
22
+ MediaPlayer: AppMediaPlayer.kind as string,
23
+ };
@@ -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,42 +1,34 @@
1
- import App from './Cursor.svelte';
2
- import { ApplianceMap } from './icons';
3
- import { ApplianceNames } from 'white-web-sdk';
4
- import { CursorState } from '../constants';
5
- import { Fields } from '../AttributesDelegate';
6
- import { get, omit } from 'lodash';
7
- import type { Position } from '../AttributesDelegate';
1
+ import App from "./Cursor.svelte";
2
+ import { ApplianceMap } from "./icons";
3
+ import { ApplianceNames } from "white-web-sdk";
4
+ import { omit } from "lodash";
5
+ import type { Position } from "../AttributesDelegate";
8
6
  import type { RoomMember } from "white-web-sdk";
9
7
  import type { CursorManager } from "./index";
10
8
  import type { SvelteComponent } from "svelte";
11
- import { Base } from '../Base';
12
- import type { AppManager } from '../AppManager';
9
+ import type { AppManager } from "../AppManager";
13
10
 
14
11
  export type Payload = {
15
- [key: string]: any
16
- }
17
-
12
+ [key: string]: any;
13
+ };
18
14
 
19
- export class Cursor extends Base {
15
+ export class Cursor {
20
16
  private member?: RoomMember;
21
17
  private timer?: number;
22
18
  private component?: SvelteComponent;
23
19
 
24
20
  constructor(
25
- manager: AppManager,
26
- addCursorChangeListener: (uid: string, callback: (position: Position, state: CursorState) => void) => void,
27
- private cursors: any,
21
+ private manager: AppManager,
28
22
  private memberId: string,
29
23
  private cursorManager: CursorManager,
30
- private wrapper?: HTMLElement,
24
+ private wrapper?: HTMLElement
31
25
  ) {
32
- super(manager);
33
26
  this.setMember();
34
27
  this.createCursor();
35
- addCursorChangeListener(this.memberId, this.onCursorChange);
36
28
  this.autoHidden();
37
29
  }
38
30
 
39
- private onCursorChange = (position: Position, state: CursorState) => {
31
+ public move = (position: Position) => {
40
32
  if (position.type === "main") {
41
33
  const rect = this.cursorManager.wrapperRect;
42
34
  if (this.component && rect) {
@@ -45,7 +37,6 @@ export class Cursor extends Base {
45
37
  }
46
38
  } else {
47
39
  const focusView = this.cursorManager.focusView;
48
- // TODO 可以存一个当前 focusView 的 Rect 这样只有 focus 切换的时候才调用 getBoundingClientRect
49
40
  const viewRect = focusView?.divElement?.getBoundingClientRect();
50
41
  const viewCamera = focusView?.camera;
51
42
  if (focusView && viewRect && viewCamera && this.component) {
@@ -53,10 +44,11 @@ export class Cursor extends Base {
53
44
  this.moveCursor(position, viewRect, focusView);
54
45
  }
55
46
  }
56
- if (state && state === CursorState.Leave) {
57
- this.hide();
58
- }
59
- }
47
+ };
48
+
49
+ public leave = () => {
50
+ this.hide();
51
+ };
60
52
 
61
53
  private moveCursor(cursor: Position, rect: DOMRect, view: any) {
62
54
  const { x, y, type } = cursor;
@@ -124,21 +116,12 @@ export class Cursor extends Base {
124
116
  }
125
117
  }
126
118
 
127
- public get cursorState(): CursorState | undefined {
128
- return get(this.cursors, [this.memberId, Fields.CursorState]);
129
- }
130
-
131
- public get cursorPosition(): Position | undefined {
132
- return get(this.cursors, [this.memberId, Fields.Position]);
133
- }
134
-
135
119
  private autoHidden() {
136
120
  if (this.timer) {
137
121
  clearTimeout(this.timer);
138
122
  }
139
123
  this.timer = window.setTimeout(() => {
140
124
  this.hide();
141
- this.store.updateCursorState(this.memberId, CursorState.Leave);
142
125
  }, 1000 * 10); // 10 秒钟自动隐藏
143
126
  }
144
127
 
@@ -176,7 +159,7 @@ export class Cursor extends Base {
176
159
  }
177
160
 
178
161
  public setMember() {
179
- this.member = this.context.findMemberByUid(this.memberId);
162
+ this.member = this.manager.findMemberByUid(this.memberId);
180
163
  this.updateComponent();
181
164
  }
182
165
 
@@ -188,13 +171,16 @@ export class Cursor extends Base {
188
171
  if (this.component) {
189
172
  this.component.$destroy();
190
173
  }
191
- this.manager.refresher?.remove(this.memberId);
192
174
  this.cursorManager.cursorInstances.delete(this.memberId);
175
+ if (this.timer) {
176
+ clearTimeout(this.timer);
177
+ }
193
178
  }
194
179
 
195
180
  public hide() {
196
181
  if (this.component) {
197
182
  this.component.$set({ visible: false });
183
+ this.destroy();
198
184
  }
199
185
  }
200
186
  }