@netless/window-manager 1.0.0-canary.7 → 1.0.0-canary.71

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 (112) hide show
  1. package/README.md +30 -6
  2. package/dist/index.js +13625 -0
  3. package/dist/index.mjs +13622 -0
  4. package/dist/index.umd.js +13620 -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} +12 -7
  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 +3 -1
  24. package/dist/{Page → src/Page}/index.d.ts +0 -0
  25. package/dist/{PageState.d.ts → src/PageState.d.ts} +1 -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 +4 -1
  36. package/dist/{Utils → src/Utils}/log.d.ts +0 -0
  37. package/dist/src/View/CameraSynchronizer.d.ts +21 -0
  38. package/dist/{View → src/View}/MainView.d.ts +25 -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} +12 -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} +63 -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} +21 -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/src/App/AppContext.ts +81 -46
  56. package/src/App/AppPageStateImpl.ts +3 -0
  57. package/src/App/AppProxy.ts +249 -141
  58. package/src/App/WhiteboardView.ts +37 -14
  59. package/src/App/index.ts +1 -0
  60. package/src/App/type.ts +22 -0
  61. package/src/AppListener.ts +27 -21
  62. package/src/AppManager.ts +96 -50
  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 +15 -4
  68. package/src/Cursor/icons.ts +6 -0
  69. package/src/Cursor/index.ts +16 -11
  70. package/src/Helper.ts +25 -7
  71. package/src/InternalEmitter.ts +1 -4
  72. package/src/Page/PageController.ts +3 -1
  73. package/src/PageState.ts +8 -1
  74. package/src/ReconnectRefresher.ts +7 -3
  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 +6 -2
  82. package/src/View/CameraSynchronizer.ts +55 -36
  83. package/src/View/MainView.ts +163 -77
  84. package/src/View/ScrollMode.ts +240 -0
  85. package/src/View/ViewSync.ts +138 -6
  86. package/src/callback.ts +8 -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 +197 -60
  92. package/src/storage.ts +15 -0
  93. package/src/style.css +18 -47
  94. package/src/typings.ts +24 -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 -16161
  107. package/pnpm-lock.yaml +0 -6302
  108. package/src/App/AppViewSync.ts +0 -68
  109. package/src/App/Storage/StorageEvent.ts +0 -21
  110. package/src/App/Storage/index.ts +0 -295
  111. package/src/App/Storage/typings.ts +0 -23
  112. package/src/App/Storage/utils.ts +0 -17
@@ -59,6 +59,9 @@ export class AppPageStateImpl {
59
59
  return {
60
60
  index: this.view?.focusSceneIndex || 0,
61
61
  length: this.sceneNode?.scenes.length || 0,
62
+ pages: this.sceneNode?.scenes.map(name => {
63
+ return `${this.scenePath}/${name}`;
64
+ }) || [],
62
65
  };
63
66
  }
64
67
 
@@ -3,13 +3,13 @@ import { AppAttributes, AppEvents, Events, SETUP_APP_DELAY } from "../constants"
3
3
  import { AppContext } from "./AppContext";
4
4
  import { AppPageStateImpl } from "./AppPageStateImpl";
5
5
  import { appRegister } from "../Register";
6
- import { AppViewSync } from "./AppViewSync";
6
+ import { ViewSync } from "../View/ViewSync"
7
7
  import { autorun, reaction, toJS } from "white-web-sdk";
8
8
  import { boxEmitter } from "../BoxEmitter";
9
- import { BoxManagerNotFoundError } from "../Utils/error";
9
+ import { BoxManagerNotInitializeError } from "../Utils/error";
10
10
  import { calculateNextIndex } from "../Page";
11
- import { combine, Val } from "value-enhancer";
12
- import { debounce, get } from "lodash";
11
+ import { combine, Val, ValManager } from "value-enhancer";
12
+ import { debounce, get, isEqual, isUndefined, omitBy } from "lodash";
13
13
  import { emitter } from "../InternalEmitter";
