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

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.
@@ -1,8 +1,13 @@
1
- import { isFunction } from 'lodash';
2
- import { RoomPhase } from 'white-web-sdk';
1
+ import { debounce, isFunction } from "lodash";
2
+ import { emitter } from "./index";
3
+ import { log } from "./Utils/log";
4
+ import { RoomPhase } from "white-web-sdk";
3
5
  import type { Room } from "white-web-sdk";
4
- import type { AppManager } from './AppManager';
5
- import { log } from './Utils/log';
6
+ import type { EmitterType } from "./index";
7
+
8
+ export type ReconnectRefresherContext = {
9
+ emitter: EmitterType;
10
+ };
6
11
 
7
12
  // 白板重连之后会刷新所有的对象,导致 listener 失效, 所以这里在重连之后重新对所有对象进行监听
8
13
  export class ReconnectRefresher {
@@ -11,20 +16,27 @@ export class ReconnectRefresher {
11
16
  private reactors: Map<string, any> = new Map();
12
17
  private disposers: Map<string, any> = new Map();
13
18
 
14
- constructor(room: Room | undefined, private manager: AppManager) {
19
+ constructor(private ctx: ReconnectRefresherContext) {}
20
+
21
+ public setRoom(room: Room | undefined) {
15
22
  this.room = room;
16
23
  this.phase = room?.phase;
24
+ room?.callbacks.off("onPhaseChanged", this.onPhaseChanged);
17
25
  room?.callbacks.on("onPhaseChanged", this.onPhaseChanged);
18
26
  }
19
27
 
28
+ public setContext(ctx: ReconnectRefresherContext) {
29
+ this.ctx = ctx;
30
+ }
31
+
20
32
  private onPhaseChanged = (phase: RoomPhase) => {
21
33
  if (phase === RoomPhase.Connected && this.phase === RoomPhase.Reconnecting) {
22
34
  this.onReconnected();
23
35
  }
24
36
  this.phase = phase;
25
- }
37
+ };
26
38
 
27
- private onReconnected = () => {
39
+ private onReconnected = debounce(() => {
28
40
  log("onReconnected refresh reactors");
29
41
  this.releaseDisposers();
30
42
  this.reactors.forEach((func, id) => {
@@ -32,15 +44,15 @@ export class ReconnectRefresher {
32
44
  this.disposers.set(id, func());
33
45
  }
34
46
  });
35
- this.manager.notifyReconnected();
36
- }
47
+ this.ctx.emitter.emit("onReconnected", undefined);
48
+ }, 3000);
37
49
 
38
50
  private releaseDisposers() {
39
51
  this.disposers.forEach(disposer => {
40
52
  if (isFunction(disposer)) {
41
53
  disposer();
42
54
  }
43
- })
55
+ });
44
56
  this.disposers.clear();
45
57
  }
46
58
 
@@ -64,8 +76,16 @@ export class ReconnectRefresher {
64
76
  }
65
77
  }
66
78
 
79
+ public hasReactor(id: string) {
80
+ return this.reactors.has(id);
81
+ }
82
+
67
83
  public destroy() {
68
84
  this.room?.callbacks.off("onPhaseChanged", this.onPhaseChanged);
69
85
  this.releaseDisposers();
70
86
  }
71
87
  }
88
+
89
+ export const reconnectRefresher = new ReconnectRefresher({
90
+ emitter: emitter,
91
+ });
@@ -1,10 +1,10 @@
1
- import { emitter } from '../index';
2
- import { isPlayer } from 'white-web-sdk';
1
+ import { emitter } from "../index";
2
+ import { isPlayer } from "white-web-sdk";
3
+ import type { WindowManager } from '../index';
3
4
  import type { Camera, Room , Player , PlayerSeekingResult } from "white-web-sdk";
4
- import type { AppManager } from "../AppManager";
5
5
 
6
6
  // 修改多窗口状态下一些失效的方法实现到 manager 的 mainview 上, 降低迁移成本
