@netless/window-manager 1.0.0-canary.0 → 1.0.0-canary.3
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.
- package/dist/App/AppContext.d.ts +14 -15
- package/dist/App/AppPageStateImpl.d.ts +6 -2
- package/dist/App/AppProxy.d.ts +5 -1
- package/dist/App/WhiteBoardView.d.ts +18 -0
- package/dist/App/index.d.ts +1 -0
- package/dist/AppManager.d.ts +2 -0
- package/dist/BoxManager.d.ts +2 -0
- package/dist/Helper.d.ts +12 -2
- package/dist/InternalEmitter.d.ts +2 -0
- package/dist/constants.d.ts +1 -0
- package/dist/index.cjs.js +12 -12
- package/dist/index.es.js +239 -392
- package/dist/index.umd.js +12 -12
- package/dist/style.css +1 -1
- package/dist/typings.d.ts +4 -0
- package/docs/app-context.md +94 -64
- package/docs/develop-app.md +2 -5
- package/package.json +3 -2
- package/pnpm-lock.yaml +11 -5
- package/src/App/AppContext.ts +65 -72
- package/src/App/AppPageStateImpl.ts +25 -6
- package/src/App/AppProxy.ts +39 -6
- package/src/App/Storage/index.ts +4 -4
- package/src/App/WhiteBoardView.ts +76 -0
- package/src/App/index.ts +1 -0
- package/src/AppManager.ts +9 -1
- package/src/BoxManager.ts +9 -1
- package/src/Helper.ts +10 -1
- package/src/InternalEmitter.ts +2 -0
- package/src/View/MainView.ts +2 -2
- package/src/constants.ts +2 -0
- package/src/index.ts +1 -1
- package/src/style.css +9 -0
- package/src/typings.ts +4 -0
package/src/App/AppContext.ts
CHANGED
@@ -1,5 +1,4 @@
|
|
1
1
|
import { BoxNotCreatedError } from "../Utils/error";
|
2
|
-
import { putScenes } from "../Utils/Common";
|
3
2
|
import { Storage } from "./Storage";
|
4
3
|
import {
|
5
4
|
autorun,
|
@@ -19,7 +18,7 @@ import type {
|
|
19
18
|
import type { ReadonlyTeleBox } from "@netless/telebox-insider";
|
20
19
|
import type Emittery from "emittery";
|
21
20
|
import type { BoxManager } from "../BoxManager";
|
22
|
-
import type { AppEmitterEvent } from "../index";
|
21
|
+
import type { AppEmitterEvent, Member } from "../index";
|
23
22
|
import type { AppManager } from "../AppManager";
|
24
23
|
import type { AppProxy } from "./AppProxy";
|
25
24
|
import type {
|
@@ -27,11 +26,13 @@ import type {
|
|
27
26
|
MagixEventDispatcher,
|
28
27
|
MagixEventRemoveListener,
|
29
28
|
} from "./MagixEvent";
|
30
|
-
import
|
29
|
+
import { WhiteBoardView } from "./WhiteBoardView";
|
30
|
+
import { findMemberByUid } from "../Helper";
|
31
|
+
import { MAX_PAGE_SIZE } from "../constants";
|
32
|
+
import { putScenes } from "../Utils/Common";
|
33
|
+
import { isNumber } from "lodash";
|
31
34
|
|
32
|
-
export class AppContext<TAttributes = any, TMagixEventPayloads = any, TAppOptions = any>
|
33
|
-
implements PageController
|
34
|
-
{
|
35
|
+
export class AppContext<TAttributes = any, TMagixEventPayloads = any, TAppOptions = any> {
|
35
36
|
public readonly emitter: Emittery<AppEmitterEvent<TAttributes>>;
|
36
37
|
public readonly mobxUtils = {
|
37
38
|
autorun,
|
@@ -48,6 +49,7 @@ export class AppContext<TAttributes = any, TMagixEventPayloads = any, TAppOption
|
|
48
49
|
private store = this.manager.store;
|
49
50
|
public readonly isAddApp: boolean;
|
50
51
|
public readonly isReplay = this.manager.isReplay;
|
52
|
+
private whiteBoardView?: WhiteBoardView;
|
51
53
|
|
52
54
|
constructor(
|
53
55
|
private manager: AppManager,
|
@@ -60,7 +62,7 @@ export class AppContext<TAttributes = any, TMagixEventPayloads = any, TAppOption
|
|
60
62
|
this.isAddApp = appProxy.isAddApp;
|
61
63
|
}
|
62
64
|
|
63
|
-
public
|
65
|
+
public get displayer(){
|
64
66
|
return this.manager.displayer;
|
65
67
|
};
|
66
68
|
|
@@ -78,32 +80,58 @@ export class AppContext<TAttributes = any, TMagixEventPayloads = any, TAppOption
|
|
78
80
|
}
|
79
81
|
};
|
80
82
|
|
81
|
-
public
|
83
|
+
public get view(): View | undefined {
|
82
84
|
return this.appProxy.view;
|
83
85
|
};
|
84
86
|
|
85
|
-
public
|
86
|
-
|
87
|
-
|
88
|
-
view.divElement = dom as HTMLDivElement;
|
89
|
-
setTimeout(() => {
|
90
|
-
// 渲染需要时间,延迟 refresh
|
91
|
-
this.getRoom()?.refreshViewSize();
|
92
|
-
}, 1000);
|
87
|
+
public createWhiteBoardView = (size?: number): WhiteBoardView => {
|
88
|
+
if (this.whiteBoardView) {
|
89
|
+
return this.whiteBoardView;
|
93
90
|
}
|
94
|
-
|
91
|
+
let view = this.view;
|
92
|
+
if (!view) {
|
93
|
+
view = this.appProxy.createAppDir();
|
94
|
+
}
|
95
|
+
const viewWrapper = document.createElement("div");
|
96
|
+
viewWrapper.className = "window-manager-view-wrapper";
|
97
|
+
this.box.$content.parentElement?.appendChild(viewWrapper);
|
98
|
+
const removeViewWrapper = () => {
|
99
|
+
this.box.$content.parentElement?.removeChild(viewWrapper);
|
100
|
+
}
|
101
|
+
view.divElement = viewWrapper
|
102
|
+
if (this.isAddApp) {
|
103
|
+
this.initPageSize(size);
|
104
|
+
}
|
105
|
+
this.whiteBoardView = new WhiteBoardView(this, this.appProxy, removeViewWrapper);
|
106
|
+
return this.whiteBoardView;
|
107
|
+
}
|
108
|
+
|
109
|
+
private initPageSize = (size?: number) => {
|
110
|
+
if (!isNumber(size)) return;
|
111
|
+
if (!this.appProxy.scenePath) return;
|
112
|
+
if (this.appProxy.pageState.length >= size) return;
|
113
|
+
if (size <= 0 || size >= MAX_PAGE_SIZE) {
|
114
|
+
throw Error(`[WindowManager]: size ${size} muse be in range [1, ${MAX_PAGE_SIZE}]`);
|
115
|
+
}
|
116
|
+
const needInsert = size - this.appProxy.pageState.length;
|
117
|
+
const startPageNumber = this.appProxy.pageState.length;
|
118
|
+
const scenes = new Array(needInsert).fill({}).map((_, index) => {
|
119
|
+
return { name: `${startPageNumber + index + 1}` };
|
120
|
+
});
|
121
|
+
putScenes(this.room, this.appProxy.scenePath, scenes);
|
122
|
+
}
|
95
123
|
|
96
124
|
public getInitScenePath = () => {
|
97
125
|
return this.manager.getAppInitPath(this.appId);
|
98
126
|
};
|
99
127
|
|
100
128
|
/** Get App writable status. */
|
101
|
-
public
|
129
|
+
public get isWritable(): boolean {
|
102
130
|
return this.manager.canOperate;
|
103
131
|
};
|
104
132
|
|
105
133
|
/** Get the App Window UI box. */
|
106
|
-
public
|
134
|
+
public get box(): ReadonlyTeleBox {
|
107
135
|
const box = this.boxManager.getBox(this.appId);
|
108
136
|
if (box) {
|
109
137
|
return box;
|
@@ -112,10 +140,25 @@ export class AppContext<TAttributes = any, TMagixEventPayloads = any, TAppOption
|
|
112
140
|
}
|
113
141
|
};
|
114
142
|
|
115
|
-
public
|
143
|
+
public get room(): Room | undefined {
|
116
144
|
return this.manager.room;
|
117
145
|
};
|
118
146
|
|
147
|
+
public get members() {
|
148
|
+
return this.manager.members;
|
149
|
+
}
|
150
|
+
|
151
|
+
public get memberState(): Member {
|
152
|
+
const self = findMemberByUid(this.room, this.manager.uid);
|
153
|
+
if (!self) {
|
154
|
+
throw new Error(`Member ${this.manager.uid} not found.`);
|
155
|
+
}
|
156
|
+
return {
|
157
|
+
uid: this.manager.uid,
|
158
|
+
...self,
|
159
|
+
}
|
160
|
+
}
|
161
|
+
|
119
162
|
/** @deprecated Use context.storage.setState instead. */
|
120
163
|
public setAttributes = (attributes: TAttributes) => {
|
121
164
|
this.manager.safeSetAttributes({ [this.appId]: attributes });
|
@@ -128,11 +171,12 @@ export class AppContext<TAttributes = any, TMagixEventPayloads = any, TAppOption
|
|
128
171
|
}
|
129
172
|
};
|
130
173
|
|
174
|
+
/** @deprecated Use Pages api instead. */
|
131
175
|
public setScenePath = async (scenePath: string): Promise<void> => {
|
132
176
|
if (!this.appProxy.box) return;
|
133
177
|
this.appProxy.setFullPath(scenePath);
|
134
178
|
// 兼容 15 版本 SDK 的切页
|
135
|
-
this.
|
179
|
+
this.room?.setScenePath(scenePath);
|
136
180
|
};
|
137
181
|
|
138
182
|
/** Get the local App options. */
|
@@ -196,55 +240,4 @@ export class AppContext<TAttributes = any, TMagixEventPayloads = any, TAppOption
|
|
196
240
|
public removeMagixEventListener = this.manager.displayer.removeMagixEventListener.bind(
|
197
241
|
this.manager.displayer
|
198
242
|
) as MagixEventRemoveListener<TMagixEventPayloads>;
|
199
|
-
|
200
|
-
/** PageController */
|
201
|
-
public nextPage = async (): Promise<boolean> => {
|
202
|
-
const nextIndex = this.pageState.index + 1;
|
203
|
-
if (nextIndex > this.pageState.length - 1) {
|
204
|
-
console.warn("[WindowManager] nextPage: index out of range");
|
205
|
-
return false;
|
206
|
-
}
|
207
|
-
this.appProxy.setSceneIndex(nextIndex);
|
208
|
-
return true;
|
209
|
-
};
|
210
|
-
|
211
|
-
public prevPage = async (): Promise<boolean> => {
|
212
|
-
const nextIndex = this.pageState.index - 1;
|
213
|
-
if (nextIndex < 0) {
|
214
|
-
console.warn("[WindowManager] prevPage: index out of range");
|
215
|
-
return false;
|
216
|
-
}
|
217
|
-
this.appProxy.setSceneIndex(nextIndex);
|
218
|
-
return true;
|
219
|
-
};
|
220
|
-
|
221
|
-
public addPage = async (params?: AddPageParams) => {
|
222
|
-
const after = params?.after;
|
223
|
-
const scene = params?.scene;
|
224
|
-
const scenePath = this.appProxy.scenePath;
|
225
|
-
if (!scenePath) return;
|
226
|
-
if (after) {
|
227
|
-
const nextIndex = this.pageState.index + 1;
|
228
|
-
putScenes(this.manager.room, scenePath, [scene || {}], nextIndex);
|
229
|
-
} else {
|
230
|
-
putScenes(this.manager.room, scenePath, [scene || {}]);
|
231
|
-
}
|
232
|
-
};
|
233
|
-
|
234
|
-
public removePage = async (index?: number): Promise<boolean> => {
|
235
|
-
const needRemoveIndex = index === undefined ? this.pageState.index : index;
|
236
|
-
if (this.pageState.length === 1) {
|
237
|
-
console.warn(`[WindowManager]: can not remove the last page`);
|
238
|
-
return false;
|
239
|
-
}
|
240
|
-
if (needRemoveIndex < 0 || needRemoveIndex >= this.pageState.length) {
|
241
|
-
console.warn(`[WindowManager]: page index ${index} out of range`);
|
242
|
-
return false;
|
243
|
-
}
|
244
|
-
return this.appProxy.removeSceneByIndex(needRemoveIndex);;
|
245
|
-
}
|
246
|
-
|
247
|
-
public get pageState(): PageState {
|
248
|
-
return this.appProxy.pageState;
|
249
|
-
}
|
250
243
|
}
|
@@ -9,11 +9,15 @@ export type AppPageStateParams = {
|
|
9
9
|
};
|
10
10
|
|
11
11
|
export class AppPageStateImpl {
|
12
|
-
|
12
|
+
public sceneNode: ScenesCallbacksNode | null = null;
|
13
|
+
private scenePath?: string;
|
14
|
+
private view?: View;
|
13
15
|
|
14
16
|
constructor(private params: AppPageStateParams) {
|
15
17
|
const { displayer, scenePath } = this.params;
|
18
|
+
this.view = this.params.view;
|
16
19
|
if (scenePath) {
|
20
|
+
this.scenePath = scenePath;
|
17
21
|
this.sceneNode = displayer.createScenesCallback(scenePath, {
|
18
22
|
onAddScene: this.onSceneChange,
|
19
23
|
onRemoveScene: this.onSceneChange,
|
@@ -21,24 +25,39 @@ export class AppPageStateImpl {
|
|
21
25
|
}
|
22
26
|
}
|
23
27
|
|
24
|
-
|
25
|
-
this.
|
28
|
+
public createSceneNode = (scenePath: string) => {
|
29
|
+
this.scenePath = scenePath;
|
30
|
+
if (this.sceneNode) {
|
31
|
+
this.sceneNode.dispose();
|
32
|
+
}
|
33
|
+
this.sceneNode = this.params.displayer.createScenesCallback(scenePath, {
|
34
|
+
onAddScene: this.onSceneChange,
|
35
|
+
onRemoveScene: this.onSceneChange,
|
36
|
+
});
|
37
|
+
return this.sceneNode;
|
38
|
+
}
|
39
|
+
|
40
|
+
public setView(view: View) {
|
41
|
+
this.view = view;
|
42
|
+
}
|
43
|
+
|
44
|
+
private onSceneChange = () => {
|
26
45
|
this.params.notifyPageStateChange();
|
27
46
|
};
|
28
47
|
|
29
48
|
public getFullPath(index: number) {
|
30
49
|
const scenes = this.sceneNode?.scenes;
|
31
|
-
if (this.
|
50
|
+
if (this.scenePath && scenes) {
|
32
51
|
const name = scenes[index];
|
33
52
|
if (name) {
|
34
|
-
return `${this.
|
53
|
+
return `${this.scenePath}/${name}`;
|
35
54
|
}
|
36
55
|
}
|
37
56
|
}
|
38
57
|
|
39
58
|
public toObject(): PageState {
|
40
59
|
return {
|
41
|
-
index: this.
|
60
|
+
index: this.view?.focusSceneIndex || 0,
|
42
61
|
length: this.sceneNode?.scenes.length || 0,
|
43
62
|
};
|
44
63
|
}
|
package/src/App/AppProxy.ts
CHANGED
@@ -12,6 +12,7 @@ import { log } from "../Utils/log";
|
|
12
12
|
import {
|
13
13
|
entireScenes,
|
14
14
|
getScenePath,
|
15
|
+
putScenes,
|
15
16
|
removeScenes,
|
16
17
|
setScenePath,
|
17
18
|
setViewFocusScenePath,
|
@@ -30,6 +31,7 @@ import type { ReadonlyTeleBox } from "@netless/telebox-insider";
|
|
30
31
|
import type { PageRemoveService, PageState } from "../Page";
|
31
32
|
import { calculateNextIndex } from "../Page";
|
32
33
|
import { boxEmitter } from "../BoxEmitter";
|
34
|
+
import { SideEffectManager } from "side-effect-manager";
|
33
35
|
|
34
36
|
export type AppEmitter = Emittery<AppEmitterEvent>;
|
35
37
|
|
@@ -37,6 +39,7 @@ export class AppProxy implements PageRemoveService {
|
|
37
39
|
public kind: string;
|
38
40
|
public id: string;
|
39
41
|
public scenePath?: string;
|
42
|
+
private appScenePath: string;
|
40
43
|
public appEmitter: AppEmitter;
|
41
44
|
public scenes?: SceneDefinition[];
|
42
45
|
|
@@ -49,12 +52,14 @@ export class AppProxy implements PageRemoveService {
|
|
49
52
|
public isAddApp: boolean;
|
50
53
|
private status: "normal" | "destroyed" = "normal";
|
51
54
|
private stateKey: string;
|
52
|
-
|
55
|
+
public _pageState: AppPageStateImpl;
|
53
56
|
private _prevFullPath: string | undefined;
|
54
57
|
|
55
58
|
public appResult?: NetlessApp<any>;
|
56
59
|
public appContext?: AppContext<any, any>;
|
57
60
|
|
61
|
+
private sideEffectManager = new SideEffectManager();
|
62
|
+
|
58
63
|
constructor(
|
59
64
|
private params: BaseInsertParams,
|
60
65
|
private manager: AppManager,
|
@@ -63,6 +68,7 @@ export class AppProxy implements PageRemoveService {
|
|
63
68
|
) {
|
64
69
|
this.kind = params.kind;
|
65
70
|
this.id = appId;
|
71
|
+
this.appScenePath = `/${this.id}-app-dir`;
|
66
72
|
this.stateKey = `${this.id}_state`;
|
67
73
|
this.appProxies.set(this.id, this);
|
68
74
|
this.appEmitter = new Emittery();
|
@@ -75,12 +81,37 @@ export class AppProxy implements PageRemoveService {
|
|
75
81
|
// 只有传入了 scenePath 的 App 才会创建 View
|
76
82
|
this.createView();
|
77
83
|
}
|
84
|
+
if (!this.scenePath) {
|
85
|
+
this.scenePath = this.appScenePath;
|
86
|
+
}
|
78
87
|
this._pageState = new AppPageStateImpl({
|
79
88
|
displayer: this.manager.displayer,
|
80
89
|
scenePath: this.scenePath,
|
81
90
|
view: this.view,
|
82
91
|
notifyPageStateChange: this.notifyPageStateChange,
|
83
92
|
});
|
93
|
+
this.sideEffectManager.add(() => {
|
94
|
+
return () => this._pageState.destroy();
|
95
|
+
});
|
96
|
+
this.sideEffectManager.add(() => {
|
97
|
+
return emitter.on("roomMembersChange", members => {
|
98
|
+
this.appEmitter.emit("roomMembersChange", members);
|
99
|
+
});
|
100
|
+
});
|
101
|
+
}
|
102
|
+
|
103
|
+
public createAppDir() {
|
104
|
+
const scenePath = this.scenePath || this.appScenePath;
|
105
|
+
const sceneNode = this._pageState.createSceneNode(scenePath);
|
106
|
+
if (!sceneNode) {
|
107
|
+
putScenes(this.manager.room, scenePath, [{ name: "1" }]);
|
108
|
+
this._pageState.createSceneNode(scenePath);
|
109
|
+
this.setSceneIndex(0);
|
110
|
+
}
|
111
|
+
this.scenes = entireScenes(this.manager.displayer)[scenePath];
|
112
|
+
const view = this.createView();
|
113
|
+
this._pageState.setView(view);
|
114
|
+
return view;
|
84
115
|
}
|
85
116
|
|
86
117
|
private initScenes() {
|
@@ -395,14 +426,16 @@ export class AppProxy implements PageRemoveService {
|
|
395
426
|
return fullPath;
|
396
427
|
}
|
397
428
|
|
398
|
-
private
|
399
|
-
const view =
|
429
|
+
private createView(): View {
|
430
|
+
const view = this.viewManager.createView(this.id);
|
400
431
|
this.setViewFocusScenePath();
|
401
432
|
return view;
|
402
433
|
}
|
403
434
|
|
404
435
|
public notifyPageStateChange = debounce(() => {
|
405
|
-
|
436
|
+
if (this.pageState) {
|
437
|
+
this.appEmitter.emit("pageStateChange", this.pageState);
|
438
|
+
}
|
406
439
|
}, 50);
|
407
440
|
|
408
441
|
public get pageState(): PageState {
|
@@ -412,7 +445,7 @@ export class AppProxy implements PageRemoveService {
|
|
412
445
|
// PageRemoveService
|
413
446
|
public async removeSceneByIndex(index: number) {
|
414
447
|
const scenePath = this._pageState.getFullPath(index);
|
415
|
-
if (scenePath) {
|
448
|
+
if (scenePath && this.pageState) {
|
416
449
|
const nextIndex = calculateNextIndex(index, this.pageState);
|
417
450
|
// 只修改 focus path 不修改 FullPath
|
418
451
|
this.setSceneIndexWithoutSync(nextIndex);
|
@@ -474,7 +507,6 @@ export class AppProxy implements PageRemoveService {
|
|
474
507
|
}
|
475
508
|
}
|
476
509
|
this.appProxies.delete(this.id);
|
477
|
-
this._pageState.destroy();
|
478
510
|
|
479
511
|
this.viewManager.destroyView(this.id);
|
480
512
|
this.manager.appStatus.delete(this.id);
|
@@ -482,6 +514,7 @@ export class AppProxy implements PageRemoveService {
|
|
482
514
|
this.manager.refresher?.remove(this.stateKey);
|
483
515
|
this.manager.refresher?.remove(`${this.id}-fullPath`);
|
484
516
|
this._prevFullPath = undefined;
|
517
|
+
this.sideEffectManager.flushAll();
|
485
518
|
}
|
486
519
|
|
487
520
|
public close(): Promise<void> {
|
package/src/App/Storage/index.ts
CHANGED
@@ -37,7 +37,7 @@ export class Storage<TState extends Record<string, any> = any> implements Storag
|
|
37
37
|
this._state = {} as TState;
|
38
38
|
const rawState = this._getRawState(this._state);
|
39
39
|
|
40
|
-
if (this._context.
|
40
|
+
if (this._context.isWritable) {
|
41
41
|
if (this.id === null) {
|
42
42
|
if (context.isAddApp && defaultState) {
|
43
43
|
this.setState(defaultState);
|
@@ -115,7 +115,7 @@ export class Storage<TState extends Record<string, any> = any> implements Storag
|
|
115
115
|
return;
|
116
116
|
}
|
117
117
|
|
118
|
-
if (!this._context.
|
118
|
+
if (!this._context.isWritable) {
|
119
119
|
console.error(new Error(`Cannot setState on Storage "${this.id}" without writable access`), state);
|
120
120
|
return;
|
121
121
|
}
|
@@ -165,7 +165,7 @@ export class Storage<TState extends Record<string, any> = any> implements Storag
|
|
165
165
|
return;
|
166
166
|
}
|
167
167
|
|
168
|
-
if (!this._context.
|
168
|
+
if (!this._context.isWritable) {
|
169
169
|
console.error(new Error(`Cannot empty Storage "${this.id}" without writable access.`));
|
170
170
|
return;
|
171
171
|
}
|
@@ -181,7 +181,7 @@ export class Storage<TState extends Record<string, any> = any> implements Storag
|
|
181
181
|
throw new Error(`Cannot delete main Storage`);
|
182
182
|
}
|
183
183
|
|
184
|
-
if (!this._context.
|
184
|
+
if (!this._context.isWritable) {
|
185
185
|
console.error(new Error(`Cannot delete Storage "${this.id}" without writable access.`));
|
186
186
|
return;
|
187
187
|
}
|
@@ -0,0 +1,76 @@
|
|
1
|
+
import { putScenes } from "../Utils/Common";
|
2
|
+
import { Val } from "value-enhancer";
|
3
|
+
|
4
|
+
import type { ReadonlyVal } from "value-enhancer";
|
5
|
+
import type { AddPageParams, PageController, PageState } from "../Page";
|
6
|
+
import type { AppProxy } from "./AppProxy";
|
7
|
+
import type { AppContext } from "./AppContext";
|
8
|
+
|
9
|
+
export class WhiteBoardView implements PageController {
|
10
|
+
public readonly pageState$: ReadonlyVal<PageState>;
|
11
|
+
|
12
|
+
constructor(
|
13
|
+
protected appContext: AppContext,
|
14
|
+
protected appProxy: AppProxy,
|
15
|
+
private removeViewWrapper: () => void,
|
16
|
+
) {
|
17
|
+
const pageState$ = new Val<PageState>(appProxy.pageState);
|
18
|
+
this.pageState$ = pageState$;
|
19
|
+
appProxy.appEmitter.on("pageStateChange", pageState => {
|
20
|
+
pageState$.setValue(pageState);
|
21
|
+
});
|
22
|
+
}
|
23
|
+
|
24
|
+
public get pageState() {
|
25
|
+
return this.pageState$.value;
|
26
|
+
}
|
27
|
+
|
28
|
+
public nextPage = async (): Promise<boolean> => {
|
29
|
+
const nextIndex = this.pageState.index + 1;
|
30
|
+
return this.jumpPage(nextIndex);
|
31
|
+
};
|
32
|
+
|
33
|
+
public prevPage = async (): Promise<boolean> => {
|
34
|
+
const nextIndex = this.pageState.index - 1;
|
35
|
+
return this.jumpPage(nextIndex);
|
36
|
+
};
|
37
|
+
|
38
|
+
public jumpPage = async (index: number): Promise<boolean> => {
|
39
|
+
if (index < 0 || index >= this.pageState.length) {
|
40
|
+
console.warn(`[WindowManager]: index ${index} out of range`);
|
41
|
+
return false;
|
42
|
+
}
|
43
|
+
this.appProxy.setSceneIndex(index);
|
44
|
+
return true;
|
45
|
+
};
|
46
|
+
|
47
|
+
public addPage = async (params?: AddPageParams) => {
|
48
|
+
const after = params?.after;
|
49
|
+
const scene = params?.scene;
|
50
|
+
const scenePath = this.appProxy.scenePath;
|
51
|
+
if (!scenePath) return;
|
52
|
+
if (after) {
|
53
|
+
const nextIndex = this.pageState.index + 1;
|
54
|
+
putScenes(this.appContext.room, scenePath, [scene || {}], nextIndex);
|
55
|
+
} else {
|
56
|
+
putScenes(this.appContext.room, scenePath, [scene || {}]);
|
57
|
+
}
|
58
|
+
};
|
59
|
+
|
60
|
+
public removePage = async (index?: number): Promise<boolean> => {
|
61
|
+
const needRemoveIndex = index === undefined ? this.pageState.index : index;
|
62
|
+
if (this.pageState.length === 1) {
|
63
|
+
console.warn(`[WindowManager]: can not remove the last page`);
|
64
|
+
return false;
|
65
|
+
}
|
66
|
+
if (needRemoveIndex < 0 || needRemoveIndex >= this.pageState.length) {
|
67
|
+
console.warn(`[WindowManager]: page index ${index} out of range`);
|
68
|
+
return false;
|
69
|
+
}
|
70
|
+
return this.appProxy.removeSceneByIndex(needRemoveIndex);
|
71
|
+
};
|
72
|
+
|
73
|
+
public destroy() {
|
74
|
+
this.removeViewWrapper();
|
75
|
+
}
|
76
|
+
}
|
package/src/App/index.ts
CHANGED
package/src/AppManager.ts
CHANGED
@@ -15,6 +15,7 @@ import { MainViewProxy } from "./View/MainView";
|
|
15
15
|
import { onObjectRemoved, safeListenPropsUpdated } from "./Utils/Reactive";
|
16
16
|
import { reconnectRefresher, WindowManager } from "./index";
|
17
17
|
import { RedoUndo } from "./RedoUndo";
|
18
|
+
import { serializeRoomMembers } from "./Helper";
|
18
19
|
import { SideEffectManager } from "side-effect-manager";
|
19
20
|
import { ViewManager } from "./View/ViewManager";
|
20
21
|
import type { SyncRegisterAppPayload } from "./Register";
|
@@ -46,7 +47,7 @@ import type {
|
|
46
47
|
BoxResizePayload,
|
47
48
|
BoxStateChangePayload,
|
48
49
|
} from "./BoxEmitter";
|
49
|
-
|
50
|
+
import type { Member } from "./Helper";
|
50
51
|
|
51
52
|
export class AppManager {
|
52
53
|
public displayer: Displayer;
|
@@ -299,6 +300,10 @@ export class AppManager {
|
|
299
300
|
return this.room?.uid || "";
|
300
301
|
}
|
301
302
|
|
303
|
+
public get members(): Member[] {
|
304
|
+
return serializeRoomMembers(this.displayer.state.roomMembers);
|
305
|
+
}
|
306
|
+
|
302
307
|
public getMainViewSceneDir() {
|
303
308
|
const scenePath = this.store.getMainViewScenePath();
|
304
309
|
if (scenePath) {
|
@@ -660,6 +665,9 @@ export class AppManager {
|
|
660
665
|
this.appProxies.forEach(appProxy => {
|
661
666
|
appProxy.appEmitter.emit("roomStateChange", state);
|
662
667
|
});
|
668
|
+
if (state.roomMembers) {
|
669
|
+
emitter.emit("roomMembersChange", this.members);
|
670
|
+
}
|
663
671
|
emitter.emit("observerIdChange", this.displayer.observerId);
|
664
672
|
};
|
665
673
|
|
package/src/BoxManager.ts
CHANGED
@@ -210,6 +210,10 @@ export class BoxManager {
|
|
210
210
|
return this.teleBoxManager.boxes.length;
|
211
211
|
}
|
212
212
|
|
213
|
+
public get stageRect() {
|
214
|
+
return this.teleBoxManager.stageRect;
|
215
|
+
}
|
216
|
+
|
213
217
|
public createBox(params: CreateBoxParams): void {
|
214
218
|
if (!this.teleBoxManager) return;
|
215
219
|
let { minwidth = MIN_WIDTH, minheight = MIN_HEIGHT } = params.app.config ?? {};
|
@@ -242,7 +246,7 @@ export class BoxManager {
|
|
242
246
|
): TeleBoxManager {
|
243
247
|
const root = WindowManager.playground;
|
244
248
|
const initManagerState: TeleBoxManagerConfig = {
|
245
|
-
stageRatio:
|
249
|
+
stageRatio: createTeleBoxManagerConfig?.stageRatio,
|
246
250
|
root: root,
|
247
251
|
fence: false,
|
248
252
|
prefersColorScheme: createTeleBoxManagerConfig?.prefersColorScheme,
|
@@ -390,6 +394,10 @@ export class BoxManager {
|
|
390
394
|
this.teleBoxManager._root$.setValue(root);
|
391
395
|
}
|
392
396
|
|
397
|
+
public setCollector(collector: HTMLElement) {
|
398
|
+
this.teleBoxManager.collector.set$collector(collector);
|
399
|
+
}
|
400
|
+
|
393
401
|
public destroy() {
|
394
402
|
this.sideEffectManager.flushAll();
|
395
403
|
this.teleBoxManager.destroy();
|
package/src/Helper.ts
CHANGED
@@ -2,7 +2,7 @@ import { getVersionNumber } from "./Utils/Common";
|
|
2
2
|
import { REQUIRE_VERSION } from "./constants";
|
3
3
|
import { WhiteVersion } from "white-web-sdk";
|
4
4
|
import { WhiteWebSDKInvalidError } from "./Utils/error";
|
5
|
-
import type { Room } from "white-web-sdk";
|
5
|
+
import type { Room , RoomMember} from "white-web-sdk";
|
6
6
|
|
7
7
|
export const setupWrapper = (
|
8
8
|
root: HTMLElement
|
@@ -32,3 +32,12 @@ export const findMemberByUid = (room: Room | undefined, uid: string) => {
|
|
32
32
|
const roomMembers = room?.state.roomMembers;
|
33
33
|
return roomMembers?.find(member => member.payload?.uid === uid);
|
34
34
|
};
|
35
|
+
|
36
|
+
export type Member = RoomMember & { uid: string };
|
37
|
+
|
38
|
+
export const serializeRoomMembers = (members: readonly RoomMember[]) => {
|
39
|
+
return members.map(member => ({
|
40
|
+
uid: member.payload?.uid || "",
|
41
|
+
...member,
|
42
|
+
}));
|
43
|
+
}
|
package/src/InternalEmitter.ts
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
import Emittery from "emittery";
|
2
2
|
import type { TeleBoxRect } from "@netless/telebox-insider";
|
3
3
|
import type { AppInitState, CursorMovePayload } from "./index";
|
4
|
+
import type { Member } from "./Helper";
|
4
5
|
|
5
6
|
export type RemoveSceneParams = {
|
6
7
|
scenePath: string;
|
@@ -29,6 +30,7 @@ export type EmitterEvent = {
|
|
29
30
|
changePageState: undefined;
|
30
31
|
writableChange: boolean;
|
31
32
|
containerSizeRatioUpdate: number;
|
33
|
+
roomMembersChange: Member[];
|
32
34
|
};
|
33
35
|
|
34
36
|
export type EmitterType = Emittery<EmitterEvent>;
|
package/src/View/MainView.ts
CHANGED
@@ -42,7 +42,7 @@ export class MainViewProxy {
|
|
42
42
|
}
|
43
43
|
});
|
44
44
|
});
|
45
|
-
const rect = this.manager.boxManager?.
|
45
|
+
const rect = this.manager.boxManager?.stageRect;
|
46
46
|
if (rect) {
|
47
47
|
this.synchronizer.setRect(rect);
|
48
48
|
}
|
@@ -191,7 +191,7 @@ export class MainViewProxy {
|
|
191
191
|
};
|
192
192
|
|
193
193
|
private getStageSize(): Size | undefined {
|
194
|
-
const stage = this.manager.boxManager?.
|
194
|
+
const stage = this.manager.boxManager?.stageRect;
|
195
195
|
if (stage) {
|
196
196
|
return { width: stage.width, height: stage.height };
|
197
197
|
}
|
package/src/constants.ts
CHANGED
package/src/index.ts
CHANGED
@@ -340,7 +340,7 @@ export class WindowManager extends InvisiblePlugin<WindowMangerAttributes> imple
|
|
340
340
|
|
341
341
|
public bindCollectorContainer(container: HTMLElement) {
|
342
342
|
if (WindowManager.isCreated && this.boxManager) {
|
343
|
-
this.boxManager.
|
343
|
+
this.boxManager.setCollector(container);
|
344
344
|
} else {
|
345
345
|
if (WindowManager.params) {
|
346
346
|
WindowManager.params.collectorContainer = container;
|