14
14
  import { Fields } from "../AttributesDelegate";
15
15
  import { log } from "../Utils/log";
@@ -25,16 +25,17 @@ import {
25
25
  } from "../Utils/Common";
26
26
  import type {
27
27
  AppEmitterEvent,
28
- AppInitState,
29
28
  BaseInsertParams,
30
29
  setAppOptions,
31
30
  AppListenerKeys,
32
31
  } from "../index";
33
- import type { SceneState, View, SceneDefinition, Camera } from "white-web-sdk";
32
+ import type { SceneState, View, SceneDefinition, MemberState} from "white-web-sdk";
34
33
  import type { AppManager } from "../AppManager";
35
34
  import type { NetlessApp } from "../typings";
36
- import type { ReadonlyTeleBox } from "@netless/telebox-insider";
35
+ import type { ReadonlyTeleBox, TeleBox, TeleBoxRect } from "@netless/telebox-insider";
37
36
  import type { PageRemoveService, PageState } from "../Page";
37
+ import type { AppState } from "./type";
38
+ import { callbacks } from "../callback";
38
39
 
39
40
  export type AppEmitter = Emittery<AppEmitterEvent>;
40
41
 
@@ -54,23 +55,25 @@ export class AppProxy implements PageRemoveService {
54
55
  public uid = this.manager.uid;
55
56
 
56
57
  public isAddApp: boolean;
57
- private status: "normal" | "destroyed" = "normal";
58
+ public status: "normal" | "destroyed" = "normal";
58
59
  private stateKey: string;
59
60
  public _pageState: AppPageStateImpl;
60
- private _prevFullPath: string | undefined;
61
61
 
62
- public appResult?: NetlessApp<any>;
63
- public appContext?: AppContext<any, any>;
62
+ public appResult?: NetlessApp;
63
+ public appContext?: AppContext;
64
64
 
65
- private sideEffectManager = new SideEffectManager();
65
+ public sideEffectManager = new SideEffectManager();
66
+ private valManager = new ValManager();
66
67
 
67
- public camera$ = new Val<ICamera | undefined>(undefined);
68
- public size$ = new Val<ISize | undefined>(undefined);
68
+ private fullPath$ = this.valManager.attach(new Val<string | undefined>(undefined));
69
+ private viewSync?: ViewSync;
69
70
 
70
- private appViewSync?: AppViewSync;
71
-
72
- public box$ = new Val<ReadonlyTeleBox | undefined>(undefined);
73
- public view$ = new Val<View | undefined>(undefined);
71
+ public camera$ = this.valManager.attach(new Val<ICamera | undefined>(undefined));
72
+ public size$ = this.valManager.attach(new Val<ISize | undefined>(undefined));
73
+ public box$ = this.valManager.attach(new Val<ReadonlyTeleBox | undefined>(undefined));
74
+ public view$ = this.valManager.attach(new Val<View | undefined>(undefined));
75
+ public syncCamera$ = this.valManager.attach(new Val<boolean>(true));
76
+ public whiteBoardViewCreated$ = this.valManager.attach(new Val<boolean>(false));
74
77
 
75
78
  constructor(
76
79
  private params: BaseInsertParams,
@@ -103,70 +106,107 @@ export class AppProxy implements PageRemoveService {
103
106
  notifyPageStateChange: this.notifyPageStateChange,
104
107
  });
105
108
  this.sideEffectManager.add(() => () => this._pageState.destroy());
106
- this.sideEffectManager.add(() =>
107
- emitter.on("roomMembersChange", members => {
108
- this.appEmitter.emit("roomMembersChange", members);
109
- })
110
- );
111
109
  this.camera$.setValue(toJS(this.appAttributes.camera));
112
110
  this.size$.setValue(toJS(this.appAttributes.size));
113
- this.sideEffectManager.add(() => {
114
- return this.manager.refresher.add(`${this.id}-camera`, () => {
115
- return reaction(
116
- () => this.appAttributes?.camera,
117
- camera => {
118
- if (camera && camera.id !== this.uid) {
119
- this.camera$.setValue(toJS(camera));
120
- }
121
- }
122
- );
123
- });
124
- });
125
- this.sideEffectManager.add(() => {
126
- return this.manager.refresher.add(`${this.id}-size`, () => {
127
- return reaction(
128
- () => this.appAttributes?.size,
129
- size => {
130
- if (size && size.id !== this.uid) {
131
- this.size$.setValue(toJS(size));
132
- }
111
+ this.addCameraReaction();
112
+ this.addSizeReaction();
113
+ this.sideEffectManager.add(() =>
114
+ emitter.on("memberStateChange", this.onMemberStateChange)
115
+ );
116
+ this.sideEffectManager.add(() => [
117
+ this.syncCamera$.subscribe(syncCamera => {
118
+ if (!syncCamera) {
119
+ if (this.viewSync) {
120
+ this.viewSync.destroy();
121
+ this.viewSync = undefined;
122
+ this.sideEffectManager.flush("camera");
123
+ this.sideEffectManager.flush("size");
133
124
  }
134
- );
135
- });
136
- });
137
- combine([this.box$, this.view$]).subscribe(([box, view]) => {
138
- if (box && view) {
139
- if (!this.camera$.value) {
140
- this.storeCamera({
141
- centerX: 0, centerY: 0, scale: 1, id: this.uid,
142
- });
143
- this.camera$.setValue(toJS(this.appAttributes.camera));
144
125
  }
145
- if (!this.size$.value && box.contentStageRect) {
146
- this.storeSize({
147
- id: this.uid,
148
- width: box.contentStageRect?.width,
149
- height: box.contentStageRect?.height,
150
- });
151
- this.size$.setValue(toJS(this.appAttributes.size));
126
+ }),
127
+ this.whiteBoardViewCreated$.reaction(created => {
128
+ if (created && this.box) {
129
+ if (!this.syncCamera$.value) return;
130
+ combine([this.box$, this.view$]).subscribe(([box, view]) => {
131
+ if (box && view) {
132
+ if (!this.camera$.value) {
133
+ this.storeCamera({
134
+ centerX: null,
135
+ centerY: null,
136
+ scale: 1,
137
+ id: this.uid,
138
+ });
139
+ this.camera$.setValue(toJS(this.appAttributes.camera));
140
+ }
141
+ if (!this.size$.value && box.stageRect) {
142
+ const initialRect = this.computedInitialRect(box.stageRect);
143
+ const width = initialRect?.width || box.stageRect.width;
144
+ const height = initialRect?.height || box.stageRect.height;
145
+ this.storeSize({
146
+ id: this.uid,
147
+ width,
148
+ height,
149
+ });
150
+ this.size$.setValue(toJS(this.appAttributes.size));
151
+ }
152
+ this.viewSync = new ViewSync({
153
+ uid: this.uid,
154
+ view$: this.view$,
155
+ camera$: this.camera$,
156
+ size$: this.size$,
157
+ stageRect$: box._stageRect$,
158
+ storeCamera: this.storeCamera,
159
+ storeSize: this.storeSize
160
+ });
161
+ this.sideEffectManager.add(() => () => this.viewSync?.destroy());
162
+ this.whiteBoardViewCreated$.destroy();
163
+ }
164
+ })
152
165
  }
153
- this.appViewSync = new AppViewSync(this);
154
- this.sideEffectManager.add(() => () => this.appViewSync?.destroy());
166
+ }),
167
+ this.manager.members$.reaction(members => {
168
+ this.appEmitter.emit("roomMembersChange", members);
169
+ }),
170
+ ]);
171
+ }
172
+
173
+ public fireMemberStateChange = () => {
174
+ if (this.manager.room) {
175
+ this.onMemberStateChange(this.manager.room.state.memberState);
176
+ }
177
+ }
178
+
179
+ private onMemberStateChange = (memberState: MemberState) => {
180
+ // clicker 教具把事件穿透给下层
181
+ const needPointerEventsNone = memberState.currentApplianceName === "clicker";
182
+ if (needPointerEventsNone) {
183
+ if (this.appContext?._viewWrapper) {
184
+ this.appContext._viewWrapper.style.pointerEvents = "none";
155
185
  }
156
- });
157
- this.sideEffectManager.add(() => emitter.on("memberStateChange", memberState => {
158
- // clicker 教具把事件穿透给下层
159
- const needPointerEventsNone = memberState.currentApplianceName === "clicker";
160
- if (needPointerEventsNone) {
161
- if (this.appContext?._viewWrapper) {
162
- this.appContext._viewWrapper.style.pointerEvents = "none";
163
- }
186
+ } else {
187
+ if (this.appContext?._viewWrapper) {
188
+ this.appContext._viewWrapper.style.pointerEvents = "auto";
189
+ }
190
+ }
191
+ }
192
+
193
+ private computedInitialRect = (boxRect: TeleBoxRect) => {
194
+ const managerRect = this.manager.boxManager?.stageRect;
195
+ if (managerRect) {
196
+ const { width, height } = managerRect;
197
+ const boxRatio = boxRect.height / boxRect.width;
198
+ if (height < 480) {
199
+ return {
200
+ width: 480 / boxRatio,
201
+ height: 480,
202
+ };
164
203
  } else {
165
- if (this.appContext?._viewWrapper) {
166
- this.appContext._viewWrapper.style.pointerEvents = "auto";
167
- }
204
+ return {
205
+ width: width * 0.65,
206
+ height: height * 0.65,
207
+ };
168
208
  }
169
- }));
209
+ }
170
210
  }
171
211
 
172
212
  public createAppDir() {
@@ -196,7 +236,7 @@ export class AppProxy implements PageRemoveService {
196
236
  }
197
237
 
198
238
  public get view(): View | undefined {
199
- return this.manager.viewManager.getView(this.id);
239
+ return this.view$.value;
200
240
  }
201
241
 
202
242
  public get viewIndex(): number | undefined {
@@ -272,13 +312,13 @@ export class AppProxy implements PageRemoveService {
272
312
  ) {
273
313
  log("setupApp", appId, app, options);
274
314
  if (!this.boxManager) {
275
- throw new BoxManagerNotFoundError();
315
+ throw new BoxManagerNotInitializeError();
276
316
  }
277
- const context = new AppContext(this.manager, this.boxManager, appId, this, appOptions);
317
+ const context = new AppContext(this.manager, appId, this, appOptions);
278
318
  this.appContext = context;
279
319
  try {
280
320
  emitter.once(`${appId}${Events.WindowCreated}` as any).then(async () => {
281
- let boxInitState: AppInitState | undefined;
321
+ let boxInitState: AppState | undefined;
282
322
  if (!skipUpdate) {
283
323
  boxInitState = this.getAppInitState(appId);
284
324
  this.boxManager?.updateBoxState(boxInitState);
@@ -288,10 +328,19 @@ export class AppProxy implements PageRemoveService {
288
328
  this.setViewFocusScenePath();
289
329
  setTimeout(async () => {
290
330
  // 延迟执行 setup, 防止初始化的属性没有更新成功
291
- const result = await app.setup(context);
292
- this.appResult = result;
293
- appRegister.notifyApp(this.kind, "created", { appId, result });
294
- this.fixMobileSize();
331
+ try {
332
+ const result = await app.setup(context);
333
+ this.appResult = result;
334
+ appRegister.notifyApp(this.kind, "created", { appId, result });
335
+ this.fixMobileSize();
336
+ if (this.isAddApp) {
337
+ this.setupDone();
338
+ }
339
+ } catch (error) {
340
+ console.error(error);
341
+ this.setupFailed();
342
+ this.destroy(false, true, true);
343
+ }
295
344
  }, SETUP_APP_DELAY);
296
345
  });
297
346
  const box = this.boxManager?.createBox({
@@ -300,11 +349,18 @@ export class AppProxy implements PageRemoveService {
300
349
  options,
301
350
  canOperate: this.manager.canOperate,
302
351
  smartPosition: this.isAddApp,
303
- });
352
+ }) as TeleBox;
353
+ const registerParams = appRegister.registered.get(this.kind);
354
+ if (registerParams?.contentStyles) {
355
+ box?.mountUserStyles(registerParams.contentStyles);
356
+ }
304
357
  this.box$.setValue(box);
305
358
  if (this.isAddApp && this.box) {
306
359
  this.store.updateAppState(appId, AppAttributes.ZIndex, this.box.zIndex);
307
- this.boxManager.focusBox({ appId }, false);
360
+ this.store.updateAppState(appId, AppAttributes.Size, {
361
+ width: this.box.intrinsicWidth,
362
+ height: this.box.intrinsicHeight,
363
+ });
308
364
  }
309
365
  } catch (error: any) {
310
366
  console.error(error);
@@ -316,12 +372,14 @@ export class AppProxy implements PageRemoveService {
316
372
  private fixMobileSize() {
317
373
  const box = this.boxManager?.getBox(this.id);
318
374
  if (box) {
319
- this.boxManager?.resizeBox({
320
- appId: this.id,
321
- width: box.intrinsicWidth + 0.001,
322
- height: box.intrinsicHeight + 0.001,
323
- skipUpdate: true,
324
- });
375
+ if (!box.minimized) {
376
+ this.boxManager?.resizeBox({
377
+ appId: this.id,
378
+ width: box.intrinsicWidth + 0.001,
379
+ height: box.intrinsicHeight + 0.001,
380
+ skipUpdate: true,
381
+ });
382
+ }
325
383
  }
326
384
  }
327
385
 
@@ -366,30 +424,18 @@ export class AppProxy implements PageRemoveService {
366
424
  }
367
425
  }
368
426
 
369
- public getAppInitState = (id: string) => {
427
+ public getAppInitState = (id: string): AppState | undefined => {
370
428
  const attrs = this.store.getAppState(id);
371
429
  if (!attrs) return;
372
- const position = attrs?.[AppAttributes.Position];
373
430
  const focus = this.store.focus;
374
- const size = attrs?.[AppAttributes.Size];
375
- const sceneIndex = attrs?.[AppAttributes.SceneIndex];
376
431
  const maximized = this.attributes?.["maximized"];
377
432
  const minimized = this.attributes?.["minimized"];
378
- const zIndex = attrs?.zIndex;
379
- let payload = { maximized, minimized, zIndex } as AppInitState;
380
- if (position) {
381
- payload = { ...payload, id: id, x: position.x, y: position.y };
382
- }
433
+ let payload = { maximized, minimized, id } as AppState;
434
+ const state = omitBy(attrs, isUndefined);
383
435
  if (focus === id) {
384
436
  payload = { ...payload, focus: true };
385
437
  }
386
- if (size) {
387
- payload = { ...payload, width: size.width, height: size.height };
388
- }
389
- if (sceneIndex) {
390
- payload = { ...payload, sceneIndex };
391
- }
392
- return payload;
438
+ return Object.assign(payload, state);;
393
439
  };
394
440
 
395
441
  public emitAppSceneStateChange(sceneState: SceneState) {
@@ -446,32 +492,34 @@ export class AppProxy implements PageRemoveService {
446
492
  }
447
493
 
448
494
  private appAttributesUpdateListener = (appId: string) => {
449
- this.manager.refresher?.add(appId, () => {
450
- return autorun(() => {
451
- const attrs = this.manager.attributes[appId];
452
- if (attrs) {
453
- this.appEmitter.emit("attributesUpdate", attrs);
454
- }
455
- });
456
- });
457
- this.manager.refresher?.add(this.stateKey, () => {
458
- return autorun(() => {
459
- const appState = this.appAttributes?.state;
460
- if (appState?.zIndex > 0 && appState.zIndex !== this.box?.zIndex) {
461
- this.boxManager?.setZIndex(appId, appState.zIndex);
462
- }
463
- });
464
- });
465
- this.manager.refresher?.add(`${appId}-fullPath`, () => {
466
- return autorun(() => {
467
- const fullPath = this.appAttributes?.fullPath;
468
- this.setFocusScenePathHandler(fullPath);
469
- if (this._prevFullPath !== fullPath) {
470
- this.notifyPageStateChange();
471
- this._prevFullPath = fullPath;
472
- }
473
- });
474
- });
495
+ this.sideEffectManager.add(() => [
496
+ this.manager.refresher.add(appId, () => {
497
+ return autorun(() => {
498
+ const attrs = this.manager.attributes[appId];
499
+ if (attrs) {
500
+ this.appEmitter.emit("attributesUpdate", attrs);
501
+ }
502
+ });
503
+ }),
504
+ this.manager.refresher.add(this.stateKey, () => {
505
+ return autorun(() => {
506
+ const appState = this.appAttributes?.state;
507
+ if (appState?.zIndex > 0 && appState.zIndex !== this.box?.zIndex) {
508
+ this.boxManager?.setZIndex(appId, appState.zIndex);
509
+ }
510
+ });
511
+ }),
512
+ this.manager.refresher.add(`${appId}-fullPath`, () => {
513
+ return autorun(() => {
514
+ const fullPath = this.appAttributes?.fullPath;
515
+ this.setFocusScenePathHandler(fullPath);
516
+ if (this.fullPath$.value !== fullPath) {
517
+ this.notifyPageStateChange();
518
+ this.fullPath$.setValue(fullPath);
519
+ }
520
+ });
521
+ }),
522
+ ]);
475
523
  };
476
524
 
477
525
  private setFocusScenePathHandler = debounce((fullPath: string | undefined) => {
@@ -489,6 +537,7 @@ export class AppProxy implements PageRemoveService {
489
537
  }
490
538
 
491
539
  public setViewFocusScenePath() {
540
+ if (this.status === "destroyed") return;
492
541
  const fullPath = this.getFullScenePath();
493
542
  if (fullPath && this.view) {
494
543
  setViewFocusScenePath(this.view, fullPath);
@@ -548,6 +597,7 @@ export class AppProxy implements PageRemoveService {
548
597
  const fullPath = this._pageState.getFullPath(index);
549
598
  if (fullPath) {
550
599
  this.setFullPath(fullPath);
600
+ setScenePath(this.manager.room, fullPath);
551
601
  }
552
602
  }
553
603
  }
@@ -560,12 +610,22 @@ export class AppProxy implements PageRemoveService {
560
610
  this.store.updateAppAttributes(this.id, Fields.Size, size);
561
611
  };
562
612
 
563
- public moveCamera = (camera: Camera) => {
613
+ public updateSize = (width: number, height: number) => {
614
+ const iSize = {
615
+ id: this.manager.uid,
616
+ width, height
617
+ }
618
+ this.store.updateAppAttributes(this.id, Fields.Size, iSize);
619
+ this.size$.setValue(iSize);
620
+ }
621
+
622
+ public moveCamera = (camera: Partial<ICamera>) => {
564
623
  if (!this.camera$.value) {
565
624
  return;
566
625
  }
567
- const nextCamera = { ...this.camera$.value, ...camera };
626
+ const nextCamera = { ...this.camera$.value, ...camera, id: this.uid };
568
627
  this.storeCamera(nextCamera);
628
+ this.camera$.setValue(nextCamera);
569
629
  };
570
630
 
571
631
  public async destroy(
@@ -578,6 +638,7 @@ export class AppProxy implements PageRemoveService {
578
638
  this.status = "destroyed";
579
639
  try {
580
640
  await appRegister.notifyApp(this.kind, "destroy", { appId: this.id });
641
+ callbacks.emit("appClose", { appId: this.id, kind: this.kind, error });
581
642
  await this.appEmitter.emit("destroy", { error });
582
643
  } catch (error) {
583
644
  console.error("[WindowManager]: notifyApp error", error.message, error.stack);
@@ -598,13 +659,60 @@ export class AppProxy implements PageRemoveService {
598
659
 
599
660
  this.viewManager.destroyView(this.id);
600
661
  this.manager.appStatus.delete(this.id);
601
- this.manager.refresher?.remove(this.id);
602
- this.manager.refresher?.remove(this.stateKey);
603
- this.manager.refresher?.remove(`${this.id}-fullPath`);
604
- this._prevFullPath = undefined;
605
- this.camera$.destroy();
606
- this.size$.destroy();
607
- this.box$.destroy();
662
+ this.valManager.destroy();
663
+ }
664
+
665
+ private addCameraReaction = () => {
666
+ this.sideEffectManager.add(() =>
667
+ this.manager.refresher.add(`${this.id}-camera`, () =>
668
+ reaction(
669
+ () => this.appAttributes?.camera,
670
+ camera => {
671
+ if (camera) {
672
+ const rawCamera = toJS(camera);
673
+ if (!isEqual(rawCamera, this.camera$.value)) {
674
+ this.camera$.setValue(rawCamera);
675
+ }
676
+ }
677
+ }
678
+ )
679
+ )
680
+ , "camera");
681
+ }
682
+
683
+ private addSizeReaction = () => {
684
+ this.sideEffectManager.add(() =>
685
+ this.manager.refresher.add(`${this.id}-size`, () =>
686
+ reaction(
687
+ () => this.appAttributes?.size,
688
+ size => {
689
+ if (size) {
690
+ const rawSize = toJS(size);
691
+ if (!isEqual(rawSize, this.size$.value)) {
692
+ this.size$.setValue(rawSize);
693
+ }
694
+ }
695
+ }
696
+ )
697
+ )
698
+ , "size");
699
+ }
700
+
701
+ public onFocus = () => {
702
+ this.setScenePath();
703
+ }
704
+
705
+ // 异步值设置完成通知其他端创建 app
706
+ private setupDone = () => {
707
+ this.store.updateAppAttributes(this.id, "setup", true);
708
+ this.manager.dispatchInternalEvent(Events.InvokeAttributesUpdateCallback);
709
+ if (this.boxManager && this.box) {
710
+ this.boxManager.focusBox({ appId: this.id }, false);
711
+ }
712
+ }
713
+
714
+ private setupFailed = () => {
715
+ this.store.cleanAppAttributes(this.id);
608
716
  }
609
717
 
610
718
  public close(): Promise<void> {
@@ -1,36 +1,58 @@
1
1
  import { putScenes } from "../Utils/Common";
2
2
  import { Val } from "value-enhancer";
3
+ import { pick } from "lodash";
3
4
 
4
5
  import type { ReadonlyVal } from "value-enhancer";
5
6
  import type { AddPageParams, PageController, PageState } from "../Page";
6
7
  import type { AppProxy } from "./AppProxy";
7
8
  import type { AppContext } from "./AppContext";
8
- import type { Camera } from "white-web-sdk";
9
+ import type { Camera, View } from "white-web-sdk";
10
+ import type { TeleBoxRect } from "@netless/telebox-insider";
11
+ import type { ICamera, ISize } from "../AttributesDelegate";
12
+
13
+ export type WhiteBoardViewCamera = Omit<ICamera, "id">;
14
+ export type WhiteBoardViewRect = Omit<ISize, "id">;
9
15
 
10
16
  export class WhiteBoardView implements PageController {
11
17
  public readonly pageState$: ReadonlyVal<PageState>;
18
+ public readonly camera$: ReadonlyVal<WhiteBoardViewCamera>;
19
+ public readonly baseRect$: ReadonlyVal<WhiteBoardViewRect | undefined>;
12
20
 
13
21
  constructor(
22
+ public view: View,
14
23
  protected appContext: AppContext,
15
24
  protected appProxy: AppProxy,
16
- private removeViewWrapper: () => void
25
+ public ensureSize: (size: number) => void
17
26
  ) {
18
27
  const pageState$ = new Val<PageState>(appProxy.pageState);
28
+ const baseRect$ = new Val<WhiteBoardViewRect | undefined>(appProxy.size$.value);
29
+ const pickCamera = (camera: Camera | ICamera) =>
30
+ pick(camera, ["centerX", "centerY", "scale"]);
31
+ const camera$ = new Val<WhiteBoardViewCamera>(pickCamera(this.view.camera));
32
+ this.baseRect$ = baseRect$;
19
33
  this.pageState$ = pageState$;
20
- appProxy.appEmitter.on("pageStateChange", pageState => {
21
- pageState$.setValue(pageState);
22
- });
23
- }
24
-
25
- public get view() {
26
- return this.appContext.view;
34
+ this.camera$ = camera$;
35
+ this.appProxy.sideEffectManager.add(() => [
36
+ appProxy.appEmitter.on("pageStateChange", pageState => pageState$.setValue(pageState)),
37
+ appProxy.camera$.subscribe(camera => {
38
+ if (camera) {
39
+ camera$.setValue(pickCamera(camera));
40
+ }
41
+ }),
42
+ appProxy.size$.subscribe(size => {
43
+ if (size) {
44
+ baseRect$.setValue(pick(size, ["width", "height"]));
45
+ }
46
+ }),
47
+ ]);
48
+ view.disableCameraTransform = true;
27
49
  }
28
50
 
29
51
  public get pageState() {
30
52
  return this.pageState$.value;
31
53
  }
32
54
 
33
- public moveCamera(camera: Camera) {
55
+ public moveCamera(camera: Partial<WhiteBoardViewCamera>) {
34
56
  this.appProxy.moveCamera(camera);
35
57
  }
36
58
 
@@ -58,11 +80,12 @@ export class WhiteBoardView implements PageController {
58
80
  const scene = params?.scene;
59
81
  const scenePath = this.appProxy.scenePath;
60
82
  if (!scenePath) return;
83
+ const scenes = Array.isArray(scene) ? scene : [scene || {}];
61
84
  if (after) {
62
85
  const nextIndex = this.pageState.index + 1;
63
- putScenes(this.appContext.room, scenePath, [scene || {}], nextIndex);
86
+ putScenes(this.appContext.room, scenePath, scenes, nextIndex);
64
87
  } else {
65
- putScenes(this.appContext.room, scenePath, [scene || {}]);
88
+ putScenes(this.appContext.room, scenePath, scenes);
66
89
  }
67
90
  };
68
91
 
@@ -79,7 +102,7 @@ export class WhiteBoardView implements PageController {
79
102
  return this.appProxy.removeSceneByIndex(needRemoveIndex);
80
103
  };
81
104
 
82
- public destroy() {
83
- this.removeViewWrapper();
105
+ public setBaseRect(rect: Omit<TeleBoxRect, "x" | "y">) {
106
+ this.appProxy.updateSize(rect.width, rect.height);
84
107
  }
85
108
  }
package/src/App/index.ts CHANGED
@@ -1,3 +1,4 @@
1
1
  export * from "./AppProxy";
2
2
  export * from "./AppContext";
3
3
  export * from "./WhiteboardView";
4
+ export * from "./type";