7
- export const replaceRoomFunction = (room: Room, manager: AppManager) => {
7
+ export const replaceRoomFunction = (room: Room, manager: WindowManager) => {
8
8
  if (isPlayer(room)) {
9
9
  const player = room as unknown as Player;
10
10
  const originSeek = player.seekToProgressTime;
@@ -30,7 +30,7 @@ export const replaceRoomFunction = (room: Room, manager: AppManager) => {
30
30
  });
31
31
 
32
32
  room.moveCamera = (camera: Camera) => manager.mainView.moveCamera(camera);
33
- room.moveCameraToContain = (...args) => manager.mainView.moveCameraToContain(...args);
33
+ room.moveCameraToContain = (...args) => manager.moveCameraToContain(...args);
34
34
  room.convertToPointInWorld = (...args) => manager.mainView.convertToPointInWorld(...args);
35
35
  room.setCameraBound = (...args) => manager.mainView.setCameraBound(...args);
36
36
  room.scenePreview = (...args) => manager.mainView.scenePreview(...args);
@@ -1,3 +1,4 @@
1
+
1
2
  export class AppCreateError extends Error {
2
3
  override message = "[WindowManager]: app duplicate exists and cannot be created again";
3
4
  }
@@ -28,4 +29,8 @@ export class BoxNotCreatedError extends Error {
28
29
 
29
30
  export class InvalidScenePath extends Error {
30
31
  override message = `[WindowManager]: ScenePath should start with "/"`;
31
- }
32
+ }
33
+
34
+ export class BoxManagerNotFoundError extends Error {
35
+ override message = "[WindowManager]: boxManager not found";
36
+ }
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";
package/src/index.ts CHANGED
@@ -4,8 +4,9 @@ import Emittery from "emittery";
4
4
  import pRetry from "p-retry";
5
5
  import { AppManager } from "./AppManager";
6
6
  import { appRegister } from "./Register";
7
+ import { createBoxManager } from "./BoxManager";
7
8
  import { CursorManager } from "./Cursor";
8
- import { DEFAULT_CONTAINER_RATIO, REQUIRE_VERSION } from "./constants";
9
+ import { DEFAULT_CONTAINER_RATIO, Events, REQUIRE_VERSION } from "./constants";
9
10
  import { Fields } from "./AttributesDelegate";
10
11
  import { initDb } from "./Register/storage";
11
12
  import { isNull, isObject } from "lodash";
@@ -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,
@@ -80,14 +81,14 @@ export type AddAppOptions = {
80
81
 
81
82
  export type setAppOptions = AddAppOptions & { appOptions?: any };
82
83
 
83
- export type AddAppParams = {
84
+ export type AddAppParams<TAttributes = any> = {
84
85
  kind: string;
85
86
  // app 地址(本地 app 不需要传)
86
87
  src?: string;
87
88
  // 窗口配置
88
89
  options?: AddAppOptions;
89
90
  // 初始化 attributes
90
- attributes?: any;
91
+ attributes?: TAttributes;
91
92
  };
92
93
 
93
94
  export type BaseInsertParams = {
@@ -108,6 +109,7 @@ export type AppSyncAttributes = {
108
109
  state?: any;
109
110
  isDynamicPPT?: boolean;
110
111
  fullPath?: string;
112
+ createdAt?: number;
111
113
  };
112
114
 
113
115
  export type AppInitState = {
@@ -137,9 +139,11 @@ export type EmitterEvent = {
137
139
  observerIdChange: number;
138
140
  boxStateChange: string;
139
141
  playgroundSizeChange: DOMRect;
142
+ onReconnected: void;
140
143
  };
141
144
 
142
- export const emitter: Emittery<EmitterEvent> = new Emittery();
145
+ export type EmitterType = Emittery<EmitterEvent>;
146
+ export const emitter: EmitterType = new Emittery();
143
147
 
144
148
  export type PublicEvent = {
145
149
  mainViewModeChange: ViewVisionMode;
@@ -151,7 +155,7 @@ export type PublicEvent = {
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,8 @@ 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();
169
174
 
170
175
  export class WindowManager extends InvisiblePlugin<WindowMangerAttributes> {
171
176
  public static kind = "WindowManager";
@@ -177,7 +182,7 @@ export class WindowManager extends InvisiblePlugin<WindowMangerAttributes> {
177
182
  public static containerSizeRatio = DEFAULT_CONTAINER_RATIO;
178
183
  private static isCreated = false;
179
184
 
180
- public version = "0.3.17";
185
+ public version = "0.4.0-canary.2";
181
186
 
182
187
  public appListeners?: AppListeners;
183
188
 
@@ -188,75 +193,22 @@ export class WindowManager extends InvisiblePlugin<WindowMangerAttributes> {
188
193
  public viewMode = ViewMode.Broadcaster;
189
194
  public isReplay = isPlayer(this.displayer);
190
195
 
196
+ private boxManager?: BoxManager;
197
+ private static params?: MountParams;
198
+
191
199
  constructor(context: InvisiblePluginContext) {
192
200
  super(context);
201
+ WindowManager.displayer = context.displayer;
193
202
  }
194
203
 
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
- }
204
+ public static async mount(params: MountParams): Promise<WindowManager> {
205
+ const room = params.room;
206
+ WindowManager.container = params.container;
207
+ const containerSizeRatio = params.containerSizeRatio;
208
+ const debug = params.debug;
209
+
210
+ const cursor = params.cursor;
211
+ WindowManager.params = params;
260
212
 
261
213
  this.checkVersion();
262
214
  if (isRoom(room)) {
@@ -264,9 +216,6 @@ export class WindowManager extends InvisiblePlugin<WindowMangerAttributes> {
264
216
  throw new Error("[WindowManager]: Room only Connected can be mount");
265
217
  }
266
218
  }
267
- if (!container) {
268
- throw new Error("[WindowManager]: Container must provide");
269
- }
270
219
  if (WindowManager.isCreated) {
271
220
  throw new Error("[WindowManager]: Already created cannot be created again");
272
221
  }
@@ -297,29 +246,19 @@ export class WindowManager extends InvisiblePlugin<WindowMangerAttributes> {
297
246
  if (containerSizeRatio) {
298
247
  WindowManager.containerSizeRatio = containerSizeRatio;
299
248
  }
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
249
  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);
250
+
251
+ manager.appManager = new AppManager(manager);
252
+
318
253
  if (cursor) {
319
254
  manager.cursorManager = new CursorManager(manager.appManager);
320
255
  }
321
- manager.bindMainView(mainViewElement, disableCameraTransform);
322
- replaceRoomFunction(room, manager.appManager);
256
+
257
+ if (params.container) {
258
+ manager.bindContainer(params.container);
259
+ }
260
+
261
+ replaceRoomFunction(room, manager);
323
262
  emitter.emit("onCreated");
324
263
  WindowManager.isCreated = true;
325
264
  try {
@@ -359,6 +298,74 @@ export class WindowManager extends InvisiblePlugin<WindowMangerAttributes> {
359
298
  return manager;
360
299
  }
361
300
 
301
+ private static initContainer(
302
+ manager: WindowManager,
303
+ container: HTMLElement,
304
+ chessboard: boolean | undefined,
305
+ overwriteStyles: string | undefined
306
+ ) {
307
+ if (!WindowManager.container) {
308
+ WindowManager.container = container;
309
+ }
310
+ const { playground, wrapper, sizer, mainViewElement } = setupWrapper(container);
311
+ WindowManager.playground = playground;
312
+ if (chessboard) {
313
+ sizer.classList.add("netless-window-manager-chess-sizer");
314
+ }
315
+ if (overwriteStyles) {
316
+ const style = document.createElement("style");
317
+ style.textContent = overwriteStyles;
318
+ playground.appendChild(style);
319
+ }
320
+ manager.observePlaygroundSize(playground, sizer, wrapper);
321
+ WindowManager.wrapper = wrapper;
322
+ return mainViewElement;
323
+ }
324
+
325
+ public bindContainer(container: HTMLElement) {
326
+ if (WindowManager.isCreated && WindowManager.container) {
327
+ if (WindowManager.container.firstChild) {
328
+ container.appendChild(WindowManager.container.firstChild);
329
+ }
330
+ } else {
331
+ if (WindowManager.params) {
332
+ const params = WindowManager.params;
333
+ const mainViewElement = WindowManager.initContainer(
334
+ this,
335
+ container,
336
+ params.chessboard,
337
+ params.overwriteStyles
338
+ );
339
+ const boxManager = createBoxManager(this, callbacks, emitter, {
340
+ collectorContainer: params.collectorContainer,
341
+ collectorStyles: params.collectorStyles,
342
+ prefersColorScheme: params.prefersColorScheme,
343
+ });
344
+ this.boxManager = boxManager;
345
+ this.appManager?.setBoxManager(boxManager);
346
+ this.bindMainView(mainViewElement, params.disableCameraTransform);
347
+ if (WindowManager.wrapper) {
348
+ this.cursorManager?.setupWrapper(WindowManager.wrapper);
349
+ }
350
+ }
351
+ }
352
+ this.boxManager?.updateManagerRect();
353
+ this.appManager?.refresh();
354
+ this.appManager?.resetMaximized();
355
+ this.appManager?.resetMinimized();
356
+ WindowManager.container = container;
357
+ }
358
+
359
+ public bindCollectorContainer(container: HTMLElement) {
360
+ if (WindowManager.isCreated) {
361
+ this.boxManager?.setCollectorContainer(container);
362
+ } else {
363
+ if (WindowManager.params) {
364
+ WindowManager.params.collectorContainer = container;
365
+ }
366
+ }
367
+ }
368
+
362
369
  /**
363
370
  * 注册插件
364
371
  */
@@ -371,7 +378,7 @@ export class WindowManager extends InvisiblePlugin<WindowMangerAttributes> {
371
378
  /**
372
379
  * 创建一个 app 至白板
373
380
  */
374
- public async addApp(params: AddAppParams): Promise<string | undefined> {
381
+ public async addApp<T = any>(params: AddAppParams<T>): Promise<string | undefined> {
375
382
  if (this.appManager) {
376
383
  if (!params.kind || typeof params.kind !== "string") {
377
384
  throw new ParamsInvalidError();
@@ -470,7 +477,7 @@ export class WindowManager extends InvisiblePlugin<WindowMangerAttributes> {
470
477
  public setReadonly(readonly: boolean): void {
471
478
  if (this.room?.isWritable) {
472
479
  this.readonly = readonly;
473
- this.appManager?.boxManager.setReadonly(readonly);
480
+ this.appManager?.boxManager?.setReadonly(readonly);
474
481
  }
475
482
  }
476
483
 
@@ -531,21 +538,21 @@ export class WindowManager extends InvisiblePlugin<WindowMangerAttributes> {
531
538
  return this.appManager?.store.apps();
532
539
  }
533
540
 
534
- public get boxState(): TeleBoxState {
541
+ public get boxState(): TeleBoxState | undefined {
535
542
  if (this.appManager) {
536
- return this.appManager.boxManager.boxState;
543
+ return this.appManager.boxManager?.boxState;
537
544
  } else {
538
545
  throw new AppManagerNotInitError();
539
546
  }
540
547
  }
541
548
 
542
549
  public get darkMode(): boolean {
543
- return Boolean(this.appManager?.boxManager.darkMode);
550
+ return Boolean(this.appManager?.boxManager?.darkMode);
544
551
  }
545
552
 
546
- public get prefersColorScheme(): TeleBoxColorScheme {
553
+ public get prefersColorScheme(): TeleBoxColorScheme | undefined {
547
554
  if (this.appManager) {
548
- return this.appManager.boxManager.prefersColorScheme;
555
+ return this.appManager.boxManager?.prefersColorScheme;
549
556
  } else {
550
557
  throw new AppManagerNotInitError();
551
558
  }
@@ -585,6 +592,10 @@ export class WindowManager extends InvisiblePlugin<WindowMangerAttributes> {
585
592
  }>
586
593
  ): void {
587
594
  this.mainView.moveCameraToContain(rectangle);
595
+ this.appManager?.dispatchInternalEvent(Events.MoveCameraToContain, rectangle);
596
+ setTimeout(() => {
597
+ this.appManager?.mainViewProxy.setCameraAndSize();
598
+ }, 1000);
588
599
  }
589
600
 
590
601
  public convertToPointInWorld(point: Point): Point {
@@ -613,12 +624,13 @@ export class WindowManager extends InvisiblePlugin<WindowMangerAttributes> {
613
624
  if (WindowManager.playground) {
614
625
  WindowManager.playground.parentNode?.removeChild(WindowManager.playground);
615
626
  }
627
+ WindowManager.params = undefined;
616
628
  log("Destroyed");
617
629
  }
618
630
 
619
- private bindMainView(divElement: HTMLDivElement, disableCameraTransform: boolean) {
631
+ private bindMainView(divElement: HTMLDivElement, disableCameraTransform: boolean | undefined) {
620
632
  if (this.appManager) {
621
- this.appManager.bindMainView(divElement, disableCameraTransform);
633
+ this.appManager.bindMainView(divElement, Boolean(disableCameraTransform));
622
634
  this.cursorManager?.setMainViewDivElement(divElement);
623
635
  }
624
636
  }
@@ -651,7 +663,7 @@ export class WindowManager extends InvisiblePlugin<WindowMangerAttributes> {
651
663
  }
652
664
 
653
665
  public setPrefersColorScheme(scheme: TeleBoxColorScheme): void {
654
- this.appManager?.boxManager.setPrefersColorScheme(scheme);
666
+ this.appManager?.boxManager?.setPrefersColorScheme(scheme);
655
667
  }
656
668
 
657
669
  private isDynamicPPT(scenes: SceneDefinition[]) {
@@ -701,7 +713,7 @@ export class WindowManager extends InvisiblePlugin<WindowMangerAttributes> {
701
713
  if (containerRect) {
702
714
  this.updateSizer(containerRect, sizer, wrapper);
703
715
  this.cursorManager?.updateContainerRect();
704
- this.appManager?.boxManager.updateManagerRect();
716
+ this.boxManager?.updateManagerRect();
705
717
  emitter.emit("playgroundSizeChange", containerRect);
706
718
  }
707
719
  });
package/src/style.css CHANGED
@@ -115,7 +115,7 @@
115
115
  flex-direction: column;
116
116
  align-items: center;
117
117
  justify-content: center;
118
- position: fixed;
118
+ position: absolute;
119
119
  width: 26px;
120
120
  height: 26px;
121
121
  z-index: 2147483647;
@@ -103,7 +103,7 @@ export class ViewManager extends Base {
103
103
  setViewMode(this.mainView, ViewVisionMode.Freedom);
104
104
  }
105
105
  if (!this.mainView.focusScenePath) {
106
- this.store.setMainViewFocusPath();
106
+ this.store.setMainViewFocusPath(this.mainView);
107
107
  }
108
108
  }
109
109
 
@@ -116,7 +116,7 @@ export class ViewManager extends Base {
116
116
  this.appTimer = setTimeout(() => {
117
117
  const appProxy = this.manager.appProxies.get(id);
118
118
  if (appProxy) {
119
- if (this.manager.boxManager.minimized) return;
119
+ if (this.manager.boxManager?.minimized) return;
120
120
  appProxy.setScenePath();
121
121
  appProxy.switchToWritable();
122
122
  appProxy.focusBox();