@netless/window-manager 1.0.0-canary.0 → 1.0.0-canary.11

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 (49) hide show
  1. package/__mocks__/white-web-sdk.ts +10 -1
  2. package/dist/App/AppContext.d.ts +16 -15
  3. package/dist/App/AppPageStateImpl.d.ts +6 -2
  4. package/dist/App/AppProxy.d.ts +26 -4
  5. package/dist/App/AppViewSync.d.ts +11 -0
  6. package/dist/App/WhiteboardView.d.ts +24 -0
  7. package/dist/App/index.d.ts +1 -0
  8. package/dist/AppManager.d.ts +5 -3
  9. package/dist/AttributesDelegate.d.ts +6 -14
  10. package/dist/BoxManager.d.ts +4 -3
  11. package/dist/Helper.d.ts +12 -2
  12. package/dist/InternalEmitter.d.ts +4 -0
  13. package/dist/Page/PageController.d.ts +1 -0
  14. package/dist/ReconnectRefresher.d.ts +1 -1
  15. package/dist/Utils/Common.d.ts +1 -0
  16. package/dist/View/CameraSynchronizer.d.ts +7 -7
  17. package/dist/View/MainView.d.ts +0 -1
  18. package/dist/constants.d.ts +1 -0
  19. package/dist/index.cjs.js +12 -12
  20. package/dist/index.d.ts +6 -3
  21. package/dist/index.es.js +722 -652
  22. package/dist/index.umd.js +12 -12
  23. package/dist/style.css +1 -1
  24. package/dist/typings.d.ts +4 -0
  25. package/docs/app-context.md +98 -64
  26. package/docs/develop-app.md +2 -5
  27. package/package.json +3 -2
  28. package/pnpm-lock.yaml +11 -5
  29. package/src/App/AppContext.ts +71 -74
  30. package/src/App/AppPageStateImpl.ts +25 -6
  31. package/src/App/AppProxy.ts +206 -26
  32. package/src/App/AppViewSync.ts +73 -0
  33. package/src/App/Storage/index.ts +4 -4
  34. package/src/App/WhiteboardView.ts +89 -0
  35. package/src/App/index.ts +1 -0
  36. package/src/AppManager.ts +32 -23
  37. package/src/AttributesDelegate.ts +14 -17
  38. package/src/BoxManager.ts +14 -9
  39. package/src/Helper.ts +10 -1
  40. package/src/InternalEmitter.ts +4 -0
  41. package/src/Page/PageController.ts +1 -0
  42. package/src/ReconnectRefresher.ts +1 -0
  43. package/src/Utils/Common.ts +6 -0
  44. package/src/View/CameraSynchronizer.ts +32 -27
  45. package/src/View/MainView.ts +24 -41
  46. package/src/constants.ts +2 -0
  47. package/src/index.ts +20 -5
  48. package/src/style.css +9 -0
  49. package/src/typings.ts +4 -0
