@netless/window-manager 1.0.0-canary.6 → 1.0.0-canary.60

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 (111) hide show
  1. package/README.md +30 -6
  2. package/dist/index.js +13539 -0
  3. package/dist/index.mjs +13536 -0
  4. package/dist/index.umd.js +13534 -46
  5. package/dist/{App → src/App}/AppContext.d.ts +16 -14
  6. package/dist/{App → src/App}/AppPageStateImpl.d.ts +0 -0
  7. package/dist/{App → src/App}/AppProxy.d.ts +30 -11
  8. package/dist/{App → src/App}/MagixEvent/index.d.ts +0 -0
  9. package/dist/src/App/WhiteboardView.d.ts +27 -0
  10. package/dist/{App → src/App}/index.d.ts +1 -0
  11. package/dist/src/App/type.d.ts +21 -0
  12. package/dist/{AppListener.d.ts → src/AppListener.d.ts} +2 -2
  13. package/dist/{AppManager.d.ts → src/AppManager.d.ts} +11 -6
  14. package/dist/{AttributesDelegate.d.ts → src/AttributesDelegate.d.ts} +5 -2
  15. package/dist/{BoxEmitter.d.ts → src/BoxEmitter.d.ts} +0 -0
  16. package/dist/{BoxManager.d.ts → src/BoxManager.d.ts} +12 -6
  17. package/dist/{BuiltinApps.d.ts → src/BuiltinApps.d.ts} +3 -0
  18. package/dist/{Cursor → src/Cursor}/Cursor.d.ts +0 -0
  19. package/dist/{Cursor → src/Cursor}/icons.d.ts +0 -0
  20. package/dist/{Cursor → src/Cursor}/index.d.ts +4 -3
  21. package/dist/{Helper.d.ts → src/Helper.d.ts} +4 -8
  22. package/dist/{InternalEmitter.d.ts → src/InternalEmitter.d.ts} +1 -4
  23. package/dist/{Page → src/Page}/PageController.d.ts +2 -1
  24. package/dist/{Page → src/Page}/index.d.ts +0 -0
  25. package/dist/{PageState.d.ts → src/PageState.d.ts} +0 -0
  26. package/dist/{ReconnectRefresher.d.ts → src/ReconnectRefresher.d.ts} +0 -0
  27. package/dist/{RedoUndo.d.ts → src/RedoUndo.d.ts} +0 -0
  28. package/dist/{Register → src/Register}/index.d.ts +4 -2
  29. package/dist/{Register → src/Register}/loader.d.ts +1 -1
  30. package/dist/src/Register/storage.d.ts +11 -0
  31. package/dist/{Utils → src/Utils}/AppCreateQueue.d.ts +0 -0
  32. package/dist/{Utils → src/Utils}/Common.d.ts +0 -0
  33. package/dist/{Utils → src/Utils}/Reactive.d.ts +1 -1
  34. package/dist/{Utils → src/Utils}/RoomHacker.d.ts +0 -0
  35. package/dist/{Utils → src/Utils}/error.d.ts +1 -1
  36. package/dist/{Utils → src/Utils}/log.d.ts +0 -0
  37. package/dist/src/View/CameraSynchronizer.d.ts +20 -0
  38. package/dist/{View → src/View}/MainView.d.ts +18 -7
  39. package/dist/src/View/ScrollMode.d.ts +32 -0
  40. package/dist/{View → src/View}/ViewManager.d.ts +0 -0
  41. package/dist/src/View/ViewSync.d.ts +32 -0
  42. package/dist/{callback.d.ts → src/callback.d.ts} +13 -1
  43. package/dist/{constants.d.ts → src/constants.d.ts} +12 -5
  44. package/dist/src/image.d.ts +19 -0
  45. package/dist/{index.d.ts → src/index.d.ts} +66 -17
  46. package/dist/src/shim.d.ts +11 -0
  47. package/dist/src/storage.d.ts +7 -0
  48. package/dist/{typings.d.ts → src/typings.d.ts} +18 -8
  49. package/dist/style.css +810 -1
  50. package/docs/api.md +10 -0
  51. package/docs/app-context.md +155 -27
  52. package/docs/mirgrate-to-1.0.md +68 -0
  53. package/package.json +27 -22
  54. package/playwright.config.ts +29 -0
  55. package/pnpm-lock.yaml +3141 -4483
  56. package/src/App/AppContext.ts +81 -46
  57. package/src/App/AppProxy.ts +249 -139
  58. package/src/App/WhiteboardView.ts +38 -14
  59. package/src/App/index.ts +1 -0
  60. package/src/App/type.ts +22 -0
  61. package/src/AppListener.ts +21 -21
  62. package/src/AppManager.ts +84 -43
  63. package/src/AttributesDelegate.ts +6 -3
  64. package/src/BoxManager.ts +76 -38
  65. package/src/BuiltinApps.ts +9 -8
  66. package/src/Cursor/Cursor.svelte +6 -2
  67. package/src/Cursor/Cursor.ts +16 -5
  68. package/src/Cursor/icons.ts +6 -0
  69. package/src/Cursor/index.ts +13 -10
  70. package/src/Helper.ts +25 -7
  71. package/src/InternalEmitter.ts +1 -4
  72. package/src/Page/PageController.ts +2 -1
  73. package/src/PageState.ts +1 -1
  74. package/src/ReconnectRefresher.ts +6 -2
  75. package/src/Register/index.ts +36 -14
  76. package/src/Register/loader.ts +20 -9
  77. package/src/Register/storage.ts +26 -5
  78. package/src/Utils/Common.ts +3 -0
  79. package/src/Utils/Reactive.ts +29 -27
  80. package/src/Utils/RoomHacker.ts +3 -0
  81. package/src/Utils/error.ts +2 -2
  82. package/src/View/CameraSynchronizer.ts +52 -37
  83. package/src/View/MainView.ts +118 -76
  84. package/src/View/ScrollMode.ts +239 -0
  85. package/src/View/ViewSync.ts +139 -6
  86. package/src/callback.ts +9 -1
  87. package/src/constants.ts +11 -3
  88. package/src/image/pencil-eraser-1.svg +3 -0
  89. package/src/image/pencil-eraser-2.svg +3 -0
  90. package/src/image/pencil-eraser-3.svg +3 -0
  91. package/src/index.ts +202 -58
  92. package/src/storage.ts +15 -0
  93. package/src/style.css +18 -47
  94. package/src/typings.ts +21 -7
  95. package/vite.config.js +12 -7
  96. package/dist/App/AppViewSync.d.ts +0 -11
  97. package/dist/App/Storage/StorageEvent.d.ts +0 -8
  98. package/dist/App/Storage/index.d.ts +0 -39
  99. package/dist/App/Storage/typings.d.ts +0 -22
  100. package/dist/App/Storage/utils.d.ts +0 -5
  101. package/dist/App/WhiteboardView.d.ts +0 -21
  102. package/dist/Register/storage.d.ts +0 -8
  103. package/dist/View/CameraSynchronizer.d.ts +0 -17
  104. package/dist/View/ViewSync.d.ts +0 -7
  105. package/dist/index.cjs.js +0 -46
  106. package/dist/index.es.js +0 -16159
  107. package/src/App/AppViewSync.ts +0 -68
  108. package/src/App/Storage/StorageEvent.ts +0 -21
  109. package/src/App/Storage/index.ts +0 -295
  110. package/src/App/Storage/typings.ts +0 -23
  111. package/src/App/Storage/utils.ts +0 -17
