@netless/window-manager 0.3.17 → 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 (73) hide show
  1. package/CHANGELOG.md +10 -0
  2. package/README.md +4 -43
  3. package/dist/App/Storage/StorageEvent.d.ts +8 -0
  4. package/dist/App/Storage/index.d.ts +26 -0
  5. package/dist/App/Storage/typings.d.ts +21 -0
  6. package/dist/App/Storage/utils.d.ts +5 -0
  7. package/dist/AppContext.d.ts +6 -3
  8. package/dist/AppListener.d.ts +2 -2
  9. package/dist/AppManager.d.ts +17 -14
  10. package/dist/AppProxy.d.ts +5 -3
  11. package/dist/AttributesDelegate.d.ts +19 -11
  12. package/dist/Base/Context.d.ts +0 -1
  13. package/dist/Base/index.d.ts +1 -2
  14. package/dist/BoxManager.d.ts +25 -8
  15. package/dist/BuiltinApps.d.ts +6 -0
  16. package/dist/ContainerResizeObserver.d.ts +10 -0
  17. package/dist/Cursor/Cursor.d.ts +2 -3
  18. package/dist/Cursor/index.d.ts +9 -5
  19. package/dist/Helper.d.ts +6 -0
  20. package/dist/ReconnectRefresher.d.ts +9 -3
  21. package/dist/Utils/Common.d.ts +3 -1
  22. package/dist/Utils/Reactive.d.ts +1 -1
  23. package/dist/Utils/RoomHacker.d.ts +2 -2
  24. package/dist/Utils/error.d.ts +3 -0
  25. package/dist/{MainView.d.ts → View/MainView.d.ts} +3 -4
  26. package/dist/View/ViewManager.d.ts +13 -0
  27. package/dist/constants.d.ts +3 -7
  28. package/dist/index.d.ts +24 -27
  29. package/dist/index.es.js +1 -1
  30. package/dist/index.es.js.map +1 -1
  31. package/dist/index.umd.js +1 -1
  32. package/dist/index.umd.js.map +1 -1
  33. package/dist/style.css +1 -1
  34. package/dist/typings.d.ts +1 -0
  35. package/docs/api.md +17 -0
  36. package/docs/migrate.md +42 -0
  37. package/package.json +6 -4
  38. package/src/App/Storage/StorageEvent.ts +21 -0
  39. package/src/App/Storage/index.ts +243 -0
  40. package/src/App/Storage/typings.ts +21 -0
  41. package/src/App/Storage/utils.ts +17 -0
  42. package/src/AppContext.ts +12 -4
  43. package/src/AppListener.ts +15 -11
  44. package/src/AppManager.ts +132 -95
  45. package/src/AppProxy.ts +49 -52
  46. package/src/AttributesDelegate.ts +76 -49
  47. package/src/Base/Context.ts +2 -6
  48. package/src/Base/index.ts +2 -2
  49. package/src/BoxManager.ts +95 -35
  50. package/src/BuiltinApps.ts +24 -0
  51. package/src/ContainerResizeObserver.ts +62 -0
  52. package/src/Cursor/Cursor.ts +35 -39
  53. package/src/Cursor/index.ts +79 -43
  54. package/src/Helper.ts +30 -0
  55. package/src/ReconnectRefresher.ts +25 -10
  56. package/src/Utils/Common.ts +35 -13
  57. package/src/Utils/Reactive.ts +9 -3
  58. package/src/Utils/RoomHacker.ts +20 -5
  59. package/src/Utils/error.ts +6 -1
  60. package/src/{MainView.ts → View/MainView.ts} +19 -27
  61. package/src/View/ViewManager.ts +53 -0
  62. package/src/constants.ts +2 -3
  63. package/src/index.ts +143 -171
  64. package/src/shim.d.ts +4 -0
  65. package/src/style.css +7 -1
  66. package/src/typings.ts +1 -0
  67. package/vite.config.js +4 -1
  68. package/dist/Utils/CameraStore.d.ts +0 -15
  69. package/dist/ViewManager.d.ts +0 -29
  70. package/dist/sdk.d.ts +0 -14
  71. package/src/Utils/CameraStore.ts +0 -72
  72. package/src/sdk.ts +0 -39
  73. package/src/viewManager.ts +0 -177
