@netless/window-manager 1.0.0-canary.1 → 1.0.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 (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 +2 -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 +712 -648
  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 +5 -8
  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 +22 -39
  46. package/src/constants.ts +2 -0
  47. package/src/index.ts +18 -3
  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
  }
@@ -214,7 +209,7 @@ export class BoxManager {
214
209
  return this.teleBoxManager.stageRect;
215
210
  }
216
211
 
217
- public createBox(params: CreateBoxParams): void {
212
+ public createBox(params: CreateBoxParams): ReadonlyTeleBox | undefined {
218
213
  if (!this.teleBoxManager) return;
219
214
  let { minwidth = MIN_WIDTH, minheight = MIN_HEIGHT } = params.app.config ?? {};
220
215
  const { width, height } = params.app.config ?? {};
@@ -237,8 +232,9 @@ export class BoxManager {
237
232
  height,
238
233
  id: params.appId,
239
234
  };
240
- this.teleBoxManager.create(createBoxConfig, params.smartPosition);
235
+ const box = this.teleBoxManager.create(createBoxConfig, params.smartPosition);
241
236
  this.context.emitter.emit(`${params.appId}${Events.WindowCreated}` as any);
237
+ return box;
242
238
  }
243
239
 
244
240
  public setupBoxManager(
@@ -250,6 +246,7 @@ export class BoxManager {
250
246
  root: root,
251
247
  fence: false,
252
248
  prefersColorScheme: createTeleBoxManagerConfig?.prefersColorScheme,
249
+ highlightStage: createTeleBoxManagerConfig?.highlightStage,
253
250
  };
254
251
 
255
252
  const manager = new TeleBoxManager(initManagerState);
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) {