package/src/index.ts CHANGED
@@ -2,7 +2,7 @@ import pRetry from "p-retry";
2
2
  import { AppManager } from "./AppManager";
3
3
  import { appRegister } from "./Register";
4
4
  import { callbacks } from "./callback";
5
- import { checkVersion, setupWrapper } from "./Helper";
5
+ import { checkVersion, createInvisiblePlugin, setupWrapper } from "./Helper";
6
6
  import { createBoxManager } from "./BoxManager";
7
7
  import { CursorManager } from "./Cursor";
8
8
  import { DEFAULT_CONTAINER_RATIO, Events, INIT_DIR, ROOT_DIR } from "./constants";
@@ -10,13 +10,12 @@ import { emitter } from "./InternalEmitter";
10
10
  import { Fields } from "./AttributesDelegate";
11
11
  import { initDb } from "./Register/storage";
12
12
  import { InvisiblePlugin, isPlayer, isRoom, RoomPhase, ViewMode } from "white-web-sdk";
13
- import { isEqual, isNull, isObject, omit, isNumber } from "lodash";
13
+ import { isEqual, isNull, isObject, isNumber, omit, debounce } from "lodash";
14
14
  import { log } from "./Utils/log";
15
15
  import { PageStateImpl } from "./PageState";
16
16
  import { ReconnectRefresher } from "./ReconnectRefresher";
17
17
  import { replaceRoomFunction } from "./Utils/RoomHacker";
18
18
  import { setupBuiltin } from "./BuiltinApps";
19
- import "video.js/dist/video-js.css";
20
19
  import "./style.css";
21
20
  import "@netless/telebox-insider/dist/style.css";
