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

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
@@ -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,68 +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
125
  }
144
- if (!this.size$.value && box.contentStageRect) {
145
- this.storeSize({
146
- id: this.uid,
147
- width: box.contentStageRect?.width,
148
- height: box.contentStageRect?.height,
149
- });
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
+ })
150
165
  }
151
- this.appViewSync = new AppViewSync(this);
152
- 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";
153
185
  }
154
- });
155
- this.sideEffectManager.add(() => emitter.on("memberStateChange", memberState => {
156
- // clicker 教具把事件穿透给下层
157
- const needPointerEventsNone = memberState.currentApplianceName === "clicker";
158
- if (needPointerEventsNone) {
159
- if (this.appContext?._viewWrapper) {
160
- this.appContext._viewWrapper.style.pointerEvents = "none";
161
- }
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
+ };
162
203
  } else {
163
- if (this.appContext?._viewWrapper) {
164
- this.appContext._viewWrapper.style.pointerEvents = "auto";
165
- }
204
+ return {
205
+ width: width * 0.65,
206
+ height: height * 0.65,
207
+ };
166
208
  }
167
- }));
209
+ }
168
210
  }
169
211
 
170
212
  public createAppDir() {
@@ -194,7 +236,7 @@ export class AppProxy implements PageRemoveService {
194
236
  }
195
237
 
196
238
  public get view(): View | undefined {
197
- return this.manager.viewManager.getView(this.id);
239
+ return this.view$.value;
198
240
  }
199
241
 
200
242
  public get viewIndex(): number | undefined {
@@ -270,13 +312,13 @@ export class AppProxy implements PageRemoveService {
270
312
  ) {
271
313
  log("setupApp", appId, app, options);
272
314
  if (!this.boxManager) {
273
- throw new BoxManagerNotFoundError();
315
+ throw new BoxManagerNotInitializeError();
274
316
  }
275
- const context = new AppContext(this.manager, this.boxManager, appId, this, appOptions);
317
+ const context = new AppContext(this.manager, appId, this, appOptions);
276
318
  this.appContext = context;
277
319
  try {
278
320
  emitter.once(`${appId}${Events.WindowCreated}` as any).then(async () => {
279
- let boxInitState: AppInitState | undefined;
321
+ let boxInitState: AppState | undefined;
280
322
  if (!skipUpdate) {
281
323
  boxInitState = this.getAppInitState(appId);
282
324
  this.boxManager?.updateBoxState(boxInitState);
@@ -286,10 +328,19 @@ export class AppProxy implements PageRemoveService {
286
328
  this.setViewFocusScenePath();
287
329
  setTimeout(async () => {
288
330
  // 延迟执行 setup, 防止初始化的属性没有更新成功
289
- const result = await app.setup(context);
290
- this.appResult = result;
291
- appRegister.notifyApp(this.kind, "created", { appId, result });
292
- 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
+ }
293
344
  }, SETUP_APP_DELAY);
294
345
  });
295
346
  const box = this.boxManager?.createBox({
@@ -298,11 +349,18 @@ export class AppProxy implements PageRemoveService {
298
349
  options,
299
350
  canOperate: this.manager.canOperate,
300
351
  smartPosition: this.isAddApp,
301
- });
352
+ }) as TeleBox;
353
+ const registerParams = appRegister.registered.get(this.kind);
354
+ if (registerParams?.contentStyles) {
355
+ box?.mountUserStyles(registerParams.contentStyles);
356
+ }
302
357
  this.box$.setValue(box);
303
358
  if (this.isAddApp && this.box) {
304
359
  this.store.updateAppState(appId, AppAttributes.ZIndex, this.box.zIndex);
305
- this.boxManager.focusBox({ appId }, false);
360
+ this.store.updateAppState(appId, AppAttributes.Size, {
361
+ width: this.box.intrinsicWidth,
362
+ height: this.box.intrinsicHeight,
363
+ });
306
364
  }
307
365
  } catch (error: any) {
308
366
  console.error(error);
@@ -314,12 +372,14 @@ export class AppProxy implements PageRemoveService {
314
372
  private fixMobileSize() {
315
373
  const box = this.boxManager?.getBox(this.id);
316
374
  if (box) {
317
- this.boxManager?.resizeBox({
318
- appId: this.id,
319
- width: box.intrinsicWidth + 0.001,
320
- height: box.intrinsicHeight + 0.001,
321
- skipUpdate: true,
322
- });
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
+ }
323
383
  }
324
384
  }
325
385
 
@@ -364,30 +424,18 @@ export class AppProxy implements PageRemoveService {
364
424
  }
365
425
  }
366
426
 
367
- public getAppInitState = (id: string) => {
427
+ public getAppInitState = (id: string): AppState | undefined => {
368
428
  const attrs = this.store.getAppState(id);
369
429
  if (!attrs) return;
370
- const position = attrs?.[AppAttributes.Position];
371
430
  const focus = this.store.focus;
372
- const size = attrs?.[AppAttributes.Size];
373
- const sceneIndex = attrs?.[AppAttributes.SceneIndex];
374
431
  const maximized = this.attributes?.["maximized"];
375
432
  const minimized = this.attributes?.["minimized"];
376
- const zIndex = attrs?.zIndex;
377
- let payload = { maximized, minimized, zIndex } as AppInitState;
378
- if (position) {
379
- payload = { ...payload, id: id, x: position.x, y: position.y };
380
- }
433
+ let payload = { maximized, minimized, id } as AppState;
434
+ const state = omitBy(attrs, isUndefined);
381
435
  if (focus === id) {
382
436
  payload = { ...payload, focus: true };
383
437
  }
384
- if (size) {
385
- payload = { ...payload, width: size.width, height: size.height };
386
- }
387
- if (sceneIndex) {
388
- payload = { ...payload, sceneIndex };
389
- }
390
- return payload;
438
+ return Object.assign(payload, state);;
391
439
  };
392
440
 
393
441
  public emitAppSceneStateChange(sceneState: SceneState) {
@@ -444,32 +492,34 @@ export class AppProxy implements PageRemoveService {
444
492
  }
445
493
 
446
494
  private appAttributesUpdateListener = (appId: string) => {
447
- this.manager.refresher?.add(appId, () => {
448
- return autorun(() => {
449
- const attrs = this.manager.attributes[appId];
450
- if (attrs) {
451
- this.appEmitter.emit("attributesUpdate", attrs);
452
- }
453
- });
454
- });
455
- this.manager.refresher?.add(this.stateKey, () => {
456
- return autorun(() => {
457
- const appState = this.appAttributes?.state;
458
- if (appState?.zIndex > 0 && appState.zIndex !== this.box?.zIndex) {
459
- this.boxManager?.setZIndex(appId, appState.zIndex);
460
- }
461
- });
462
- });
463
- this.manager.refresher?.add(`${appId}-fullPath`, () => {
464
- return autorun(() => {
465
- const fullPath = this.appAttributes?.fullPath;
466
- this.setFocusScenePathHandler(fullPath);
467
- if (this._prevFullPath !== fullPath) {
468
- this.notifyPageStateChange();
469
- this._prevFullPath = fullPath;
470
- }
471
- });
472
- });
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
+ ]);
473
523
  };
474
524
 
475
525
  private setFocusScenePathHandler = debounce((fullPath: string | undefined) => {
@@ -487,6 +537,7 @@ export class AppProxy implements PageRemoveService {
487
537
  }
488
538
 
489
539
  public setViewFocusScenePath() {
540
+ if (this.status === "destroyed") return;
490
541
  const fullPath = this.getFullScenePath();
491
542
  if (fullPath && this.view) {
492
543
  setViewFocusScenePath(this.view, fullPath);
@@ -546,6 +597,7 @@ export class AppProxy implements PageRemoveService {
546
597
  const fullPath = this._pageState.getFullPath(index);
547
598
  if (fullPath) {
548
599
  this.setFullPath(fullPath);
600
+ setScenePath(this.manager.room, fullPath);
549
601
  }
550
602
  }
551
603
  }
@@ -558,12 +610,22 @@ export class AppProxy implements PageRemoveService {
558
610
  this.store.updateAppAttributes(this.id, Fields.Size, size);
559
611
  };
560
612
 
561
- 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>) => {
562
623
  if (!this.camera$.value) {
563
624
  return;
564
625
  }
565
- const nextCamera = { ...this.camera$.value, ...camera };
626
+ const nextCamera = { ...this.camera$.value, ...camera, id: this.uid };
566
627
  this.storeCamera(nextCamera);
628
+ this.camera$.setValue(nextCamera);
567
629
  };
568
630
 
569
631
  public async destroy(
@@ -576,6 +638,7 @@ export class AppProxy implements PageRemoveService {
576
638
  this.status = "destroyed";
577
639
  try {
578
640
  await appRegister.notifyApp(this.kind, "destroy", { appId: this.id });
641
+ callbacks.emit("appClose", { appId: this.id, kind: this.kind, error });
579
642
  await this.appEmitter.emit("destroy", { error });
580
643
  } catch (error) {
581
644
  console.error("[WindowManager]: notifyApp error", error.message, error.stack);
@@ -596,13 +659,60 @@ export class AppProxy implements PageRemoveService {
596
659
 
597
660
  this.viewManager.destroyView(this.id);
598
661
  this.manager.appStatus.delete(this.id);
599
- this.manager.refresher?.remove(this.id);
600
- this.manager.refresher?.remove(this.stateKey);
601
- this.manager.refresher?.remove(`${this.id}-fullPath`);
602
- this._prevFullPath = undefined;
603
- this.camera$.destroy();
604
- this.size$.destroy();
605
- 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);
606
716
  }
607
717
 
608
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 baseCamera$: 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.baseCamera$ = 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,13 @@ 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
+
87
+ putScenes(this.appContext.room, scenePath, scenes, nextIndex);
64
88
  } else {
65
- putScenes(this.appContext.room, scenePath, [scene || {}]);
89
+ putScenes(this.appContext.room, scenePath, scenes);
66
90
  }
67
91
  };
68
92
 
@@ -79,7 +103,7 @@ export class WhiteBoardView implements PageController {
79
103
  return this.appProxy.removeSceneByIndex(needRemoveIndex);
80
104
  };
81
105
 
82
- public destroy() {
83
- this.removeViewWrapper();
106
+ public setBaseRect(rect: Omit<TeleBoxRect, "x" | "y">) {
107
+ this.appProxy.updateSize(rect.width, rect.height);
84
108
  }
85
109
  }
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";
@@ -0,0 +1,22 @@
1
+
2
+ export type AppState = {
3
+ id: string;
4
+ focus?: boolean;
5
+ SceneIndex?: number;
6
+ draggable?: boolean;
7
+ position?: {
8
+ x: number;
9
+ y: number;
10
+ }
11
+ ratio?: number;
12
+ resizable?: boolean;
13
+ size?: {
14
+ width: number;
15
+ height: number;
16
+ }
17
+ stageRatio?: number;
18
+ visible?: boolean;
19
+ zIndex?: number;
20
+ maximized: boolean | null;
21
+ minimized: boolean | null;
22
+ }