@@ -1,27 +1,29 @@
1
- import { AnimationMode, reaction, ViewVisionMode } from "white-web-sdk";
2
- import { Base } from "./Base";
3
- import { callbacks, emitter } from "./index";
1
+ import { AnimationMode, reaction } from "white-web-sdk";
2
+ import { Base } from "../Base";
3
+ import { callbacks, emitter } from "../index";
4
4
  import { createView } from "./ViewManager";
5
5
  import { debounce, isEmpty, isEqual } from "lodash";
6
- import { Fields } from "./AttributesDelegate";
7
- import { notifyMainViewModeChange, setViewFocusScenePath, setViewMode } from "./Utils/Common";
6
+ import { Fields } from "../AttributesDelegate";
7
+ import { setViewFocusScenePath } from "../Utils/Common";
8
+ import { SideEffectManager } from "side-effect-manager";
8
9
  import type { Camera, Size, View } from "white-web-sdk";
9
- import type { AppManager } from "./AppManager";
10
+ import type { AppManager } from "../AppManager";
10
11
 
11
12
  export class MainViewProxy extends Base {
12
13
  private scale?: number;
13
- private cameraStore = this.manager.cameraStore;
14
14
  private started = false;
15
15
  private mainViewIsAddListener = false;
16
16
  private mainView: View;
17
17
  private viewId = "mainView";
18
18
 
19
+ private sideEffectManager = new SideEffectManager();
20
+
19
21
  constructor(manager: AppManager) {
20
22
  super(manager);
21
23
  this.mainView = this.createMainView();
22
24
  this.moveCameraSizeByAttributes();
23
- this.cameraStore.register(this.viewId, this.mainView);
24
25
  emitter.once("mainViewMounted").then(() => {
26
+ this.addMainViewListener();
25
27
  setTimeout(() => {
26
28
  this.start();
27
29
  if (!this.mainViewCamera || !this.mainViewSize) {
@@ -29,8 +31,12 @@ export class MainViewProxy extends Base {
29
31
  }
30
32
  }, 200); // 等待 mainView 挂载完毕再进行监听,否则会触发不必要的 onSizeUpdated
31
33
  });
32
- emitter.on("playgroundSizeChange", () => {
34
+ const playgroundSizeChangeListener = () => {
33
35
  this.sizeChangeHandler(this.mainViewSize);
36
+ };
37
+ this.sideEffectManager.add(() => {
38
+ emitter.on("playgroundSizeChange", playgroundSizeChangeListener);
39
+ return () => emitter.off("playgroundSizeChange", playgroundSizeChangeListener);
34
40
  });
35
41
  }
36
42
 
@@ -75,7 +81,7 @@ export class MainViewProxy extends Base {
75
81
  );
76
82
  };
77
83
 
78
- private sizeChangeHandler = debounce((size: Size) => {
84
+ private sizeChangeHandler = debounce((size: Size) => {
79
85
  if (size) {
80
86
  this.moveCameraToContian(size);
81
87
  this.moveCamera(this.mainViewCamera);
@@ -96,15 +102,12 @@ export class MainViewProxy extends Base {
96
102
  if (mainViewScenePath) {
97
103
  setViewFocusScenePath(mainView, mainViewScenePath);
98
104
  }
99
- if (!this.store.focus) {
100
- this.switchViewModeToWriter();
101
- }
102
105
  return mainView;
103
106
  }
104
107
 
105
108
  private onCameraUpdatedByDevice = (camera: Camera) => {
106
109
  this.store.setMainViewCamera({ ...camera, id: this.context.uid });
107
- if (!isEqual(this.mainViewSize, {...this.mainView.size, id: this.context.uid})) {
110
+ if (!isEqual(this.mainViewSize, { ...this.mainView.size, id: this.context.uid })) {
108
111
  this.setMainViewSize(this.view.size);
109
112
  }
110
113
  };
@@ -131,7 +134,6 @@ export class MainViewProxy extends Base {
131
134
 
132
135
  public async mainViewClickHandler(): Promise<void> {
133
136
  if (!this.manager.canOperate) return;
134
- if (this.view.mode === ViewVisionMode.Writable) return;
135
137
  this.store.cleanFocus();
136
138
  this.context.blurFocusBox();
137
139
  }
@@ -156,17 +158,6 @@ export class MainViewProxy extends Base {
156
158
  callbacks.emit("cameraStateChange", this.cameraState);
157
159
  };
158
160
 
159
- public switchViewModeToWriter(): void {
160
- if (!this.manager.canOperate) return;
161
- if (this.view) {
162
- if (this.view.mode === ViewVisionMode.Writable) return;
163
- this.cameraStore.switchView(this.viewId, this.mainView, () => {
164
- notifyMainViewModeChange(callbacks, ViewVisionMode.Writable);
165
- setViewMode(this.view, ViewVisionMode.Writable);
166
- });
167
- }
168
- }
169
-
170
161
  public moveCameraToContian(size: Size): void {
171
162
  if (!isEmpty(size)) {
172
163
  this.view.moveCameraToContain({
@@ -195,6 +186,7 @@ export class MainViewProxy extends Base {
195
186
  }
196
187
 
197
188
  public stop() {
189
+ this.removeMainViewListener();
198
190
  this.removeCameraListener();
199
191
  this.manager.refresher?.remove(Fields.MainViewCamera);
200
192
  this.manager.refresher?.remove(Fields.MainViewSize);
@@ -203,6 +195,6 @@ export class MainViewProxy extends Base {
203
195
 
204
196
  public destroy() {
205
197
  this.stop();
206
- this.cameraStore.unregister(this.viewId, this.mainView);
198
+ this.sideEffectManager.flushAll();
207
199
  }
208
200
  }
@@ -0,0 +1,53 @@
1
+ import type { View , Displayer} from "white-web-sdk";
2
+
3
+ export class ViewManager {
4
+ public views: Map<string, View> = new Map();
5
+
6
+ constructor(private displayer: Displayer) {}
7
+
8
+ public createView(id: string): View {
9
+ const view = createView(this.displayer);
10
+ this.views.set(id, view);
11
+ return view;
12
+ }
13
+
14
+ public getView(id: string): View | undefined {
15
+ return this.views.get(id);
16
+ }
17
+
18
+ public destroyView(id: string): void {
19
+ const view = this.views.get(id);
20
+ if (view) {
21
+ view.release();
22
+ this.views.delete(id);
23
+ }
24
+ }
25
+
26
+ public setViewScenePath(id: string, scenePath: string): void {
27
+ const view = this.views.get(id);
28
+ if (view) {
29
+ view.focusScenePath = scenePath;
30
+ }
31
+ }
32
+
33
+ public destroy() {
34
+ this.views.forEach(view => {
35
+ view.release();
36
+ });
37
+ this.views.clear();
38
+ }
39
+ }
40
+
41
+
42
+ export const createView = (displayer: Displayer): View => {
43
+ const view = displayer.views.createView();
44
+ setDefaultCameraBound(view);
45
+ return view;
46
+ };
47
+
48
+ export const setDefaultCameraBound = (view: View) => {
49
+ view.setCameraBound({
50
+ maxContentMode: () => 10,
51
+ minContentMode: () => 0.1,
52
+ });
53
+ };
package/src/constants.ts CHANGED
@@ -10,6 +10,7 @@ export enum Events {
10
10
  SetMainViewScenePath = "SetMainViewScenePath",
11
11
  SetMainViewSceneIndex = "SetMainViewSceneIndex",
12
12
  SwitchViewsToFreedom = "SwitchViewsToFreedom",
13
+ MoveCameraToContain = "MoveCameraToContain"
13
14
  }
14
15
 
15
16
  export const MagixEventName = "__WindowManger";
@@ -36,13 +37,11 @@ export enum CursorState {
36
37
  Normal = "normal",
37
38
  }
38
39
 
39
- export const REQUIRE_VERSION = "2.13.16";
40
+ export const REQUIRE_VERSION = "2.16.0";
40
41
 
41
42
  export const MIN_WIDTH = 340 / 720;
42
43
  export const MIN_HEIGHT = 340 / 720;
43
44
 
44
45
  export const SET_SCENEPATH_DELAY = 100; // 设置 scenePath 的延迟事件
45
46
 
46
- export const DEFAULT_COLLECTOR_STYLE = { right: "10px", bottom: "15px", position: "absolute" };
47
-
48
47
  export const DEFAULT_CONTAINER_RATIO = 9 / 16;
package/src/index.ts CHANGED
@@ -1,18 +1,19 @@
1
- import AppDocsViewer from "@netless/app-docs-viewer";
2
- import AppMediaPlayer, { setOptions } from "@netless/app-media-player";
3
1
  import Emittery from "emittery";
4
2
  import pRetry from "p-retry";
5
3
  import { AppManager } from "./AppManager";
6
4
  import { appRegister } from "./Register";
5
+ import { ContainerResizeObserver } from "./ContainerResizeObserver";
6
+ import { createBoxManager } from "./BoxManager";
7
7
  import { CursorManager } from "./Cursor";
8
- import { DEFAULT_CONTAINER_RATIO, REQUIRE_VERSION } from "./constants";
8
+ import { DEFAULT_CONTAINER_RATIO, Events, REQUIRE_VERSION } from "./constants";
9
9
  import { Fields } from "./AttributesDelegate";
10
10
  import { initDb } from "./Register/storage";
11
11
  import { isNull, isObject } from "lodash";
12
12
  import { log } from "./Utils/log";
13
+ import { ReconnectRefresher } from "./ReconnectRefresher";
13
14
  import { replaceRoomFunction } from "./Utils/RoomHacker";
14
- import { ResizeObserver as ResizeObserverPolyfill } from "@juggle/resize-observer";
15
- import { setupWrapper } from "./ViewManager";
15
+ import { setupBuiltin } from "./BuiltinApps";
16
+ import { setupWrapper } from "./Helper";
16
17
  import "./style.css";
17
18
  import "@netless/telebox-insider/dist/style.css";
18
19
  import {
@@ -22,7 +23,7 @@ import {
22
23
  isValidScenePath,
23
24
  wait,
24
25
  } from "./Utils/Common";
25
- import type { TELE_BOX_STATE } from "./BoxManager";
26
+ import type { TELE_BOX_STATE, BoxManager } from "./BoxManager";
26
27
  import {
27
28
  AppCreateError,
28
29
  AppManagerNotInitError,
@@ -58,8 +59,6 @@ import type { NetlessApp, RegisterParams } from "./typings";
58
59
  import type { TeleBoxColorScheme, TeleBoxState } from "@netless/telebox-insider";
59
60
  import type { AppProxy } from "./AppProxy";
60
61
 
61
- const ResizeObserver = window.ResizeObserver || ResizeObserverPolyfill;
62
-
63
62
  export type WindowMangerAttributes = {
64
63
  modelValue?: string;
65
64
  boxState: TELE_BOX_STATE;
@@ -80,14 +79,14 @@ export type AddAppOptions = {
80
79
 
81
80
  export type setAppOptions = AddAppOptions & { appOptions?: any };
82
81
 
83
- export type AddAppParams = {
82
+ export type AddAppParams<TAttributes = any> = {
84
83
  kind: string;
85
84
  // app 地址(本地 app 不需要传)
86
85
  src?: string;
87
86
  // 窗口配置
88
87
  options?: AddAppOptions;
89
88
  // 初始化 attributes
90
- attributes?: any;
89
+ attributes?: TAttributes;
91
90
  };
92
91
 
93
92
  export type BaseInsertParams = {
@@ -108,6 +107,7 @@ export type AppSyncAttributes = {
108
107
  state?: any;
109
108
  isDynamicPPT?: boolean;
110
109
  fullPath?: string;
110
+ createdAt?: number;
111
111
  };
112
112
 
113
113
  export type AppInitState = {
@@ -137,9 +137,11 @@ export type EmitterEvent = {
137
137
  observerIdChange: number;
138
138
  boxStateChange: string;
139
139
  playgroundSizeChange: DOMRect;
140
+ onReconnected: void;
140
141
  };
141
142
 
142
- export const emitter: Emittery<EmitterEvent> = new Emittery();
143
+ export type EmitterType = Emittery<EmitterEvent>;
144
+ export const emitter: EmitterType = new Emittery();
143
145
 
144
146
  export type PublicEvent = {
145
147
  mainViewModeChange: ViewVisionMode;
@@ -147,11 +149,13 @@ export type PublicEvent = {
147
149
  darkModeChange: boolean;
148
150
  prefersColorSchemeChange: TeleBoxColorScheme;
149
151
  cameraStateChange: CameraState;
152
+ mainViewScenePathChange: string;
153
+ mainViewSceneIndexChange: number;
150
154
  };
151
155
 
152
156
  export type MountParams = {
153
157
  room: Room;
154
- container: HTMLElement;
158
+ container?: HTMLElement;
155
159
  /** 白板高宽比例, 默认为 9 / 16 */
156
160
  containerSizeRatio?: number;
157
161
  /** 显示 PS 透明背景,默认 true */
@@ -165,7 +169,10 @@ export type MountParams = {
165
169
  prefersColorScheme?: TeleBoxColorScheme;
166
170
  };
167
171
 
168
- export const callbacks: Emittery<PublicEvent> = new Emittery();
172
+ export type CallbacksType = Emittery<PublicEvent>;
173
+ export const callbacks: CallbacksType = new Emittery();
174
+
175
+ export const reconnectRefresher = new ReconnectRefresher({ emitter });
169
176
 
170
177
  export class WindowManager extends InvisiblePlugin<WindowMangerAttributes> {
171
178
  public static kind = "WindowManager";
@@ -177,7 +184,7 @@ export class WindowManager extends InvisiblePlugin<WindowMangerAttributes> {
177
184
  public static containerSizeRatio = DEFAULT_CONTAINER_RATIO;
178
185
  private static isCreated = false;
179
186
 
180
- public version = "0.3.17";
187
+ public version = __APP_VERSION__;
181
188
 
182
189
  public appListeners?: AppListeners;
183
190
 
@@ -188,93 +195,40 @@ export class WindowManager extends InvisiblePlugin<WindowMangerAttributes> {
188
195
  public viewMode = ViewMode.Broadcaster;
189
196
  public isReplay = isPlayer(this.displayer);
190
197
 
198
+ private boxManager?: BoxManager;
199
+ private static params?: MountParams;
200
+
201
+ private containerResizeObserver?: ContainerResizeObserver;
202
+
191
203
  constructor(context: InvisiblePluginContext) {
192
204
  super(context);
205
+ WindowManager.displayer = context.displayer;
193
206
  }
194
207
 
195
- /**
196
- * 挂载 WindowManager
197
- * @deprecated
198
- */
199
- public static async mount(
200
- room: Room,
201
- container: HTMLElement,
202
- collectorContainer?: HTMLElement,
203
- options?: {
204
- chessboard: boolean;
205
- containerSizeRatio: number;
206
- collectorStyles?: Partial<CSSStyleDeclaration>;
207
- debug?: boolean;
208
- overwriteStyles?: string;
209
- }
210
- ): Promise<WindowManager>;
211
-
212
- public static async mount(params: MountParams): Promise<WindowManager>;
213
-
214
- public static async mount(
215
- params: MountParams | Room,
216
- container?: HTMLElement,
217
- collectorContainer?: HTMLElement,
218
- options?: {
219
- chessboard?: boolean;
220
- containerSizeRatio: number;
221
- collectorStyles?: Partial<CSSStyleDeclaration>;
222
- debug?: boolean;
223
- overwriteStyles?: string;
224
- disableCameraTransform?: boolean;
225
- }
226
- ): Promise<WindowManager> {
227
- let room: Room;
228
- let containerSizeRatio: number | undefined;
229
- let collectorStyles: Partial<CSSStyleDeclaration> | undefined;
230
- let debug: boolean | undefined;
231
- let chessboard = true;
232
- let overwriteStyles: string | undefined;
233
- let cursor: boolean | undefined;
234
- let disableCameraTransform = false;
235
- let prefersColorScheme: TeleBoxColorScheme | undefined = "light";
236
- if ("room" in params) {
237
- room = params.room;
238
- container = params.container;
239
- collectorContainer = params.collectorContainer;
240
- containerSizeRatio = params.containerSizeRatio;
241
- collectorStyles = params.collectorStyles;
242
- debug = params.debug;
243
- if (params.chessboard != null) {
244
- chessboard = params.chessboard;
245
- }
246
- overwriteStyles = params.overwriteStyles;
247
- cursor = params.cursor;
248
- disableCameraTransform = Boolean(params?.disableCameraTransform);
249
- prefersColorScheme = params.prefersColorScheme;
250
- } else {
251
- room = params;
252
- containerSizeRatio = options?.containerSizeRatio;
253
- collectorStyles = options?.collectorStyles;
254
- debug = options?.debug;
255
- if (options?.chessboard != null) {
256
- chessboard = options.chessboard;
257
- }
258
- overwriteStyles = options?.overwriteStyles;
259
- }
208
+ public static async mount(params: MountParams): Promise<WindowManager> {
209
+ const room = params.room;
210
+ WindowManager.container = params.container;
211
+ const containerSizeRatio = params.containerSizeRatio;
212
+ const debug = params.debug;
213
+
214
+ const cursor = params.cursor;
215
+ WindowManager.params = params;
260
216
 
261
217
  this.checkVersion();
262
218
  if (isRoom(room)) {
263
219
  if (room.phase !== RoomPhase.Connected) {
264
220
  throw new Error("[WindowManager]: Room only Connected can be mount");
265
221
  }
266
- }
267
- if (!container) {
268
- throw new Error("[WindowManager]: Container must provide");
222
+ if (room.phase === RoomPhase.Connected) {
223
+ // redo undo 需要设置这个属性
224
+ room.disableSerialization = false;
225
+ }
269
226
  }
270
227
  if (WindowManager.isCreated) {
271
228
  throw new Error("[WindowManager]: Already created cannot be created again");
272
229
  }
273
230
  let manager = await this.initManager(room);
274
231
  this.debug = Boolean(debug);
275
- if (this.debug) {
276
- setOptions({ verbose: true });
277
- }
278
232
  log("Already insert room", manager);
279
233
 
280
234
  if (isRoom(this.displayer)) {
@@ -297,29 +251,19 @@ export class WindowManager extends InvisiblePlugin<WindowMangerAttributes> {
297
251
  if (containerSizeRatio) {
298
252
  WindowManager.containerSizeRatio = containerSizeRatio;
299
253
  }
300
- WindowManager.container = container;
301
- const { playground, wrapper, sizer, mainViewElement } = setupWrapper(container);
302
- WindowManager.playground = playground;
303
- if (chessboard) {
304
- sizer.classList.add("netless-window-manager-chess-sizer");
305
- }
306
- if (overwriteStyles) {
307
- const style = document.createElement("style");
308
- style.textContent = overwriteStyles;
309
- playground.appendChild(style);
310
- }
311
254
  await manager.ensureAttributes();
312
- manager.appManager = new AppManager(manager, {
313
- collectorContainer: collectorContainer,
314
- collectorStyles: collectorStyles,
315
- prefersColorScheme: prefersColorScheme,
316
- });
317
- manager.observePlaygroundSize(playground, sizer, wrapper);
255
+
256
+ manager.appManager = new AppManager(manager);
257
+
318
258
  if (cursor) {
319
259
  manager.cursorManager = new CursorManager(manager.appManager);
320
260
  }
321
- manager.bindMainView(mainViewElement, disableCameraTransform);
322
- replaceRoomFunction(room, manager.appManager);
261
+
262
+ if (params.container) {
263
+ manager.bindContainer(params.container);
264
+ }
265
+
266
+ replaceRoomFunction(room, manager);
323
267
  emitter.emit("onCreated");
324
268
  WindowManager.isCreated = true;
325
269
  try {
@@ -359,6 +303,79 @@ export class WindowManager extends InvisiblePlugin<WindowMangerAttributes> {
359
303
  return manager;
360
304
  }
361
305
 
306
+ private static initContainer(
307
+ manager: WindowManager,
308
+ container: HTMLElement,
309
+ chessboard: boolean | undefined,
310
+ overwriteStyles: string | undefined
311
+ ) {
312
+ if (!WindowManager.container) {
313
+ WindowManager.container = container;
314
+ }
315
+ const { playground, wrapper, sizer, mainViewElement } = setupWrapper(container);
316
+ WindowManager.playground = playground;
317
+ if (chessboard) {
318
+ sizer.classList.add("netless-window-manager-chess-sizer");
319
+ }
320
+ if (overwriteStyles) {
321
+ const style = document.createElement("style");
322
+ style.textContent = overwriteStyles;
323
+ playground.appendChild(style);
324
+ }
325
+ manager.containerResizeObserver = ContainerResizeObserver.create(
326
+ playground,
327
+ sizer,
328
+ wrapper,
329
+ emitter
330
+ );
331
+ WindowManager.wrapper = wrapper;
332
+ return mainViewElement;
333
+ }
334
+
335
+ public bindContainer(container: HTMLElement) {
336
+ if (WindowManager.isCreated && WindowManager.container) {
337
+ if (WindowManager.container.firstChild) {
338
+ container.appendChild(WindowManager.container.firstChild);
339
+ }
340
+ } else {
341
+ if (WindowManager.params) {
342
+ const params = WindowManager.params;
343
+ const mainViewElement = WindowManager.initContainer(
344
+ this,
345
+ container,
346
+ params.chessboard,
347
+ params.overwriteStyles
348
+ );
349
+ const boxManager = createBoxManager(this, callbacks, emitter, {
350
+ collectorContainer: params.collectorContainer,
351
+ collectorStyles: params.collectorStyles,
352
+ prefersColorScheme: params.prefersColorScheme,
353
+ });
354
+ this.boxManager = boxManager;
355
+ this.appManager?.setBoxManager(boxManager);
356
+ this.bindMainView(mainViewElement, params.disableCameraTransform);
357
+ if (WindowManager.wrapper) {
358
+ this.cursorManager?.setupWrapper(WindowManager.wrapper);
359
+ }
360
+ }
361
+ }
362
+ this.boxManager?.updateManagerRect();
363
+ this.appManager?.refresh();
364
+ this.appManager?.resetMaximized();
365
+ this.appManager?.resetMinimized();
366
+ WindowManager.container = container;
367
+ }
368
+
369
+ public bindCollectorContainer(container: HTMLElement) {
370
+ if (WindowManager.isCreated && this.boxManager) {
371
+ this.boxManager.setCollectorContainer(container);
372
+ } else {
373
+ if (WindowManager.params) {
374
+ WindowManager.params.collectorContainer = container;
375
+ }
376
+ }
377
+ }
378
+
362
379
  /**
363
380
  * 注册插件
364
381
  */
@@ -371,7 +388,7 @@ export class WindowManager extends InvisiblePlugin<WindowMangerAttributes> {
371
388
  /**
372
389
  * 创建一个 app 至白板
373
390
  */
374
- public async addApp(params: AddAppParams): Promise<string | undefined> {
391
+ public async addApp<T = any>(params: AddAppParams<T>): Promise<string | undefined> {
375
392
  if (this.appManager) {
376
393
  if (!params.kind || typeof params.kind !== "string") {
377
394
  throw new ParamsInvalidError();
@@ -468,10 +485,8 @@ export class WindowManager extends InvisiblePlugin<WindowMangerAttributes> {
468
485
  * 设置所有 app 的 readonly 模式
469
486
  */
470
487
  public setReadonly(readonly: boolean): void {
471
- if (this.room?.isWritable) {
472
- this.readonly = readonly;
473
- this.appManager?.boxManager.setReadonly(readonly);
474
- }
488
+ this.readonly = readonly;
489
+ this.boxManager?.setReadonly(readonly);
475
490
  }
476
491
 
477
492
  /**
@@ -531,26 +546,30 @@ export class WindowManager extends InvisiblePlugin<WindowMangerAttributes> {
531
546
  return this.appManager?.store.apps();
532
547
  }
533
548
 
534
- public get boxState(): TeleBoxState {
549
+ public get boxState(): TeleBoxState | undefined {
535
550
  if (this.appManager) {
536
- return this.appManager.boxManager.boxState;
551
+ return this.appManager.boxManager?.boxState;
537
552
  } else {
538
553
  throw new AppManagerNotInitError();
539
554
  }
540
555
  }
541
556
 
542
557
  public get darkMode(): boolean {
543
- return Boolean(this.appManager?.boxManager.darkMode);
558
+ return Boolean(this.appManager?.boxManager?.darkMode);
544
559
  }
545
560
 
546
- public get prefersColorScheme(): TeleBoxColorScheme {
561
+ public get prefersColorScheme(): TeleBoxColorScheme | undefined {
547
562
  if (this.appManager) {
548
- return this.appManager.boxManager.prefersColorScheme;
563
+ return this.appManager.boxManager?.prefersColorScheme;
549
564
  } else {
550
565
  throw new AppManagerNotInitError();
551
566
  }
552
567
  }
553
568
 
569
+ public get focused(): string | undefined {
570
+ return this.attributes.focus;
571
+ }
572
+
554
573
  /**
555
574
  * 查询所有的 App
556
575
  */
@@ -585,6 +604,10 @@ export class WindowManager extends InvisiblePlugin<WindowMangerAttributes> {
585
604
  }>
586
605
  ): void {
587
606
  this.mainView.moveCameraToContain(rectangle);
607
+ this.appManager?.dispatchInternalEvent(Events.MoveCameraToContain, rectangle);
608
+ setTimeout(() => {
609
+ this.appManager?.mainViewProxy.setCameraAndSize();
610
+ }, 1000);
588
611
  }
589
612
 
590
613
  public convertToPointInWorld(point: Point): Point {
@@ -613,12 +636,13 @@ export class WindowManager extends InvisiblePlugin<WindowMangerAttributes> {
613
636
  if (WindowManager.playground) {
614
637
  WindowManager.playground.parentNode?.removeChild(WindowManager.playground);
615
638
  }
639
+ WindowManager.params = undefined;
616
640
  log("Destroyed");
617
641
  }
618
642
 
619
- private bindMainView(divElement: HTMLDivElement, disableCameraTransform: boolean) {
643
+ private bindMainView(divElement: HTMLDivElement, disableCameraTransform: boolean | undefined) {
620
644
  if (this.appManager) {
621
- this.appManager.bindMainView(divElement, disableCameraTransform);
645
+ this.appManager.bindMainView(divElement, Boolean(disableCameraTransform));
622
646
  this.cursorManager?.setMainViewDivElement(divElement);
623
647
  }
624
648
  }
@@ -651,7 +675,7 @@ export class WindowManager extends InvisiblePlugin<WindowMangerAttributes> {
651
675
  }
652
676
 
653
677
  public setPrefersColorScheme(scheme: TeleBoxColorScheme): void {
654
- this.appManager?.boxManager.setPrefersColorScheme(scheme);
678
+ this.appManager?.boxManager?.setPrefersColorScheme(scheme);
655
679
  }
656
680
 
657
681
  private isDynamicPPT(scenes: SceneDefinition[]) {
@@ -686,62 +710,10 @@ export class WindowManager extends InvisiblePlugin<WindowMangerAttributes> {
686
710
  }
687
711
  }
688
712
  }
689
-
690
- private containerResizeObserver?: ResizeObserver;
691
-
692
- private observePlaygroundSize(
693
- container: HTMLElement,
694
- sizer: HTMLElement,
695
- wrapper: HTMLDivElement
696
- ) {
697
- this.updateSizer(container.getBoundingClientRect(), sizer, wrapper);
698
-
699
- this.containerResizeObserver = new ResizeObserver(entries => {
700
- const containerRect = entries[0]?.contentRect;
701
- if (containerRect) {
702
- this.updateSizer(containerRect, sizer, wrapper);
703
- this.cursorManager?.updateContainerRect();
704
- this.appManager?.boxManager.updateManagerRect();
705
- emitter.emit("playgroundSizeChange", containerRect);
706
- }
707
- });
708
-
709
- this.containerResizeObserver.observe(container);
710
- }
711
-
712
- private updateSizer(
713
- { width, height }: DOMRectReadOnly,
714
- sizer: HTMLElement,
715
- wrapper: HTMLDivElement
716
- ) {
717
- if (width && height) {
718
- if (height / width > WindowManager.containerSizeRatio) {
719
- height = width * WindowManager.containerSizeRatio;
720
- sizer.classList.toggle("netless-window-manager-sizer-horizontal", true);
721
- } else {
722
- width = height / WindowManager.containerSizeRatio;
723
- sizer.classList.toggle("netless-window-manager-sizer-horizontal", false);
724
- }
725
- wrapper.style.width = `${width}px`;
726
- wrapper.style.height = `${height}px`;
727
- }
728
- }
729
713
  }
730
714
 
731
- WindowManager.register({
732
- kind: AppDocsViewer.kind,
733
- src: AppDocsViewer,
734
- });
735
- WindowManager.register({
736
- kind: AppMediaPlayer.kind,
737
- src: AppMediaPlayer,
738
- });
739
-
740
- export const BuiltinApps = {
741
- DocsViewer: AppDocsViewer.kind as string,
742
- MediaPlayer: AppMediaPlayer.kind as string,
743
- };
715
+ setupBuiltin();
744
716
 
745
717
  export * from "./typings";
746
718
 
747
- export { WhiteWindowSDK } from "./sdk";
719
+ export { BuiltinApps } from "./BuiltinApps";