@netless/window-manager 0.4.26 → 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/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 (scenePath: string) => {
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
- // 如果移除的 path 跟 MainViewScenePath 相同就取当前目录的当前 index
119
- const mainViewScenePath = this.store.getMainViewScenePath();
120
- if (this.room && mainViewScenePath) {
121
- if (mainViewScenePath === scenePath) {
122
- const nextPath = this.callbacksNode?.scenes[this.store.getMainViewSceneIndex()];
123
- this.setMainViewScenePath(`/${nextPath}` || INIT_DIR);
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
- const sceneName = node.scenes[currentIndex];
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
- const view = setViewFocusScenePath(this.mainView, focusScenePath);
476
- return view?.focusScenePath === focusScenePath;
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 mainViewScenePath = this.store.getMainViewScenePath() as string;
647
- if (mainViewScenePath) {
648
- const sceneDir = parseSceneDir(mainViewScenePath);
649
- const scenePath = makeValidScenePath(this.displayer, sceneDir, index);
650
- if (scenePath) {
651
- const success = this.setMainViewFocusPath(scenePath);
652
- if (success) {
653
- this.store.setMainViewScenePath(scenePath);
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,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;
@@ -18,7 +21,7 @@ export type EmitterEvent = {
18
21
  playgroundSizeChange: DOMRect;
19
22
  startReconnect: undefined;
20
23
  onReconnected: undefined;
21
- removeScenes: string;
24
+ removeScenes: RemoveSceneParams;
22
25
  cursorMove: CursorMovePayload;
23
26
  updateManagerRect: undefined;
24
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,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
@@ -19,8 +19,9 @@ export class PageStateImpl {
19
19
  }
20
20
 
21
21
  public toObject(): PageState {
22
+ const index = this.index >= this.length ? this.length - 1 : this.index;
22
23
  return {
23
- index: this.index,
24
+ index,
24
25
  length: this.length,
25
26
  };
26
27
  }
@@ -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
+ }
@@ -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
  };
@@ -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
+ }
@@ -146,9 +146,13 @@ export class MainViewProxy {
146
146
  this.rebind();
147
147
  } else {
148
148
  const mainViewScenePath = this.store.getMainViewScenePath();
149
- if (mainViewScenePath) {
150
- setViewFocusScenePath(this.view, mainViewScenePath);
151
- }
149
+ this.setFocusScenePath(mainViewScenePath);
150
+ }
151
+ }
152
+
153
+ public setFocusScenePath(path: string | undefined) {
154
+ if (path) {
155
+ return setViewFocusScenePath(this.view, path);
152
156
  }
153
157
  }
154
158
 
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";