22
21
  import {
@@ -27,6 +26,8 @@ import {
27
26
  putScenes,
28
27
  wait,
29
28
  } from "./Utils/Common";
29
+ import { boxEmitter } from "./BoxEmitter";
30
+ import { Val } from "value-enhancer";
30
31
  import type { TELE_BOX_STATE, BoxManager } from "./BoxManager";
31
32
  import * as Errors from "./Utils/error";
32
33
  import type { Apps, Position , ICamera, ISize } from "./AttributesDelegate";
@@ -37,29 +38,31 @@ import type {
37
38
  Room,
38
39
  InvisiblePluginContext,
39
40
  Camera,
40
- AnimationMode,
41
41
  CameraBound,
42
42
  Point,
43
- Rectangle,
44
43
  CameraState,
45
44
  Player,
46
45
  ImageInformation,
47
46
  SceneState,
47
+ Size,
48
+ AnimationMode,
49
+ Rectangle,
48
50
  } from "white-web-sdk";
49
51
  import type { AppListeners } from "./AppListener";
50
- import type { ApplianceIcons, NetlessApp, RegisterParams } from "./typings";
51
- import type { TeleBoxColorScheme, TeleBoxState } from "@netless/telebox-insider";
52
+ import type { ApplianceIcons, ManagerViewMode, NetlessApp, RegisterParams } from "./typings";
53
+ import type { TeleBoxColorScheme, TeleBoxFullscreen, TeleBoxManager, TeleBoxManagerThemeConfig, TeleBoxState } from "@netless/telebox-insider";
52
54
  import type { AppProxy } from "./App";
53
55
  import type { PublicEvent } from "./callback";
54
56
  import type Emittery from "emittery";
55
57
  import type { PageController, AddPageParams, PageState } from "./Page";
56
- import { boxEmitter } from "./BoxEmitter";
58
+ import type { ScrollState } from "./View/ScrollMode";
57
59
 
58
60
  export type WindowMangerAttributes = {
59
61
  modelValue?: string;
60
62
  boxState: TELE_BOX_STATE;
61
63
  maximized?: boolean;
62
64
  minimized?: boolean;
65
+ scrollTop?: number;
63
66
  [key: string]: any;
64
67
  };
65
68
 
@@ -106,6 +109,7 @@ export type AppSyncAttributes = {
106
109
  createdAt?: number;
107
110
  camera?: ICamera;
108
111
  size?: ISize;
112
+ setup: boolean;
109
113
  };
110
114
 
111
115
  export type AppInitState = {
@@ -120,6 +124,11 @@ export type AppInitState = {
120
124
  sceneIndex?: number;
121
125
  boxState?: TeleBoxState; // 兼容旧版 telebox
122
126
  zIndex?: number;
127
+ visible?: boolean;
128
+ stageRatio?: number;
129
+ resizable?: boolean;
130
+ draggable?: boolean;
131
+ ratio?: number;
123
132
  };
124
133
 
125
134
  export type CursorMovePayload = { uid: string; state?: "leave"; position: Position };
@@ -129,8 +138,6 @@ export type MountParams = {
129
138
  container?: HTMLElement;
130
139
  /** 白板高宽比例, 默认为 9 / 16 */
131
140
  containerSizeRatio?: number;
132
- /** 显示 PS 透明背景,默认 true */
133
- chessboard?: boolean;
134
141
  collectorContainer?: HTMLElement;
135
142
  collectorStyles?: Partial<CSSStyleDeclaration>;
136
143
  overwriteStyles?: string;
@@ -138,12 +145,28 @@ export type MountParams = {
138
145
  debug?: boolean;
139
146
  disableCameraTransform?: boolean;
140
147
  prefersColorScheme?: TeleBoxColorScheme;
148
+ /** @deprecated */
149
+ chessboard?: boolean;
141
150
  applianceIcons?: ApplianceIcons;
151
+ containerStyle?: string;
152
+ stageStyle?: string;
153
+ fullscreen?: TeleBoxFullscreen;
154
+ /** Custom `style` attribute value for content area of all boxes. Can be overwritten by box. */
155
+ defaultBoxBodyStyle?: string | null;
156
+ /** Custom `style` attribute value for stage area of all boxes. Can be overwritten by box. */
157
+ defaultBoxStageStyle?: string | null;
158
+ /** Theme variable */
159
+ theme?: TeleBoxManagerThemeConfig;
160
+ /** ScrollMode BaseWidth */
161
+ scrollModeWidth?: number;
162
+ /** ScrollMode BaseHeight */
163
+ scrollModeHeight?: number;
164
+ viewMode?: ManagerViewMode;
142
165
  };
143
166
 
144
167
  export const reconnectRefresher = new ReconnectRefresher({ emitter });
145
168
 
146
- export class WindowManager extends InvisiblePlugin<WindowMangerAttributes> implements PageController {
169
+ export class WindowManager extends InvisiblePlugin<WindowMangerAttributes, any> implements PageController {
147
170
  public static kind = "WindowManager";
148
171
  public static displayer: Displayer;
149
172
  public static playground?: HTMLElement;
@@ -151,6 +174,7 @@ export class WindowManager extends InvisiblePlugin<WindowMangerAttributes> imple
151
174
  public static debug = false;
152
175
  public static containerSizeRatio = DEFAULT_CONTAINER_RATIO;
153
176
  private static isCreated = false;
177
+ public static registry = appRegister;
154
178
 
155
179
  public version = __APP_VERSION__;
156
180
  public dependencies = __APP_DEPENDENCIES__;
@@ -161,7 +185,8 @@ export class WindowManager extends InvisiblePlugin<WindowMangerAttributes> imple
161
185
  public emitter: Emittery<PublicEvent> = callbacks;
162
186
  public appManager?: AppManager;
163
187
  public cursorManager?: CursorManager;
164
- public viewMode = ViewMode.Broadcaster;
188
+ public viewMode$ = new Val<ManagerViewMode>(ViewMode.Broadcaster);
189
+ public playground$ = new Val<HTMLElement | undefined>(undefined);
165
190
  public isReplay = isPlayer(this.displayer);
166
191
  private _pageState?: PageStateImpl;
167
192
 
@@ -179,14 +204,13 @@ export class WindowManager extends InvisiblePlugin<WindowMangerAttributes> imple
179
204
  public static async mount(params: MountParams): Promise<WindowManager> {
180
205
  const room = params.room;
181
206
  WindowManager.container = params.container;
182
- const containerSizeRatio = params.containerSizeRatio;
183
207
  const debug = params.debug;
184
-
185
208
  const cursor = params.cursor;
186
209
  WindowManager.params = params;
187
210
  WindowManager.displayer = params.room;
188
- checkVersion();
189
211
  let manager: WindowManager | undefined = undefined;
212
+
213
+ checkVersion();
190
214
  if (isRoom(room)) {
191
215
  if (room.phase !== RoomPhase.Connected) {
192
216
  throw new Error("[WindowManager]: Room only Connected can be mount");
@@ -225,33 +249,42 @@ export class WindowManager extends InvisiblePlugin<WindowMangerAttributes> imple
225
249
  throw new Error("[WindowManager]: create manager failed");
226
250
  }
227
251
 
228
- if (containerSizeRatio) {
229
- WindowManager.containerSizeRatio = containerSizeRatio;
252
+ if (params.containerSizeRatio) {
253
+ WindowManager.containerSizeRatio = params.containerSizeRatio;
230
254
  }
255
+ manager.containerSizeRatio = WindowManager.containerSizeRatio;
231
256
  await manager.ensureAttributes();
232
-
257
+ if (params.viewMode) {
258
+ manager.viewMode$.setValue(params.viewMode);
259
+ }
233
260
  manager.appManager = new AppManager(manager);
234
261
  manager._pageState = new PageStateImpl(manager.appManager);
235
262
  manager.cursorManager = new CursorManager(manager.appManager, Boolean(cursor), params.applianceIcons);
236
- if (containerSizeRatio) {
237
- manager.containerSizeRatio = containerSizeRatio;
238
- }
263
+
239
264
  manager.boxManager = createBoxManager(manager, callbacks, emitter, boxEmitter, {
240
265
  collectorContainer: params.collectorContainer,
241
266
  collectorStyles: params.collectorStyles,
242
267
  prefersColorScheme: params.prefersColorScheme,
243
- stageRatio: params.containerSizeRatio,
268
+ stageRatio: WindowManager.containerSizeRatio,
269
+ containerStyle: params.containerStyle,
270
+ stageStyle: params.stageStyle,
271
+ fullscreen: params.fullscreen,
272
+ theme: params.theme,
244
273
  });
245
274
  manager.appManager?.setBoxManager(manager.boxManager);
246
275
  if (params.container) {
247
276
  manager.bindContainer(params.container);
248
277
  }
249
278
 
279
+ if (params.scrollModeWidth && params.scrollModeHeight) {
280
+ manager.appManager.scrollBaseSize$.setValue({ width: params.scrollModeWidth, height: params.scrollModeHeight });
281
+ }
282
+
250
283
  replaceRoomFunction(room, manager);
251
284
  emitter.emit("onCreated");
252
285
  WindowManager.isCreated = true;
253
286
  try {
254
- await initDb();
287
+ await initDb(appRegister);
255
288
  } catch (error) {
256
289
  console.warn("[WindowManager]: indexedDB open failed");
257
290
  console.log(error);
@@ -259,8 +292,8 @@ export class WindowManager extends InvisiblePlugin<WindowMangerAttributes> imple
259
292
  return manager;
260
293
  }
261
294
 
262
- private static async initManager(room: Room): Promise<WindowManager> {
263
- let manager = room.getInvisiblePlugin(WindowManager.kind) as WindowManager;
295
+ private static async initManager(room: Room): Promise<WindowManager | undefined> {
296
+ let manager = room.getInvisiblePlugin(WindowManager.kind) as WindowManager | undefined;
264
297
  if (!manager) {
265
298
  if (isRoom(room)) {
266
299
  if (room.isWritable === false) {
@@ -269,18 +302,12 @@ export class WindowManager extends InvisiblePlugin<WindowMangerAttributes> imple
269
302
  } catch (error) {
270
303
  throw new Error("[WindowManger]: room must be switched to be writable");
271
304
  }
272
- manager = (await room.createInvisiblePlugin(
273
- WindowManager,
274
- {}
275
- )) as WindowManager;
276
- manager.ensureAttributes();
305
+ manager = await createInvisiblePlugin(room);
306
+ manager?.ensureAttributes();
277
307
  await wait(500);
278
308
  await room.setWritable(false);
279
309
  } else {
280
- manager = (await room.createInvisiblePlugin(
281
- WindowManager,
282
- {}
283
- )) as WindowManager;
310
+ manager = await createInvisiblePlugin(room);
284
311
  }
285
312
  }
286
313
  }
@@ -289,12 +316,13 @@ export class WindowManager extends InvisiblePlugin<WindowMangerAttributes> imple
289
316
 
290
317
  private static initContainer(
291
318
  container: HTMLElement,
319
+ target: HTMLElement,
292
320
  overwriteStyles: string | undefined
293
321
  ) {
294
322
  if (!WindowManager.container) {
295
323
  WindowManager.container = container;
296
324
  }
297
- const { playground, mainViewElement } = setupWrapper(container);
325
+ const { playground, mainViewElement } = setupWrapper(container, target);
298
326
  WindowManager.playground = playground;
299
327
  if (overwriteStyles) {
300
328
  const style = document.createElement("style");
@@ -317,10 +345,12 @@ export class WindowManager extends InvisiblePlugin<WindowMangerAttributes> imple
317
345
  container.appendChild(WindowManager.container.firstChild);
318
346
  }
319
347
  } else {
320
- if (WindowManager.params) {
348
+ const teleboxContainer = this.boxManager?.teleBoxManager.$stage;
349
+ if (WindowManager.params && teleboxContainer) {
321
350
  const params = WindowManager.params;
322
351
  const mainViewElement = WindowManager.initContainer(
323
352
  container,
353
+ teleboxContainer,
324
354
  params.overwriteStyles
325
355
  );
326
356
  if (this.boxManager && WindowManager.playground) {
@@ -329,7 +359,9 @@ export class WindowManager extends InvisiblePlugin<WindowMangerAttributes> imple
329
359
  this.bindMainView(mainViewElement, params.disableCameraTransform);
330
360
  if (WindowManager.playground) {
331
361
  this.cursorManager?.setupWrapper(WindowManager.playground);
362
+ this.playground$.setValue(WindowManager.playground);
332
363
  }
364
+
333
365
  }
334
366
  }
335
367
  emitter.emit("updateManagerRect");
@@ -353,7 +385,7 @@ export class WindowManager extends InvisiblePlugin<WindowMangerAttributes> imple
353
385
  /**
354
386
  * 注册插件
355
387
  */
356
- public static register<AppOptions = any, SetupResult = any, Attributes = any>(
388
+ public static register<AppOptions = any, SetupResult = any, Attributes extends Record<string, any> = any>(
357
389
  params: RegisterParams<AppOptions, SetupResult, Attributes>
358
390
  ): Promise<void> {
359
391
  return appRegister.register(params);
@@ -504,15 +536,28 @@ export class WindowManager extends InvisiblePlugin<WindowMangerAttributes> imple
504
536
  }
505
537
  }
506
538
 
539
+ public async jumpPage(index: number): Promise<boolean> {
540
+ if (!this.appManager) {
541
+ return false;
542
+ }
543
+ if (index < 0 || index >= this.pageState.length) {
544
+ console.warn(`[WindowManager]: index ${index} out of range`);
545
+ return false;
546
+ }
547
+ await this.appManager.setMainViewSceneIndex(index);
548
+ return true;
549
+ }
550
+
507
551
  public async addPage(params?: AddPageParams): Promise<void> {
508
552
  if (this.appManager) {
509
553
  const after = params?.after;
510
- const scene = params?.scene;
554
+ const scene = params?.scene || {};
555
+ const scenes = Array.isArray(scene) ? scene : [scene];
511
556
  if (after) {
512
557
  const nextIndex = this.mainViewSceneIndex + 1;
513
- this.room.putScenes(ROOT_DIR, [scene || {}], nextIndex);
558
+ this.room.putScenes(ROOT_DIR, scenes, nextIndex);
514
559
  } else {
515
- this.room.putScenes(ROOT_DIR, [scene || {}]);
560
+ this.room.putScenes(ROOT_DIR, scenes);
516
561
  }
517
562
  }
518
563
  }
@@ -579,17 +624,20 @@ export class WindowManager extends InvisiblePlugin<WindowMangerAttributes> imple
579
624
  /**
580
625
  * 设置 ViewMode
581
626
  */
582
- public setViewMode(mode: ViewMode): void {
627
+ public setViewMode(mode: ManagerViewMode): void {
628
+ log("setViewMode", mode);
629
+ const mainViewProxy = this.appManager?.mainViewProxy;
583
630
  if (mode === ViewMode.Broadcaster) {
584
631
  if (this.canOperate) {
585
- this.appManager?.mainViewProxy.setCameraAndSize();
632
+ mainViewProxy?.storeCurrentCamera();
633
+ mainViewProxy?.storeCurrentSize();
586
634
  }
587
- this.appManager?.mainViewProxy.start();
635
+ mainViewProxy?.start();
588
636
  }
589
- if (mode === ViewMode.Freedom) {
590
- this.appManager?.mainViewProxy.stop();
637
+ if (mode === ViewMode.Freedom || mode === "scroll") {
638
+ mainViewProxy?.stop();
591
639
  }
592
- this.viewMode = mode;
640
+ this.viewMode$.setValue(mode);
593
641
  }
594
642
 
595
643
  public setBoxState(boxState: TeleBoxState): void {
@@ -637,6 +685,22 @@ export class WindowManager extends InvisiblePlugin<WindowMangerAttributes> imple
637
685
  }
638
686
  }
639
687
 
688
+ public get baseCamera() {
689
+ if (this.appManager) {
690
+ return this.appManager.mainViewProxy.camera$.value;
691
+ } else {
692
+ throw new Errors.AppManagerNotInitError();
693
+ }
694
+ }
695
+
696
+ public get baseSize() {
697
+ if (this.appManager) {
698
+ return this.appManager.mainViewProxy.size$.value;
699
+ } else {
700
+ throw new Errors.AppManagerNotInitError();
701
+ }
702
+ }
703
+
640
704
  public get cameraState(): CameraState {
641
705
  if (this.appManager) {
642
706
  return this.appManager.mainViewProxy.cameraState;
@@ -661,6 +725,10 @@ export class WindowManager extends InvisiblePlugin<WindowMangerAttributes> imple
661
725
  return Boolean(this.appManager?.boxManager?.darkMode);
662
726
  }
663
727
 
728
+ public get viewMode() {
729
+ return this.viewMode$.value;
730
+ }
731
+
664
732
  public get prefersColorScheme(): TeleBoxColorScheme | undefined {
665
733
  if (this.appManager) {
666
734
  return this.appManager.boxManager?.prefersColorScheme;
@@ -669,6 +737,14 @@ export class WindowManager extends InvisiblePlugin<WindowMangerAttributes> imple
669
737
  }
670
738
  }
671
739
 
740
+ public get fullscreen(): TeleBoxFullscreen | undefined {
741
+ if (this.appManager) {
742
+ return this.appManager.boxManager?.teleBoxManager.fullscreen;
743
+ } else {
744
+ throw new Errors.AppManagerNotInitError();
745
+ }
746
+ }
747
+
672
748
  public get focused(): string | undefined {
673
749
  return this.attributes.focus;
674
750
  }
@@ -722,6 +798,17 @@ export class WindowManager extends InvisiblePlugin<WindowMangerAttributes> imple
722
798
  }
723
799
  }
724
800
 
801
+ public get scrollState(): ScrollState | undefined {
802
+ return this.appManager?.scrollMode?.scrollState$.value;
803
+ }
804
+
805
+ public get teleboxManager(): TeleBoxManager {
806
+ if (!this.boxManager) {
807
+ throw new Errors.BoxManagerNotInitializeError();
808
+ }
809
+ return this.boxManager.teleBoxManager;
810
+ }
811
+
725
812
  /**
726
813
  * 查询所有的 App
727
814
  */
@@ -743,18 +830,14 @@ export class WindowManager extends InvisiblePlugin<WindowMangerAttributes> imple
743
830
  return this.appManager?.closeApp(appId);
744
831
  }
745
832
 
746
- public moveCamera(
747
- camera: Partial<Camera> & { animationMode?: AnimationMode | undefined }
748
- ): void {
833
+ public moveCamera = (camera: Partial<Camera> & { animationMode?: AnimationMode } ): void => {
749
834
  const pureCamera = omit(camera, ["animationMode"]);
750
835
  const mainViewCamera = { ...this.mainView.camera };
751
836
  if (isEqual({ ...mainViewCamera, ...pureCamera }, mainViewCamera)) return;
837
+ this.debouncedStoreCamera();
752
838
  this.mainView.moveCamera(camera);
753
839
  this.appManager?.dispatchInternalEvent(Events.MoveCamera, camera);
754
- setTimeout(() => {
755
- this.appManager?.mainViewProxy.setCameraAndSize();
756
- }, 500);
757
- }
840
+ };
758
841
 
759
842
  public moveCameraToContain(
760
843
  rectangle: Rectangle &
@@ -762,11 +845,18 @@ export class WindowManager extends InvisiblePlugin<WindowMangerAttributes> imple
762
845
  animationMode?: AnimationMode;
763
846
  }>
764
847
  ): void {
848
+ this.debouncedStoreCamera();
765
849
  this.mainView.moveCameraToContain(rectangle);
766
850
  this.appManager?.dispatchInternalEvent(Events.MoveCameraToContain, rectangle);
767
- setTimeout(() => {
768
- this.appManager?.mainViewProxy.setCameraAndSize();
769
- }, 500);
851
+ }
852
+
853
+ private debouncedStoreCamera = () => {
854
+ const storeCamera = debounce(() => {
855
+ this.appManager?.mainViewProxy.storeCurrentCamera();
856
+ this.appManager?.mainViewProxy.storeCurrentSize();
857
+ this.mainView.callbacks.off("onCameraUpdated", storeCamera);
858
+ }, 200);
859
+ this.mainView.callbacks.on("onCameraUpdated", storeCamera);
770
860
  }
771
861
 
772
862
  public convertToPointInWorld(point: Point): Point {
@@ -835,6 +925,10 @@ export class WindowManager extends InvisiblePlugin<WindowMangerAttributes> imple
835
925
  this.appManager?.boxManager?.setPrefersColorScheme(scheme);
836
926
  }
837
927
 
928
+ public setFullscreen(fullscreen: TeleBoxFullscreen): void {
929
+ this.appManager?.boxManager?.teleBoxManager.setFullscreen(fullscreen);
930
+ }
931
+
838
932
  public cleanCurrentScene(): void {
839
933
  this.focusedView?.cleanCurrentScene();
840
934
  }
@@ -894,7 +988,7 @@ export class WindowManager extends InvisiblePlugin<WindowMangerAttributes> imple
894
988
  if (WindowManager.container) {
895
989
  this.bindContainer(WindowManager.container);
896
990
  }
897
- this.appManager?.refresher?.refresh();
991
+ this.appManager?.refresher.refresh();
898
992
  }
899
993
 
900
994
  public setContainerSizeRatio(ratio: number) {
@@ -906,6 +1000,55 @@ export class WindowManager extends InvisiblePlugin<WindowMangerAttributes> imple
906
1000
  emitter.emit("containerSizeRatioUpdate", ratio);
907
1001
  }
908
1002
 
1003
+ public setContainerStyle(style: string) {
1004
+ this.boxManager?.teleBoxManager.setContainerStyle(style);
1005
+ }
1006
+
1007
+ public setStageStyle(style: string) {
1008
+ this.boxManager?.teleBoxManager.setStageStyle(style);
1009
+ }
1010
+
1011
+ public setBaseSize(size: Size) {
1012
+ this.appManager?.mainViewProxy.setMainViewSize(size);
1013
+ setTimeout(() => {
1014
+ if (!this.appManager || !this.appManager.mainViewProxy.camera$.value) return;
1015
+ this.appManager.mainViewProxy.storeCamera({
1016
+ ...this.appManager.mainViewProxy.camera$.value,
1017
+ id: this.appManager.uid,
1018
+ scale: 1
1019
+ });
1020
+ }, 500);
1021
+ }
1022
+ /**
1023
+ * 切换 focus 到指定的 app, 并且把这个 app 放到最前面
1024
+ */
1025
+ public focusApp(appId: string) {
1026
+ const box = this.boxManager?.getBox(appId);
1027
+ if (box) {
1028
+ this.boxManager?.focusBox({ appId }, false);
1029
+ // 1.0 版本这里会有正式的 api
1030
+ (this.boxManager?.teleBoxManager as any).makeBoxTop(box, false);
1031
+ }
1032
+ }
1033
+
1034
+ public createPPTHandler() {
1035
+ return {
1036
+ onPageJumpTo: (_pptUUID: string, index: number) => {
1037
+ this.appManager?.focusApp?.appContext?.whiteBoardView?.jumpPage(index);
1038
+ },
1039
+ onPageToNext: () => {
1040
+ if (this.focused) {
1041
+ this.appManager?.focusApp?.appContext?.whiteBoardView?.nextPage();
1042
+ }
1043
+ },
1044
+ onPageToPrev: () => {
1045
+ if (this.focused) {
1046
+ this.appManager?.focusApp?.appContext?.whiteBoardView?.prevPage();
1047
+ }
1048
+ }
1049
+ }
1050
+ }
1051
+
909
1052
  private isDynamicPPT(scenes: SceneDefinition[]) {
910
1053
  const sceneSrc = scenes[0]?.ppt?.src;
911
1054
  return sceneSrc?.startsWith("pptx://");
@@ -939,5 +1082,6 @@ setupBuiltin();
939
1082
 
940
1083
  export * from "./typings";
941
1084
 
942
- export { BuiltinApps } from "./BuiltinApps";
1085
+ export { BuiltinApps, BuiltinAppsMap } from "./BuiltinApps";
943
1086
  export type { PublicEvent } from "./callback";
1087
+ export type { Member } from "./Helper";
package/src/storage.ts ADDED
@@ -0,0 +1,15 @@
1
+ import { Storage } from "@netless/synced-store";
2
+ import { Val } from "value-enhancer";
3
+ import type { AppManager } from "./AppManager";
4
+
5
+ export type ScrollStorageState = { scrollTop: number }
6
+ export type ScrollStorage = Storage<ScrollStorageState>;
7
+
8
+ export const createScrollStorage = (manager: AppManager) => {
9
+ return new Storage<ScrollStorageState>({
10
+ plugin$: new Val(manager.windowManger),
11
+ isWritable$: manager.isWritable$,
12
+ namespace: "scrollStorage",
13
+ defaultState: { scrollTop: 0 }
14
+ });
15
+ };
package/src/style.css CHANGED
@@ -7,48 +7,9 @@
7
7
  user-select: none;
8
8
  }
9
9
 
10
- .netless-window-manager-sizer {
11
- position: absolute;
12
- top: 0;
13
- left: 0;
14
- width: 100%;
15
- height: 100%;
16
- z-index: 1;
17
- overflow: hidden;
18
- display: flex;
19
- }
20
-
21
- .netless-window-manager-sizer-horizontal {
22
- flex-direction: column;
23
- }
24
-
25
- .netless-window-manager-sizer::before,
26
- .netless-window-manager-sizer::after {
27
- flex: 1;
28
- content: "";
29
- display: block;
30
- }
31
-
32
- .netless-window-manager-chess-sizer::before,
33
- .netless-window-manager-chess-sizer::after {
34
- background-image: linear-gradient(45deg, #b0b0b0 25%, transparent 25%),
35
- linear-gradient(-45deg, #b0b0b0 25%, transparent 25%),
36
- linear-gradient(45deg, transparent 75%, #b0b0b0 75%),
37
- linear-gradient(-45deg, transparent 75%, #b0b0b0 75%);
38
- background-color: #fff;
39
- background-size: 20px 20px;
40
- background-position: 0 0, 0 10px, 10px -10px, -10px 0px;
41
- }
42
-
43
- .netless-window-manager-wrapper {
44
- position: relative;
45
- z-index: 1;
46
- width: 100%;
47
- height: 100%;
48
- overflow: hidden;
49
- }
50
10
 
51
11
  .netless-window-manager-main-view {
12
+ position: absolute;
52
13
  width: 100%;
53
14
  height: 100%;
54
15
  }
@@ -122,7 +83,7 @@
122
83
  left: 0;
123
84
  top: 0;
124
85
  will-change: transform;
125
- transition: transform 0.1s;
86
+ transition: transform 0.12s;
126
87
  transform-origin: 0 0;
127
88
  user-select: none;
128
89
  }
@@ -158,6 +119,20 @@
158
119
  margin-top: 3px;
159
120
  }
160
121
 
122
+ .netless-window-manager-cursor-pencilEraser-image {
123
+ margin-left: -22px;
124
+ margin-top: 3px;
125
+ }
126
+
127
+ .netless-window-manager-laserPointer-pencilEraser-offset {
128
+ margin-left: -18px;
129
+ }
130
+
131
+ .netless-window-manager-pencilEraser-3-offset {
132
+ margin-top: -14px;
133
+ margin-left: -6px;
134
+ }
135
+
161
136
  .netless-window-manager-cursor-name {
162
137
  width: 100%;
163
138
  height: 48px;
@@ -180,10 +155,6 @@
180
155
  }
181
156
 
182
157
  .window-manager-view-wrapper {
183
- z-index: 5000;
184
- width: 100%;
185
- height: 100%;
186
158
  position: absolute;
187
- left: 0;
188
- top: 0;
189
- }
159
+ z-index: 10;
160
+ }