@netless/window-manager 0.4.24 → 0.4.27-canary.0
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/CHANGELOG.md +9 -0
- package/__mocks__/white-web-sdk.ts +41 -0
- package/dist/App/AppContext.d.ts +2 -1
- package/dist/App/AppProxy.d.ts +7 -3
- package/dist/AppListener.d.ts +1 -0
- package/dist/AppManager.d.ts +2 -0
- package/dist/ContainerResizeObserver.d.ts +2 -1
- package/dist/InternalEmitter.d.ts +8 -2
- package/dist/Page/PageController.d.ts +5 -0
- package/dist/Page/index.d.ts +2 -0
- package/dist/Utils/Common.d.ts +2 -1
- package/dist/Utils/error.d.ts +3 -0
- package/dist/View/MainView.d.ts +4 -1
- package/dist/constants.d.ts +1 -0
- package/dist/index.cjs.js +12 -12
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.es.js +263 -61
- package/dist/index.es.js.map +1 -1
- package/dist/index.umd.js +12 -12
- package/dist/index.umd.js.map +1 -1
- package/dist/typings.d.ts +1 -0
- package/docs/advanced.md +29 -4
- package/docs/api.md +17 -0
- package/docs/app-context.md +149 -100
- package/package.json +5 -9
- package/pnpm-lock.yaml +793 -2690
- package/src/App/AppContext.ts +20 -11
- package/src/App/AppProxy.ts +61 -5
- package/src/App/Storage/index.ts +14 -8
- package/src/AppListener.ts +22 -0
- package/src/AppManager.ts +57 -24
- package/src/ContainerResizeObserver.ts +12 -1
- package/src/InternalEmitter.ts +7 -2
- package/src/Page/PageController.ts +6 -0
- package/src/Page/index.ts +18 -0
- package/src/PageState.ts +2 -1
- package/src/ReconnectRefresher.ts +4 -1
- package/src/Utils/Common.ts +14 -2
- package/src/Utils/RoomHacker.ts +2 -2
- package/src/Utils/error.ts +4 -0
- package/src/View/MainView.ts +37 -8
- package/src/constants.ts +1 -0
- package/src/index.ts +26 -1
- package/src/typings.ts +1 -0
- package/vite.config.js +9 -1
package/src/App/AppContext.ts
CHANGED
@@ -82,6 +82,17 @@ export class AppContext<TAttributes = any, TMagixEventPayloads = any, TAppOption
|
|
82
82
|
return this.appProxy.view;
|
83
83
|
};
|
84
84
|
|
85
|
+
public mountView = (dom: HTMLElement): void => {
|
86
|
+
const view = this.getView();
|
87
|
+
if (view) {
|
88
|
+
view.divElement = dom as HTMLDivElement;
|
89
|
+
setTimeout(() => {
|
90
|
+
// 渲染需要时间,延迟 refresh
|
91
|
+
this.getRoom()?.refreshViewSize();
|
92
|
+
}, 1000);
|
93
|
+
}
|
94
|
+
};
|
95
|
+
|
85
96
|
public getInitScenePath = () => {
|
86
97
|
return this.manager.getAppInitPath(this.appId);
|
87
98
|
};
|
@@ -124,17 +135,6 @@ export class AppContext<TAttributes = any, TMagixEventPayloads = any, TAppOption
|
|
124
135
|
this.getRoom()?.setScenePath(scenePath);
|
125
136
|
};
|
126
137
|
|
127
|
-
public mountView = (dom: HTMLElement): void => {
|
128
|
-
const view = this.getView();
|
129
|
-
if (view) {
|
130
|
-
view.divElement = dom as HTMLDivElement;
|
131
|
-
setTimeout(() => {
|
132
|
-
// 渲染需要时间,延迟 refresh
|
133
|
-
this.getRoom()?.refreshViewSize();
|
134
|
-
}, 1000);
|
135
|
-
}
|
136
|
-
};
|
137
|
-
|
138
138
|
/** Get the local App options. */
|
139
139
|
public getAppOptions = (): TAppOptions | undefined => {
|
140
140
|
return typeof this.appOptions === "function"
|
@@ -231,6 +231,15 @@ export class AppContext<TAttributes = any, TMagixEventPayloads = any, TAppOption
|
|
231
231
|
}
|
232
232
|
};
|
233
233
|
|
234
|
+
public removePage = async (index: number): Promise<boolean> => {
|
235
|
+
if (index < 0 || index >= this.pageState.length) {
|
236
|
+
console.warn(`[WindowManager]: page index ${index} out of range`);
|
237
|
+
return false;
|
238
|
+
}
|
239
|
+
this.appProxy.removeSceneByIndex(index);
|
240
|
+
return true;
|
241
|
+
}
|
242
|
+
|
234
243
|
public get pageState(): PageState {
|
235
244
|
return this.appProxy.pageState;
|
236
245
|
}
|
package/src/App/AppProxy.ts
CHANGED
@@ -27,11 +27,11 @@ import type { SceneState, View, SceneDefinition } from "white-web-sdk";
|
|
27
27
|
import type { AppManager } from "../AppManager";
|
28
28
|
import type { NetlessApp } from "../typings";
|
29
29
|
import type { ReadonlyTeleBox } from "@netless/telebox-insider";
|
30
|
-
import
|
30
|
+
import { calculateNextIndex, PageRemoveService, PageState } from "../Page";
|
31
31
|
|
32
32
|
export type AppEmitter = Emittery<AppEmitterEvent>;
|
33
33
|
|
34
|
-
export class AppProxy {
|
34
|
+
export class AppProxy implements PageRemoveService {
|
35
35
|
public kind: string;
|
36
36
|
public id: string;
|
37
37
|
public scenePath?: string;
|
@@ -48,6 +48,7 @@ export class AppProxy {
|
|
48
48
|
private status: "normal" | "destroyed" = "normal";
|
49
49
|
private stateKey: string;
|
50
50
|
private _pageState: AppPageStateImpl;
|
51
|
+
private _prevFullPath: string | undefined;
|
51
52
|
|
52
53
|
public appResult?: NetlessApp<any>;
|
53
54
|
public appContext?: AppContext<any, any>;
|
@@ -248,6 +249,24 @@ export class AppProxy {
|
|
248
249
|
this.boxManager?.updateBoxState(currentAppState);
|
249
250
|
}
|
250
251
|
|
252
|
+
public async onRemoveScene(scenePath: string) {
|
253
|
+
if (this.scenePath && scenePath.startsWith(this.scenePath + "/")) {
|
254
|
+
let nextIndex = this.pageState.index;
|
255
|
+
let fullPath = this._pageState.getFullPath(nextIndex);
|
256
|
+
if (!fullPath) {
|
257
|
+
nextIndex = 0;
|
258
|
+
fullPath = this._pageState.getFullPath(nextIndex);
|
259
|
+
}
|
260
|
+
if (fullPath) {
|
261
|
+
this.setFullPath(fullPath);
|
262
|
+
}
|
263
|
+
this.setViewFocusScenePath();
|
264
|
+
if (this.view) {
|
265
|
+
this.view.focusSceneIndex = nextIndex;
|
266
|
+
}
|
267
|
+
}
|
268
|
+
}
|
269
|
+
|
251
270
|
public getAppInitState = (id: string) => {
|
252
271
|
const attrs = this.store.getAppState(id);
|
253
272
|
if (!attrs) return;
|
@@ -348,7 +367,10 @@ export class AppProxy {
|
|
348
367
|
return autorun(() => {
|
349
368
|
const fullPath = this.appAttributes?.fullPath;
|
350
369
|
this.setFocusScenePathHandler(fullPath);
|
351
|
-
this.
|
370
|
+
if (this._prevFullPath !== fullPath) {
|
371
|
+
this.notifyPageStateChange();
|
372
|
+
this._prevFullPath = fullPath;
|
373
|
+
}
|
352
374
|
});
|
353
375
|
});
|
354
376
|
};
|
@@ -381,14 +403,47 @@ export class AppProxy {
|
|
381
403
|
return view;
|
382
404
|
}
|
383
405
|
|
384
|
-
public notifyPageStateChange = () => {
|
406
|
+
public notifyPageStateChange = debounce(() => {
|
385
407
|
this.appEmitter.emit("pageStateChange", this.pageState);
|
386
|
-
};
|
408
|
+
}, 50);
|
387
409
|
|
388
410
|
public get pageState(): PageState {
|
389
411
|
return this._pageState.toObject();
|
390
412
|
}
|
391
413
|
|
414
|
+
// PageRemoveService
|
415
|
+
public async removeSceneByIndex(index: number) {
|
416
|
+
const scenePath = this._pageState.getFullPath(index);
|
417
|
+
if (scenePath) {
|
418
|
+
// 不能删除所有场景
|
419
|
+
if (this.pageState.length <= 1) {
|
420
|
+
return false;
|
421
|
+
}
|
422
|
+
const nextIndex = calculateNextIndex(index, this.pageState);
|
423
|
+
// 只修改 focus path 不修改 FullPath
|
424
|
+
this.setSceneIndexWithoutSync(nextIndex);
|
425
|
+
this.manager.dispatchInternalEvent(Events.SetAppFocusIndex, {
|
426
|
+
type: "app",
|
427
|
+
appID: this.id,
|
428
|
+
index: nextIndex,
|
429
|
+
});
|
430
|
+
// 手动添加一个延迟, 让 app 切换场景后再删除以避免闪烁
|
431
|
+
setTimeout(() => {
|
432
|
+
removeScenes(this.manager.room, scenePath, index);
|
433
|
+
}, 100);
|
434
|
+
return true;
|
435
|
+
} else {
|
436
|
+
return false;
|
437
|
+
}
|
438
|
+
}
|
439
|
+
|
440
|
+
public setSceneIndexWithoutSync(index: number) {
|
441
|
+
if (this.view) {
|
442
|
+
this.view.focusSceneIndex = index;
|
443
|
+
}
|
444
|
+
}
|
445
|
+
// PageRemoveService end
|
446
|
+
|
392
447
|
public setSceneIndex(index: number) {
|
393
448
|
if (this.view) {
|
394
449
|
this.view.focusSceneIndex = index;
|
@@ -432,6 +487,7 @@ export class AppProxy {
|
|
432
487
|
this.manager.refresher?.remove(this.id);
|
433
488
|
this.manager.refresher?.remove(this.stateKey);
|
434
489
|
this.manager.refresher?.remove(`${this.id}-fullPath`);
|
490
|
+
this._prevFullPath = undefined;
|
435
491
|
}
|
436
492
|
|
437
493
|
public close(): Promise<void> {
|
package/src/App/Storage/index.ts
CHANGED
@@ -37,15 +37,21 @@ 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.
|
41
|
-
if (
|
42
|
-
if (
|
43
|
-
|
40
|
+
if (this._context.getIsWritable()) {
|
41
|
+
if (this.id === null) {
|
42
|
+
if (context.isAddApp && defaultState) {
|
43
|
+
this.setState(defaultState);
|
44
|
+
}
|
45
|
+
} else {
|
46
|
+
if (rawState === this._state || !isObject(rawState)) {
|
47
|
+
if (!get(this._context.getAttributes(), [STORAGE_NS])) {
|
48
|
+
this._context.updateAttributes([STORAGE_NS], {});
|
49
|
+
}
|
50
|
+
this._context.updateAttributes([STORAGE_NS, this.id], this._state);
|
51
|
+
if (defaultState) {
|
52
|
+
this.setState(defaultState);
|
53
|
+
}
|
44
54
|
}
|
45
|
-
this._context.updateAttributes([STORAGE_NS, this.id], this._state);
|
46
|
-
}
|
47
|
-
if (defaultState) {
|
48
|
-
this.setState(defaultState);
|
49
55
|
}
|
50
56
|
}
|
51
57
|
|
package/src/AppListener.ts
CHANGED
@@ -6,6 +6,13 @@ import { setViewFocusScenePath } from "./Utils/Common";
|
|
6
6
|
import type { AnimationMode, Camera, Event } from "white-web-sdk";
|
7
7
|
import type { AppManager } from "./AppManager";
|
8
8
|
import type { TeleBoxState } from "@netless/telebox-insider";
|
9
|
+
|
10
|
+
type SetAppFocusIndex = {
|
11
|
+
type: "main" | "app";
|
12
|
+
appID?: string;
|
13
|
+
index: number;
|
14
|
+
}
|
15
|
+
|
9
16
|
export class AppListeners {
|
10
17
|
private displayer = this.manager.displayer;
|
11
18
|
|
@@ -67,6 +74,10 @@ export class AppListeners {
|
|
67
74
|
this.initMainViewCameraHandler();
|
68
75
|
break;
|
69
76
|
}
|
77
|
+
case Events.SetAppFocusIndex: {
|
78
|
+
this.setAppFocusViewIndexHandler(data.payload);
|
79
|
+
break;
|
80
|
+
}
|
70
81
|
default:
|
71
82
|
break;
|
72
83
|
}
|
@@ -119,4 +130,15 @@ export class AppListeners {
|
|
119
130
|
private initMainViewCameraHandler = () => {
|
120
131
|
this.manager.mainViewProxy.addCameraReaction();
|
121
132
|
}
|
133
|
+
|
134
|
+
private setAppFocusViewIndexHandler = (payload: SetAppFocusIndex) => {
|
135
|
+
if (payload.type === "main") {
|
136
|
+
this.manager.setSceneIndexWithoutSync(payload.index);
|
137
|
+
} else if (payload.type === "app" && payload.appID) {
|
138
|
+
const app = this.manager.appProxies.get(payload.appID);
|
139
|
+
if (app) {
|
140
|
+
app.setSceneIndexWithoutSync(payload.index);
|
141
|
+
}
|
142
|
+
}
|
143
|
+
}
|
122
144
|
}
|
package/src/AppManager.ts
CHANGED
@@ -6,7 +6,7 @@ import { appRegister } from "./Register";
|
|
6
6
|
import { autorun, isPlayer, isRoom, ScenePathType } from "white-web-sdk";
|
7
7
|
import { callbacks } from "./callback";
|
8
8
|
import { debounce, get, isInteger, orderBy } from "lodash";
|
9
|
-
import { emitter } from "./InternalEmitter";
|
9
|
+
import { emitter, RemoveSceneParams } from "./InternalEmitter";
|
10
10
|
import { Fields, store } from "./AttributesDelegate";
|
11
11
|
import { log } from "./Utils/log";
|
12
12
|
import { MainViewProxy } from "./View/MainView";
|
@@ -20,8 +20,10 @@ import type { EmitterEvent } from "./InternalEmitter";
|
|
20
20
|
import {
|
21
21
|
entireScenes,
|
22
22
|
genAppId,
|
23
|
+
isRootDirPage,
|
23
24
|
makeValidScenePath,
|
24
25
|
parseSceneDir,
|
26
|
+
removeScenes,
|
25
27
|
setScenePath,
|
26
28
|
setViewFocusScenePath,
|
27
29
|
} from "./Utils/Common";
|
@@ -35,6 +37,7 @@ import type {
|
|
35
37
|
SceneState,
|
36
38
|
} from "white-web-sdk";
|
37
39
|
import type { AddAppParams, BaseInsertParams, TeleBoxRect } from "./index";
|
40
|
+
import { calculateNextIndex } from "./Page";
|
38
41
|
|
39
42
|
export class AppManager {
|
40
43
|
public displayer: Displayer;
|
@@ -108,20 +111,29 @@ export class AppManager {
|
|
108
111
|
});
|
109
112
|
}
|
110
113
|
|
111
|
-
private onRemoveScenes = async (
|
114
|
+
private onRemoveScenes = async (params: RemoveSceneParams) => {
|
115
|
+
const { scenePath } = params;
|
112
116
|
// 如果移除根目录就把 scenePath 设置为初始值
|
113
117
|
if (scenePath === ROOT_DIR) {
|
114
118
|
await this.onRootDirRemoved();
|
115
119
|
this.dispatchInternalEvent(Events.RootDirRemoved);
|
116
120
|
return;
|
117
121
|
}
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
if (
|
122
|
-
|
123
|
-
this.
|
122
|
+
if (isRootDirPage(scenePath)) {
|
123
|
+
let nextIndex = this.mainView.focusSceneIndex || 0;
|
124
|
+
let sceneName = this.callbacksNode?.scenes[nextIndex];
|
125
|
+
if (!sceneName) {
|
126
|
+
nextIndex = 0;
|
127
|
+
sceneName = this.callbacksNode?.scenes[nextIndex];
|
124
128
|
}
|
129
|
+
if (sceneName) {
|
130
|
+
this.setMainViewScenePath(`${ROOT_DIR}${sceneName}`);
|
131
|
+
}
|
132
|
+
await this.setMainViewSceneIndex(nextIndex);
|
133
|
+
} else {
|
134
|
+
this.appProxies.forEach(app => {
|
135
|
+
app.onRemoveScene(scenePath);
|
136
|
+
});
|
125
137
|
}
|
126
138
|
};
|
127
139
|
|
@@ -180,6 +192,26 @@ export class AppManager {
|
|
180
192
|
}
|
181
193
|
};
|
182
194
|
|
195
|
+
public removeSceneByIndex = async (index: number) => {
|
196
|
+
const nextIndex = calculateNextIndex(index, this.windowManger.pageState);
|
197
|
+
this.setSceneIndexWithoutSync(nextIndex);
|
198
|
+
this.dispatchInternalEvent(Events.SetAppFocusIndex, { type: "main", index: nextIndex });
|
199
|
+
setTimeout(() => {
|
200
|
+
const scene = this.callbacksNode?.scenes[index];
|
201
|
+
if (scene) {
|
202
|
+
removeScenes(this.room, `${ROOT_DIR}${scene}`, index)
|
203
|
+
}
|
204
|
+
}, 100);
|
205
|
+
return true;
|
206
|
+
}
|
207
|
+
|
208
|
+
public setSceneIndexWithoutSync = (index: number) => {
|
209
|
+
const sceneName = this.callbacksNode?.scenes[index];
|
210
|
+
if (sceneName) {
|
211
|
+
this.mainViewProxy.setFocusScenePath(`${ROOT_DIR}${sceneName}`);
|
212
|
+
}
|
213
|
+
}
|
214
|
+
|
183
215
|
private onSceneChange = (node: ScenesCallbacksNode) => {
|
184
216
|
this.mainViewScenesLength = node.scenes.length;
|
185
217
|
this.updateSceneState(node);
|
@@ -193,7 +225,10 @@ export class AppManager {
|
|
193
225
|
|
194
226
|
private updateSceneState = (node: ScenesCallbacksNode) => {
|
195
227
|
const currentIndex = this.store.getMainViewSceneIndex() || 0;
|
196
|
-
|
228
|
+
let sceneName = node.scenes[currentIndex];
|
229
|
+
if (!sceneName) {
|
230
|
+
sceneName = node.scenes[this.mainView.focusSceneIndex || 0];
|
231
|
+
}
|
197
232
|
this.sceneState = {
|
198
233
|
scenePath: `${ROOT_DIR}${sceneName}`,
|
199
234
|
contextPath: node.path,
|
@@ -322,6 +357,7 @@ export class AppManager {
|
|
322
357
|
});
|
323
358
|
};
|
324
359
|
|
360
|
+
|
325
361
|
private onMainViewIndexChange = (index: number) => {
|
326
362
|
if (index !== undefined && this._prevSceneIndex !== index) {
|
327
363
|
callbacks.emit("mainViewSceneIndexChange", index);
|
@@ -472,8 +508,8 @@ export class AppManager {
|
|
472
508
|
public setMainViewFocusPath(scenePath?: string) {
|
473
509
|
const focusScenePath = scenePath || this.store.getMainViewScenePath();
|
474
510
|
if (focusScenePath) {
|
475
|
-
|
476
|
-
return
|
511
|
+
setViewFocusScenePath(this.mainView, focusScenePath);
|
512
|
+
return this.mainView?.focusScenePath === focusScenePath;
|
477
513
|
}
|
478
514
|
}
|
479
515
|
|
@@ -643,20 +679,17 @@ export class AppManager {
|
|
643
679
|
public async setMainViewSceneIndex(index: number) {
|
644
680
|
if (this.room) {
|
645
681
|
if (this.store.getMainViewSceneIndex() === index) return;
|
646
|
-
const
|
647
|
-
|
648
|
-
|
649
|
-
const
|
650
|
-
if (
|
651
|
-
|
652
|
-
|
653
|
-
|
654
|
-
this.safeSetAttributes({ _mainSceneIndex: index });
|
655
|
-
this.dispatchSetMainViewScenePath(scenePath);
|
656
|
-
}
|
657
|
-
} else {
|
658
|
-
throw new Error(`[WindowManager]: ${sceneDir}: ${index} not valid index`);
|
682
|
+
const sceneName = this.callbacksNode?.scenes[index];
|
683
|
+
const scenePath =`${ROOT_DIR}${sceneName}`;
|
684
|
+
if (sceneName) {
|
685
|
+
const success = this.setMainViewFocusPath(scenePath);
|
686
|
+
if (success) {
|
687
|
+
this.store.setMainViewScenePath(scenePath);
|
688
|
+
this.safeSetAttributes({ _mainSceneIndex: index });
|
689
|
+
this.dispatchSetMainViewScenePath(scenePath);
|
659
690
|
}
|
691
|
+
} else {
|
692
|
+
throw new Error(`[WindowManager]: ${index} not valid index`);
|
660
693
|
}
|
661
694
|
}
|
662
695
|
}
|
@@ -1,11 +1,14 @@
|
|
1
1
|
import { ResizeObserver as ResizeObserverPolyfill } from "@juggle/resize-observer";
|
2
|
+
import { isFunction } from "lodash";
|
2
3
|
import { WindowManager } from "./index";
|
3
4
|
import type { EmitterType } from "./InternalEmitter";
|
5
|
+
import type { UnsubscribeFn } from "emittery";
|
4
6
|
|
5
7
|
const ResizeObserver = window.ResizeObserver || ResizeObserverPolyfill;
|
6
8
|
|
7
9
|
export class ContainerResizeObserver {
|
8
10
|
private containerResizeObserver?: ResizeObserver;
|
11
|
+
private disposer?: UnsubscribeFn;
|
9
12
|
|
10
13
|
constructor(private emitter: EmitterType) {}
|
11
14
|
|
@@ -35,10 +38,14 @@ export class ContainerResizeObserver {
|
|
35
38
|
}
|
36
39
|
});
|
37
40
|
|
41
|
+
this.disposer = this.emitter.on("containerSizeRatioUpdate", () => {
|
42
|
+
this.updateSizer(container.getBoundingClientRect(), sizer, wrapper);
|
43
|
+
});
|
44
|
+
|
38
45
|
this.containerResizeObserver.observe(container);
|
39
46
|
}
|
40
47
|
|
41
|
-
|
48
|
+
public updateSizer(
|
42
49
|
{ width, height }: DOMRectReadOnly,
|
43
50
|
sizer: HTMLElement,
|
44
51
|
wrapper: HTMLDivElement
|
@@ -58,5 +65,9 @@ export class ContainerResizeObserver {
|
|
58
65
|
|
59
66
|
public disconnect() {
|
60
67
|
this.containerResizeObserver?.disconnect();
|
68
|
+
if (isFunction(this.disposer)) {
|
69
|
+
this.disposer();
|
70
|
+
this.disposer = undefined;
|
71
|
+
}
|
61
72
|
}
|
62
73
|
}
|
package/src/InternalEmitter.ts
CHANGED
@@ -1,6 +1,9 @@
|
|
1
1
|
import Emittery from "emittery";
|
2
2
|
import type { AppInitState, CursorMovePayload } from "./index";
|
3
3
|
|
4
|
+
export type RemoveSceneParams = {
|
5
|
+
scenePath: string, index?: number
|
6
|
+
}
|
4
7
|
|
5
8
|
export type EmitterEvent = {
|
6
9
|
onCreated: undefined;
|
@@ -16,8 +19,9 @@ export type EmitterEvent = {
|
|
16
19
|
observerIdChange: number;
|
17
20
|
boxStateChange: string;
|
18
21
|
playgroundSizeChange: DOMRect;
|
19
|
-
|
20
|
-
|
22
|
+
startReconnect: undefined;
|
23
|
+
onReconnected: undefined;
|
24
|
+
removeScenes: RemoveSceneParams;
|
21
25
|
cursorMove: CursorMovePayload;
|
22
26
|
updateManagerRect: undefined;
|
23
27
|
focusedChange: { focused: string | undefined; prev: string | undefined };
|
@@ -25,6 +29,7 @@ export type EmitterEvent = {
|
|
25
29
|
setReadonly: boolean;
|
26
30
|
changePageState: undefined;
|
27
31
|
writableChange: boolean;
|
32
|
+
containerSizeRatioUpdate: number;
|
28
33
|
};
|
29
34
|
|
30
35
|
export type EmitterType = Emittery<EmitterEvent>;
|
@@ -14,5 +14,11 @@ export interface PageController {
|
|
14
14
|
nextPage: () => Promise<boolean>;
|
15
15
|
prevPage: () => Promise<boolean>;
|
16
16
|
addPage: (params?: AddPageParams) => Promise<void>;
|
17
|
+
removePage: (index: number) => Promise<boolean>;
|
17
18
|
pageState: PageState;
|
18
19
|
}
|
20
|
+
|
21
|
+
export interface PageRemoveService {
|
22
|
+
removeSceneByIndex: (index: number) => Promise<boolean>;
|
23
|
+
setSceneIndexWithoutSync: (index: number) => void;
|
24
|
+
}
|
package/src/Page/index.ts
CHANGED
@@ -1 +1,19 @@
|
|
1
|
+
import type { PageState } from "./PageController";
|
2
|
+
|
1
3
|
export * from "./PageController";
|
4
|
+
|
5
|
+
export const calculateNextIndex = (index: number, pageState: PageState) => {
|
6
|
+
let nextIndex = 0;
|
7
|
+
if (index === 0) {
|
8
|
+
return index + 1;
|
9
|
+
}
|
10
|
+
if (pageState.index !== 0 && index !== 0) {
|
11
|
+
const maxIndex = pageState.length - 1;
|
12
|
+
if (index === maxIndex) {
|
13
|
+
nextIndex = maxIndex - 1;
|
14
|
+
} else if (index > 0 && index < maxIndex) {
|
15
|
+
nextIndex = index + 1;
|
16
|
+
}
|
17
|
+
}
|
18
|
+
return nextIndex;
|
19
|
+
}
|
package/src/PageState.ts
CHANGED
@@ -29,6 +29,9 @@ export class ReconnectRefresher {
|
|
29
29
|
}
|
30
30
|
|
31
31
|
private onPhaseChanged = (phase: RoomPhase) => {
|
32
|
+
if (phase === RoomPhase.Reconnecting) {
|
33
|
+
this.ctx.emitter.emit("startReconnect");
|
34
|
+
}
|
32
35
|
if (phase === RoomPhase.Connected && this.phase === RoomPhase.Reconnecting) {
|
33
36
|
this.onReconnected();
|
34
37
|
}
|
@@ -47,7 +50,7 @@ export class ReconnectRefresher {
|
|
47
50
|
this.disposers.set(id, func());
|
48
51
|
}
|
49
52
|
});
|
50
|
-
this.ctx.emitter.emit("onReconnected"
|
53
|
+
this.ctx.emitter.emit("onReconnected");
|
51
54
|
}
|
52
55
|
|
53
56
|
private releaseDisposers() {
|
package/src/Utils/Common.ts
CHANGED
@@ -53,11 +53,11 @@ export const getScenePath = (
|
|
53
53
|
}
|
54
54
|
};
|
55
55
|
|
56
|
-
export const removeScenes = (room: Room | undefined, scenePath: string) => {
|
56
|
+
export const removeScenes = (room: Room | undefined, scenePath: string, index?: number) => {
|
57
57
|
if (room) {
|
58
58
|
const type = room.scenePathType(scenePath);
|
59
59
|
if (type !== ScenePathType.None) {
|
60
|
-
room.removeScenes(scenePath);
|
60
|
+
(room.removeScenes as any)(scenePath, index);
|
61
61
|
}
|
62
62
|
}
|
63
63
|
};
|
@@ -140,3 +140,15 @@ export const getVersionNumber = (version: string) => {
|
|
140
140
|
};
|
141
141
|
|
142
142
|
export const wait = (time: number) => new Promise(resolve => setTimeout(resolve, time));
|
143
|
+
|
144
|
+
// rootDirPage: /page1 || / page2
|
145
|
+
// notRootDirPage: /dir1/page1 || /dir1/page2
|
146
|
+
export const isRootDirPage = (scenePath: string) => {
|
147
|
+
const delimiterCount = scenePath.split("").reduce((prev, cur) => {
|
148
|
+
if (cur === ROOT_DIR) {
|
149
|
+
prev += 1;
|
150
|
+
}
|
151
|
+
return prev;
|
152
|
+
}, 0);
|
153
|
+
return delimiterCount === 1;
|
154
|
+
}
|
package/src/Utils/RoomHacker.ts
CHANGED
@@ -61,12 +61,12 @@ export const replaceRoomFunction = (room: Room | Player, manager: WindowManager)
|
|
61
61
|
|
62
62
|
const delegateRemoveScenes = (room: Room, manager: WindowManager) => {
|
63
63
|
const originRemoveScenes = room.removeScenes;
|
64
|
-
room.removeScenes = (scenePath: string) => {
|
64
|
+
room.removeScenes = (scenePath: string, index?: number) => {
|
65
65
|
if (scenePath === ROOT_DIR) {
|
66
66
|
manager.appManager?.updateRootDirRemoving(true);
|
67
67
|
}
|
68
68
|
const result = originRemoveScenes.call(room, scenePath);
|
69
|
-
emitter.emit("removeScenes", scenePath);
|
69
|
+
emitter.emit("removeScenes", { scenePath, index });
|
70
70
|
return result;
|
71
71
|
};
|
72
72
|
};
|
package/src/Utils/error.ts
CHANGED
@@ -34,3 +34,7 @@ export class InvalidScenePath extends Error {
|
|
34
34
|
export class BoxManagerNotFoundError extends Error {
|
35
35
|
override message = "[WindowManager]: boxManager not found";
|
36
36
|
}
|
37
|
+
|
38
|
+
export class BindContainerRoomPhaseInvalidError extends Error {
|
39
|
+
override message = "[WindowManager]: room phase only Connected can be bindContainer";
|
40
|
+
}
|
package/src/View/MainView.ts
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
import { AnimationMode, reaction } from "white-web-sdk";
|
2
2
|
import { callbacks } from "../callback";
|
3
3
|
import { createView } from "./ViewManager";
|
4
|
-
import { debounce, isEmpty, isEqual } from "lodash";
|
4
|
+
import { debounce, get, isEmpty, isEqual } from "lodash";
|
5
5
|
import { emitter } from "../InternalEmitter";
|
6
6
|
import { Fields } from "../AttributesDelegate";
|
7
7
|
import { setViewFocusScenePath } from "../Utils/Common";
|
@@ -32,8 +32,15 @@ export class MainViewProxy {
|
|
32
32
|
this.sizeChangeHandler(this.mainViewSize);
|
33
33
|
};
|
34
34
|
this.sideEffectManager.add(() => {
|
35
|
-
emitter.on("playgroundSizeChange", playgroundSizeChangeListener);
|
36
|
-
|
35
|
+
return emitter.on("playgroundSizeChange", playgroundSizeChangeListener);
|
36
|
+
});
|
37
|
+
this.sideEffectManager.add(() => {
|
38
|
+
return emitter.on("containerSizeRatioUpdate", this.onUpdateContainerSizeRatio);
|
39
|
+
});
|
40
|
+
this.sideEffectManager.add(() => {
|
41
|
+
return emitter.on("startReconnect", () => {
|
42
|
+
this.mainView.release();
|
43
|
+
});
|
37
44
|
});
|
38
45
|
}
|
39
46
|
|
@@ -62,6 +69,10 @@ export class MainViewProxy {
|
|
62
69
|
return this.store.getMainViewSize();
|
63
70
|
}
|
64
71
|
|
72
|
+
private get didRelease(): boolean {
|
73
|
+
return get(this.view, ["didRelease"]);
|
74
|
+
}
|
75
|
+
|
65
76
|
private moveCameraSizeByAttributes() {
|
66
77
|
this.moveCameraToContian(this.mainViewSize);
|
67
78
|
this.moveCamera(this.mainViewCamera);
|
@@ -98,13 +109,21 @@ export class MainViewProxy {
|
|
98
109
|
);
|
99
110
|
};
|
100
111
|
|
101
|
-
|
112
|
+
public sizeChangeHandler = debounce((size: Size) => {
|
102
113
|
if (size) {
|
103
114
|
this.moveCameraToContian(size);
|
104
115
|
this.moveCamera(this.mainViewCamera);
|
105
116
|
}
|
106
117
|
}, 30);
|
107
118
|
|
119
|
+
public onUpdateContainerSizeRatio = () => {
|
120
|
+
const size = this.store.getMainViewSize();
|
121
|
+
this.sizeChangeHandler(size);
|
122
|
+
if (size.id === this.manager.uid) {
|
123
|
+
this.setCameraAndSize();
|
124
|
+
}
|
125
|
+
}
|
126
|
+
|
108
127
|
public get view(): View {
|
109
128
|
return this.mainView;
|
110
129
|
}
|
@@ -123,9 +142,17 @@ export class MainViewProxy {
|
|
123
142
|
}
|
124
143
|
|
125
144
|
public onReconnect(): void {
|
126
|
-
|
127
|
-
|
128
|
-
|
145
|
+
if (this.didRelease) {
|
146
|
+
this.rebind();
|
147
|
+
} else {
|
148
|
+
const mainViewScenePath = this.store.getMainViewScenePath();
|
149
|
+
this.setFocusScenePath(mainViewScenePath);
|
150
|
+
}
|
151
|
+
}
|
152
|
+
|
153
|
+
public setFocusScenePath(path: string | undefined) {
|
154
|
+
if (path) {
|
155
|
+
return setViewFocusScenePath(this.view, path);
|
129
156
|
}
|
130
157
|
}
|
131
158
|
|
@@ -133,7 +160,9 @@ export class MainViewProxy {
|
|
133
160
|
const divElement = this.mainView.divElement;
|
134
161
|
const disableCameraTransform = this.mainView.disableCameraTransform;
|
135
162
|
this.stop();
|
136
|
-
this.
|
163
|
+
if (!this.didRelease) {
|
164
|
+
this.mainView.release();
|
165
|
+
}
|
137
166
|
this.removeMainViewListener();
|
138
167
|
this.mainView = this.createMainView();
|
139
168
|
this.mainView.disableCameraTransform = disableCameraTransform;
|