@@ -0,0 +1,73 @@
1
+ import { CameraSynchronizer } from "../View/CameraSynchronizer";
2
+ import { SideEffectManager } from "side-effect-manager";
3
+ import type { Camera, View } from "white-web-sdk";
4
+ import type { AppProxy } from "./AppProxy";
5
+ import { isEqual } from "lodash";
6
+ import { combine } from "value-enhancer";
7
+
8
+ export class AppViewSync {
9
+ private sem = new SideEffectManager();
10
+ private synchronizer: CameraSynchronizer;
11
+
12
+ constructor(private appProxy: AppProxy) {
13
+ this.synchronizer = new CameraSynchronizer((camera: Camera) => {
14
+ this.appProxy.storeCamera({
15
+ id: this.appProxy.uid,
16
+ ...camera,
17
+ });
18
+ });
19
+ this.bindView(appProxy.view);
20
+ this.sem.add(() => this.appProxy.camera$.subscribe(camera => {
21
+ const size = this.appProxy.size$.value;
22
+ if (camera && size) {
23
+ this.synchronizer.onRemoteUpdate(camera, size);
24
+ }
25
+ }));
26
+ this.sem.add(() => this.appProxy.size$.subscribe(size => {
27
+ if (size) {
28
+ this.synchronizer.onRemoteSizeUpdate(size);
29
+ }
30
+ }));
31
+ const box = this.appProxy.box;
32
+ if (box && box.contentStageRect) {
33
+ this.synchronizer.setRect(box.contentStageRect);
34
+ this.sem.add(() =>
35
+ box._contentStageRect$.subscribe(rect => {
36
+ if (rect) {
37
+ this.synchronizer.setRect(rect);
38
+ }
39
+ }),
40
+ );
41
+ }
42
+ this.sem.add(() => combine([this.appProxy.camera$, this.appProxy.size$]).subscribe(([camera, size]) => {
43
+ if (camera && size) {
44
+ this.synchronizer.onRemoteUpdate(camera, size);
45
+ }
46
+ }));
47
+ }
48
+
49
+ public bindView = (view?: View) => {
50
+ if (!view) return;
51
+ this.synchronizer.setView(view);
52
+ this.sem.add(() => {
53
+ view.callbacks.on("onCameraUpdatedByDevice", this.onCameraUpdatedByDevice);
54
+ return () =>
55
+ view.callbacks.off("onCameraUpdatedByDevice", this.onCameraUpdatedByDevice);
56
+ });
57
+ };
58
+
59
+ private onCameraUpdatedByDevice = (camera: Camera) => {
60
+ this.synchronizer.onLocalCameraUpdate(camera);
61
+ const stage = this.appProxy.box?.contentStageRect;
62
+ if (stage) {
63
+ const size = { width: stage.width, height: stage.height, id: this.appProxy.uid };
64
+ if (!isEqual(size, this.appProxy.size$.value)) {
65
+ this.appProxy.storeSize(size);
66
+ }
67
+ }
68
+ };
69
+
70
+ public destroy() {
71
+ this.sem.flushAll();
72
+ }
73
+ }
@@ -37,7 +37,7 @@ export class Storage<TState extends Record<string, any> = any> implements Storag
37
37
  this._state = {} as TState;
38
38
  const rawState = this._getRawState(this._state);
39
39
 
