@netless/window-manager 0.4.25 → 0.4.27
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 +10 -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/InternalEmitter.d.ts +7 -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 +2 -0
- 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 +1 -0
- package/dist/index.es.js +233 -56
- 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 +17 -0
- package/docs/api.md +9 -0
- package/docs/app-context.md +149 -100
- package/package.json +1 -1
- 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/InternalEmitter.ts +6 -2
- package/src/Page/PageController.ts +6 -0
- package/src/Page/index.ts +17 -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 +24 -5
- package/src/constants.ts +1 -0
- package/src/index.ts +16 -0
- package/src/typings.ts +1 -0
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
|
}
|
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 };
|
@@ -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,18 @@
|
|
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
|
+
const maxIndex = pageState.length - 1;
|
8
|
+
if (index === pageState.index) {
|
9
|
+
if (index === maxIndex) {
|
10
|
+
nextIndex = index - 1;
|
11
|
+
} else {
|
12
|
+
nextIndex = pageState.index + 1;
|
13
|
+
}
|
14
|
+
} else {
|
15
|
+
nextIndex = pageState.index;
|
16
|
+
}
|
17
|
+
return nextIndex;
|
18
|
+
}
|
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";
|
@@ -37,6 +37,11 @@ export class MainViewProxy {
|
|
37
37
|
this.sideEffectManager.add(() => {
|
38
38
|
return emitter.on("containerSizeRatioUpdate", this.onUpdateContainerSizeRatio);
|
39
39
|
});
|
40
|
+
this.sideEffectManager.add(() => {
|
41
|
+
return emitter.on("startReconnect", () => {
|
42
|
+
this.mainView.release();
|
43
|
+
});
|
44
|
+
});
|
40
45
|
}
|
41
46
|
|
42
47
|
private startListenWritableChange = () => {
|
@@ -64,6 +69,10 @@ export class MainViewProxy {
|
|
64
69
|
return this.store.getMainViewSize();
|
65
70
|
}
|
66
71
|
|
72
|
+
private get didRelease(): boolean {
|
73
|
+
return get(this.view, ["didRelease"]);
|
74
|
+
}
|
75
|
+
|
67
76
|
private moveCameraSizeByAttributes() {
|
68
77
|
this.moveCameraToContian(this.mainViewSize);
|
69
78
|
this.moveCamera(this.mainViewCamera);
|
@@ -133,9 +142,17 @@ export class MainViewProxy {
|
|
133
142
|
}
|
134
143
|
|
135
144
|
public onReconnect(): void {
|
136
|
-
|
137
|
-
|
138
|
-
|
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);
|
139
156
|
}
|
140
157
|
}
|
141
158
|
|
@@ -143,7 +160,9 @@ export class MainViewProxy {
|
|
143
160
|
const divElement = this.mainView.divElement;
|
144
161
|
const disableCameraTransform = this.mainView.disableCameraTransform;
|
145
162
|
this.stop();
|
146
|
-
this.
|
163
|
+
if (!this.didRelease) {
|
164
|
+
this.mainView.release();
|
165
|
+
}
|
147
166
|
this.removeMainViewListener();
|
148
167
|
this.mainView = this.createMainView();
|
149
168
|
this.mainView.disableCameraTransform = disableCameraTransform;
|
package/src/constants.ts
CHANGED
@@ -9,6 +9,7 @@ export enum Events {
|
|
9
9
|
WindowCreated = "WindowCreated",
|
10
10
|
SetMainViewScenePath = "SetMainViewScenePath",
|
11
11
|
SetMainViewSceneIndex = "SetMainViewSceneIndex",
|
12
|
+
SetAppFocusIndex = "SetAppFocusIndex",
|
12
13
|
SwitchViewsToFreedom = "SwitchViewsToFreedom",
|
13
14
|
MoveCamera = "MoveCamera",
|
14
15
|
MoveCameraToContain = "MoveCameraToContain",
|
package/src/index.ts
CHANGED
@@ -32,6 +32,7 @@ import type { TELE_BOX_STATE, BoxManager } from "./BoxManager";
|
|
32
32
|
import {
|
33
33
|
AppCreateError,
|
34
34
|
AppManagerNotInitError,
|
35
|
+
BindContainerRoomPhaseInvalidError,
|
35
36
|
InvalidScenePath,
|
36
37
|
ParamsInvalidError,
|
37
38
|
} from "./Utils/error";
|
@@ -319,6 +320,9 @@ export class WindowManager extends InvisiblePlugin<WindowMangerAttributes> imple
|
|
319
320
|
}
|
320
321
|
|
321
322
|
public bindContainer(container: HTMLElement) {
|
323
|
+
if (this.room.phase !== RoomPhase.Connected) {
|
324
|
+
throw new BindContainerRoomPhaseInvalidError();
|
325
|
+
}
|
322
326
|
if (WindowManager.isCreated && WindowManager.container) {
|
323
327
|
if (WindowManager.container.firstChild) {
|
324
328
|
container.appendChild(WindowManager.container.firstChild);
|
@@ -533,6 +537,18 @@ export class WindowManager extends InvisiblePlugin<WindowMangerAttributes> imple
|
|
533
537
|
}
|
534
538
|
}
|
535
539
|
|
540
|
+
public async removePage(index: number): Promise<boolean> {
|
541
|
+
if (this.appManager) {
|
542
|
+
if (index < 0 || index >= this.pageState.length) {
|
543
|
+
console.warn(`[WindowManager]: index ${index} out of range`);
|
544
|
+
return false;
|
545
|
+
}
|
546
|
+
return this.appManager.removeSceneByIndex(index);;
|
547
|
+
} else {
|
548
|
+
return false;
|
549
|
+
}
|
550
|
+
}
|
551
|
+
|
536
552
|
/**
|
537
553
|
* 返回 mainView 的 ScenePath
|
538
554
|
*/
|
package/src/typings.ts
CHANGED
@@ -80,3 +80,4 @@ export type { ReadonlyTeleBox, TeleBoxRect };
|
|
80
80
|
export type { SceneState, SceneDefinition, View, AnimationMode, Displayer, Room, Player };
|
81
81
|
export type { Storage, StorageStateChangedEvent, StorageStateChangedListener } from "./App/Storage";
|
82
82
|
export * from "./Page";
|
83
|
+
export * from "./Utils/error";
|