40
- if (this._context.getIsWritable()) {
40
+ if (this._context.isWritable) {
41
41
  if (this.id === null) {
42
42
  if (context.isAddApp && defaultState) {
43
43
  this.setState(defaultState);
@@ -115,7 +115,7 @@ export class Storage<TState extends Record<string, any> = any> implements Storag
115
115
  return;
116
116
  }
117
117
 
118
- if (!this._context.getIsWritable()) {
118
+ if (!this._context.isWritable) {
119
119
  console.error(new Error(`Cannot setState on Storage "${this.id}" without writable access`), state);
120
120
  return;
121
121
  }
@@ -165,7 +165,7 @@ export class Storage<TState extends Record<string, any> = any> implements Storag
165
165
  return;
166
166
  }
167
167
 
168
- if (!this._context.getIsWritable()) {
168
+ if (!this._context.isWritable) {
169
169
  console.error(new Error(`Cannot empty Storage "${this.id}" without writable access.`));
170
170
  return;
171
171
  }
@@ -181,7 +181,7 @@ export class Storage<TState extends Record<string, any> = any> implements Storag
181
181
  throw new Error(`Cannot delete main Storage`);
182
182
  }
183
183
 
184
- if (!this._context.getIsWritable()) {
184
+ if (!this._context.isWritable) {
185
185
  console.error(new Error(`Cannot delete Storage "${this.id}" without writable access.`));
186
186
  return;
187
187
  }
@@ -0,0 +1,89 @@
1
+ import { putScenes } from "../Utils/Common";
2
+ import { Val } from "value-enhancer";
3
+
4
+ import type { ReadonlyVal } from "value-enhancer";
5
+ import type { AddPageParams, PageController, PageState } from "../Page";
6
+ import type { AppProxy } from "./AppProxy";
7
+ import type { AppContext } from "./AppContext";
8
+ import type { Camera, View } from "white-web-sdk";
9
+ import type { TeleBoxRect } from "@netless/telebox-insider";
10
+
11
+ export class WhiteBoardView implements PageController {
12
+ public readonly pageState$: ReadonlyVal<PageState>;
13
+
14
+ constructor(
15
+ public view: View,
16
+ protected appContext: AppContext,
17
+ protected appProxy: AppProxy,
18
+ private removeViewWrapper: () => void,
19
+ public ensureSize: (size: number) => void
20
+ ) {
21
+ const pageState$ = new Val<PageState>(appProxy.pageState);
22
+ this.pageState$ = pageState$;
23
+ appProxy.appEmitter.on("pageStateChange", pageState => {
24
+ pageState$.setValue(pageState);
25
+ });
26
+ }
27
+
28
+ public get pageState() {
29
+ return this.pageState$.value;
30
+ }
31
+
32
+ public moveCamera(camera: Camera) {
33
+ this.appProxy.moveCamera(camera);
34
+ }
35
+
36
+ public nextPage = async (): Promise<boolean> => {
37
+ const nextIndex = this.pageState.index + 1;
38
+ return this.jumpPage(nextIndex);
39
+ };
40
+
41
+ public prevPage = async (): Promise<boolean> => {
42
+ const nextIndex = this.pageState.index - 1;
43
+ return this.jumpPage(nextIndex);
44
+ };
45
+
46
+ public jumpPage = async (index: number): Promise<boolean> => {
47
+ if (index < 0 || index >= this.pageState.length) {
48
+ console.warn(`[WindowManager]: index ${index} out of range`);
49
+ return false;
50
+ }
51
+ this.appProxy.setSceneIndex(index);
52
+ return true;
53
+ };
54
+
55
+ public addPage = async (params?: AddPageParams) => {
56
+ const after = params?.after;
57
+ const scene = params?.scene;
58
+ const scenePath = this.appProxy.scenePath;
59
+ if (!scenePath) return;
60
+ if (after) {
61
+ const nextIndex = this.pageState.index + 1;
62
+ putScenes(this.appContext.room, scenePath, [scene || {}], nextIndex);
63
+ } else {
64
+ putScenes(this.appContext.room, scenePath, [scene || {}]);
65
+ }
66
+ };
67
+
68
+ public removePage = async (index?: number): Promise<boolean> => {
69
+ const needRemoveIndex = index === undefined ? this.pageState.index : index;
70
+ if (this.pageState.length === 1) {
71
+ console.warn(`[WindowManager]: can not remove the last page`);
72
+ return false;
73
+ }
74
+ if (needRemoveIndex < 0 || needRemoveIndex >= this.pageState.length) {
75
+ console.warn(`[WindowManager]: page index ${index} out of range`);
76
+ return false;
77
+ }
78
+ return this.appProxy.removeSceneByIndex(needRemoveIndex);
79
+ };
80
+
81
+ public setRect(rect: Omit<TeleBoxRect, "x" | "y">) {
82
+ this.appProxy.updateSize(rect.width, rect.height);
83
+ }
84
+
85
+ public destroy() {
86
+ this.pageState$.destroy();
87
+ this.removeViewWrapper();
88
+ }
89
+ }
package/src/App/index.ts CHANGED
@@ -1,2 +1,3 @@
1
1
  export * from "./AppProxy";
2
2
  export * from "./AppContext";
3
+ export * from "./WhiteboardView";
package/src/AppManager.ts CHANGED
@@ -3,7 +3,7 @@ import { AppCreateQueue } from "./Utils/AppCreateQueue";
3
3
  import { AppListeners } from "./AppListener";
4
4
  import { AppProxy } from "./App";
5
5
  import { appRegister } from "./Register";
6
- import { autorun, isPlayer, isRoom, ScenePathType } from "white-web-sdk";
6
+ import { autorun, isPlayer, isRoom, ScenePathType, toJS } from "white-web-sdk";
7
7
  import { boxEmitter } from "./BoxEmitter";
8
8
  import { calculateNextIndex } from "./Page";
9
9
  import { callbacks } from "./callback";
@@ -15,8 +15,10 @@ import { MainViewProxy } from "./View/MainView";
15
15
  import { onObjectRemoved, safeListenPropsUpdated } from "./Utils/Reactive";
16
16
  import { reconnectRefresher, WindowManager } from "./index";
17
17
  import { RedoUndo } from "./RedoUndo";
18
+ import { serializeRoomMembers } from "./Helper";
18
19
  import { SideEffectManager } from "side-effect-manager";
19
20
  import { ViewManager } from "./View/ViewManager";
21
+ import { Val } from "value-enhancer";
20
22
  import type { SyncRegisterAppPayload } from "./Register";
21
23
  import type { RemoveSceneParams } from "./InternalEmitter";
22
24
  import {
@@ -33,10 +35,10 @@ import type { ReconnectRefresher } from "./ReconnectRefresher";
33
35
  import type { BoxManager } from "./BoxManager";
34
36
  import type {
35
37
  Displayer,
36
- DisplayerState,
37
38
  Room,
38
39
  ScenesCallbacksNode,
39
40
  SceneState,
41
+ RoomState,
40
42
  } from "white-web-sdk";
41
43
  import type { AddAppParams, BaseInsertParams, TeleBoxRect } from "./index";
42
44
  import type {
@@ -46,7 +48,7 @@ import type {
46
48
  BoxResizePayload,
47
49
  BoxStateChangePayload,
48
50
  } from "./BoxEmitter";
49
-
51
+ import type { Member } from "./Helper";
50
52
 
51
53
  export class AppManager {
52
54
  public displayer: Displayer;
@@ -55,17 +57,17 @@ export class AppManager {
55
57
  public appStatus: Map<string, AppStatus> = new Map();
56
58
  public store = store;
57
59
  public mainViewProxy: MainViewProxy;
58
- public refresher?: ReconnectRefresher;
60
+ public refresher: ReconnectRefresher;
59
61
  public isReplay = this.windowManger.isReplay;
60
62
  public mainViewScenesLength = 0;
61
63
 
62
64
  private appListeners: AppListeners;
63
65
  public boxManager?: BoxManager;
64
66
 
65
- private _prevSceneIndex: number | undefined;
66
- private _prevFocused: string | undefined;
67
67
  private callbacksNode: ScenesCallbacksNode | null = null;
68
68
  private appCreateQueue = new AppCreateQueue();
69
+ private sceneIndex$ = new Val<number | undefined>(undefined);
70
+ private focused$ = new Val<string | undefined>(undefined);
69
71
 
70
72
  private sideEffectManager = new SideEffectManager();
71
73
 
@@ -299,6 +301,10 @@ export class AppManager {
299
301
  return this.room?.uid || "";
300
302
  }
301
303
 
304
+ public get members(): Member[] {
305
+ return serializeRoomMembers(this.displayer.state.roomMembers);
306
+ }
307
+
302
308
  public getMainViewSceneDir() {
303
309
  const scenePath = this.store.getMainViewScenePath();
304
310
  if (scenePath) {
@@ -319,31 +325,31 @@ export class AppManager {
319
325
 
320
326
  this.addAppsChangeListener();
321
327
  this.addAppCloseListener();
322
- this.refresher?.add("maximized", () => {
328
+ this.refresher.add("maximized", () => {
323
329
  return autorun(() => {
324
330
  const maximized = this.attributes.maximized;
325
331
  this.boxManager?.setMaximized(Boolean(maximized));
326
332
  });
327
333
  });
328
- this.refresher?.add("minimized", () => {
334
+ this.refresher.add("minimized", () => {
329
335
  return autorun(() => {
330
336
  const minimized = this.attributes.minimized;
331
337
  this.onMinimized(minimized);
332
338
  });
333
339
  });
334
- this.refresher?.add("mainViewIndex", () => {
340
+ this.refresher.add("mainViewIndex", () => {
335
341
  return autorun(() => {
336
342
  const mainSceneIndex = get(this.attributes, "_mainSceneIndex");
337
343
  this.onMainViewIndexChange(mainSceneIndex);
338
344
  });
339
345
  });
340
- this.refresher?.add("focusedChange", () => {
346
+ this.refresher.add("focusedChange", () => {
341
347
  return autorun(() => {
342
348
  const focused = get(this.attributes, "focus");
343
349
  this.onFocusChange(focused);
344
350
  });
345
351
  });
346
- this.refresher?.add("registeredChange", () => {
352
+ this.refresher.add("registeredChange", () => {
347
353
  return autorun(() => {
348
354
  const registered = get(this.attributes, Fields.Registered);
349
355
  this.onRegisteredChange(registered);
@@ -356,7 +362,7 @@ export class AppManager {
356
362
  }
357
363
  this.displayerWritableListener(!this.room?.isWritable);
358
364
  this.displayer.callbacks.on("onEnableWriteNowChanged", this.displayerWritableListener);
359
- this._prevFocused = this.attributes.focus;
365
+ this.focused$.setValue(this.attributes.focus);
360
366
 
361
367
  this.sideEffectManager.add(() => {
362
368
  const redoUndo = new RedoUndo({
@@ -421,21 +427,21 @@ export class AppManager {
421
427
  };
422
428
 
423
429
  private onMainViewIndexChange = (index: number) => {
424
- if (index !== undefined && this._prevSceneIndex !== index) {
430
+ if (index !== undefined && this.sceneIndex$.value !== index) {
425
431
  callbacks.emit("mainViewSceneIndexChange", index);
426
432
  emitter.emit("changePageState");
427
433
  if (this.callbacksNode) {
428
434
  this.updateSceneState(this.callbacksNode);
429
435
  }
430
- this._prevSceneIndex = index;
436
+ this.sceneIndex$.setValue(index);
431
437
  }
432
438
  };
433
439
 
434
440
  private onFocusChange = (focused: string | undefined) => {
435
- if (this._prevFocused !== focused) {
441
+ if (this.focused$.value !== focused) {
436
442
  callbacks.emit("focusedChange", focused);
437
- emitter.emit("focusedChange", { focused, prev: this._prevFocused });
438
- this._prevFocused = focused;
443
+ emitter.emit("focusedChange", { focused, prev: this.focused$.value });
444
+ this.focused$.setValue(focused);
439
445
  if (focused !== undefined) {
440
446
  this.boxManager?.focusBox({ appId: focused });
441
447
  // 确保 focus 修改的时候, appProxy 已经创建
@@ -646,7 +652,7 @@ export class AppManager {
646
652
  }
647
653
  }
648
654
 
649
- private displayerStateListener = (state: Partial<DisplayerState>) => {
655
+ private displayerStateListener = (state: Partial<RoomState>) => {
650
656
  const sceneState = state.sceneState;
651
657
  if (sceneState) {
652
658
  const scenePath = sceneState.scenePath;
@@ -660,7 +666,13 @@ export class AppManager {
660
666
  this.appProxies.forEach(appProxy => {
661
667
  appProxy.appEmitter.emit("roomStateChange", state);
662
668
  });
669
+ if (state.roomMembers) {
670
+ emitter.emit("roomMembersChange", this.members);
671
+ }
663
672
  emitter.emit("observerIdChange", this.displayer.observerId);
673
+ if (state.memberState) {
674
+ emitter.emit("memberStateChange", toJS(state.memberState));
675
+ }
664
676
  };
665
677
 
666
678
  public displayerWritableListener = (isReadonly: boolean) => {
@@ -676,12 +688,9 @@ export class AppManager {
676
688
  appProxy.emitAppIsWritableChange();
677
689
  });
678
690
  if (isWritable === true) {
679
- this.mainView.disableCameraTransform = false;
680
691
  if (this.room && this.room.disableSerialization === true) {
681
692
  this.room.disableSerialization = false;
682
693
  }
683
- } else {
684
- this.mainView.disableCameraTransform = true;
685
694
  }
686
695
  emitter.emit("writableChange", isWritable);
687
696
  };
@@ -823,7 +832,7 @@ export class AppManager {
823
832
  }
824
833
  callbacks.clearListeners();
825
834
  this.sideEffectManager.flushAll();
826
- this._prevFocused = undefined;
827
- this._prevSceneIndex = undefined;
835
+ this.sceneIndex$.destroy();
836
+ this.focused$.destroy();
828
837
  }
829
838
  }
@@ -18,6 +18,8 @@ export enum Fields {
18
18
  CursorState = "cursorState",
19
19
  FullPath = "fullPath",
20
20
  Registered = "registered",
21
+ Camera = "camera",
22
+ Size = "size",
21
23
  }
22
24
 
23
25
  export type Apps = {
@@ -39,9 +41,13 @@ export type StoreContext = {
39
41
  safeSetAttributes: (attributes: any) => void;
40
42
  }
41
43
 
42
- export type ICamera = Camera & { id: string };
44
+ export type ICamera = Camera & {
45
+ id: string; // room uid
46
+ };
43
47
 
44
- export type ISize = Size & { id: string };
48
+ export type ISize = Size & {
49
+ id: string; // room uid
50
+ };
45
51
 
46
52
  export class AttributesDelegate {
47
53
 
@@ -108,6 +114,10 @@ export class AttributesDelegate {
108
114
  }
109
115
  }
110
116
 
117
+ public updateAppAttributes(appId: string, key: string, value: any) {
118
+ this.context.safeUpdateAttributes([Fields.Apps, appId, key], value);
119
+ }
120
+
111
121
  public cleanAppAttributes(id: string) {
112
122
  this.context.safeUpdateAttributes([Fields.Apps, id], undefined);
113
123
  this.context.safeSetAttributes({ [id]: undefined });
@@ -149,11 +159,11 @@ export class AttributesDelegate {
149
159
  this.context.safeSetAttributes({ _mainSceneIndex: index });
150
160
  }
151
161
 
152
- public getMainViewCamera(): MainViewCamera {
162
+ public getMainViewCamera(): ICamera {
153
163
  return get(this.attributes, [Fields.MainViewCamera]);
154
164
  }
155
165
 
156
- public getMainViewSize(): MainViewSize {
166
+ public getMainViewSize(): ISize {
157
167
  return get(this.attributes, [Fields.MainViewSize]);
158
168
  }
159
169
 
@@ -214,19 +224,6 @@ export class AttributesDelegate {
214
224
  }
215
225
  }
216
226
 
217
- export type MainViewSize = {
218
- id: string;
219
- width: number;
220
- height: number;
221
- };
222
-
223
- export type MainViewCamera = {
224
- id: string;
225
- centerX: number;
226
- centerY: number;
227
- scale: number;
228
- };
229
-
230
227
  export type Cursors = {
231
228
  [key: string]: Cursor;
232
229
  };
package/src/BoxManager.ts CHANGED
@@ -47,11 +47,11 @@ export type CreateTeleBoxManagerConfig = {
47
47
  collectorStyles?: Partial<CSSStyleDeclaration>;
48
48
  prefersColorScheme?: TeleBoxColorScheme;
49
49
  stageRatio?: number;
50
+ highlightStage?: boolean;
50
51
  };
51
52
 
52
53
  export type BoxManagerContext = {
53
54
  safeSetAttributes: (attributes: any) => void;
54
- getMainView: () => View;
55
55
  updateAppState: (appId: string, field: AppAttributes, value: any) => void;
56
56
  emitter: EmitterType;
57
57
  boxEmitter: BoxEmitterType;
@@ -72,7 +72,6 @@ export const createBoxManager = (
72
72
  return new BoxManager(
73
73
  {
74
74
  safeSetAttributes: (attributes: any) => manager.safeSetAttributes(attributes),
75
- getMainView: () => manager.mainView,
76
75
  updateAppState: (...args) => manager.appManager?.store.updateAppState(...args),
77
76
  canOperate: () => manager.canOperate,
78
77
  notifyContainerRectUpdate: (rect: TeleBoxRect) =>
@@ -178,10 +177,6 @@ export class BoxManager {
178
177
  ]);
179
178
  }
180
179
 
181
- private get mainView() {
182
- return this.context.getMainView();
183
- }
184
-
185
180
  private get canOperate() {
186
181
  return this.context.canOperate();
187
182
  }
@@ -210,7 +205,11 @@ export class BoxManager {
210
205
  return this.teleBoxManager.boxes.length;
211
206
  }
212
207
 
213
- public createBox(params: CreateBoxParams): void {
208
+ public get stageRect() {
209
+ return this.teleBoxManager.stageRect;
210
+ }
211
+
212
+ public createBox(params: CreateBoxParams): ReadonlyTeleBox | undefined {
214
213
  if (!this.teleBoxManager) return;
215
214
  let { minwidth = MIN_WIDTH, minheight = MIN_HEIGHT } = params.app.config ?? {};
216
215
  const { width, height } = params.app.config ?? {};
@@ -233,8 +232,9 @@ export class BoxManager {
233
232
  height,
234
233
  id: params.appId,
235
234
  };
236
- this.teleBoxManager.create(createBoxConfig, params.smartPosition);
235
+ const box = this.teleBoxManager.create(createBoxConfig, params.smartPosition);
237
236
  this.context.emitter.emit(`${params.appId}${Events.WindowCreated}` as any);
237
+ return box;
238
238
  }
239
239
 
240
240
  public setupBoxManager(
@@ -242,10 +242,11 @@ export class BoxManager {
242
242
  ): TeleBoxManager {
243
243
  const root = WindowManager.playground;
244
244
  const initManagerState: TeleBoxManagerConfig = {
245
- stageRatio: 3 / 4,
245
+ stageRatio: createTeleBoxManagerConfig?.stageRatio,
246
246
  root: root,
247
247
  fence: false,
248
248
  prefersColorScheme: createTeleBoxManagerConfig?.prefersColorScheme,
249
+ highlightStage: createTeleBoxManagerConfig?.highlightStage,
249
250
  };
250
251
 
251
252
  const manager = new TeleBoxManager(initManagerState);
@@ -390,6 +391,10 @@ export class BoxManager {
390
391
  this.teleBoxManager._root$.setValue(root);
391
392
  }
392
393
 
394
+ public setCollector(collector: HTMLElement) {
395
+ this.teleBoxManager.collector.set$collector(collector);
396
+ }
397
+
393
398
  public destroy() {
394
399
  this.sideEffectManager.flushAll();
395
400
  this.teleBoxManager.destroy();
package/src/Helper.ts CHANGED
@@ -2,7 +2,7 @@ import { getVersionNumber } from "./Utils/Common";
2
2
  import { REQUIRE_VERSION } from "./constants";
3
3
  import { WhiteVersion } from "white-web-sdk";
4
4
  import { WhiteWebSDKInvalidError } from "./Utils/error";
5
- import type { Room } from "white-web-sdk";
5
+ import type { Room , RoomMember} from "white-web-sdk";
6
6
 
7
7
  export const setupWrapper = (
8
8
  root: HTMLElement
@@ -32,3 +32,12 @@ export const findMemberByUid = (room: Room | undefined, uid: string) => {
32
32
  const roomMembers = room?.state.roomMembers;
33
33
  return roomMembers?.find(member => member.payload?.uid === uid);
34
34
  };
35
+
36
+ export type Member = RoomMember & { uid: string };
37
+
38
+ export const serializeRoomMembers = (members: readonly RoomMember[]) => {
39
+ return members.map(member => ({
40
+ uid: member.payload?.uid || "",
41
+ ...member,
42
+ }));
43
+ }
@@ -1,6 +1,8 @@
1
1
  import Emittery from "emittery";
2
2
  import type { TeleBoxRect } from "@netless/telebox-insider";
3
3
  import type { AppInitState, CursorMovePayload } from "./index";
4
+ import type { Member } from "./Helper";
5
+ import type { MemberState } from "white-web-sdk";
4
6
 
5
7
  export type RemoveSceneParams = {
6
8
  scenePath: string;
@@ -29,6 +31,8 @@ export type EmitterEvent = {
29
31
  changePageState: undefined;
30
32
  writableChange: boolean;
31
33
  containerSizeRatioUpdate: number;
34
+ roomMembersChange: Member[];
35
+ memberStateChange: MemberState;
32
36
  };
33
37
 
34
38
  export type EmitterType = Emittery<EmitterEvent>;
@@ -13,6 +13,7 @@ export type PageState = {
13
13
  export interface PageController {
14
14
  nextPage: () => Promise<boolean>;
15
15
  prevPage: () => Promise<boolean>;
16
+ jumpPage: (index: number) => Promise<boolean>;
16
17
  addPage: (params?: AddPageParams) => Promise<void>;
17
18
  removePage: (index: number) => Promise<boolean>;
18
19
  pageState: PageState;
@@ -88,6 +88,7 @@ export class ReconnectRefresher {
88
88
  this.reactors.set(id, func);
89
89
  this.disposers.set(id, func());
90
90
  }
91
+ return () => this.remove(id);
91
92
  }
92
93
 
93
94
  public remove(id: string) {
@@ -30,6 +30,12 @@ export const setViewSceneIndex = (view: View, index: number) => {
30
30
  }
31
31
  };
32
32
 
33
+ export const releaseView = (view: View) => {
34
+ if (!(view as any).didRelease) {
35
+ view.release();
36
+ }
37
+ }
38
+
33
39
  export const setScenePath = (room: Room | undefined, scenePath: string) => {
34
40
  if (room && room.isWritable) {
35
41
  if (room.state.sceneState.scenePath !== scenePath) {