@netless/window-manager 0.4.0-canary.2 → 0.4.0-canary.23
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/.idea/inspectionProfiles/Project_Default.xml +7 -0
- package/.idea/modules.xml +8 -0
- package/.idea/vcs.xml +6 -0
- package/.idea/window-manager.iml +12 -0
- package/.vscode/settings.json +1 -0
- package/CHANGELOG.md +29 -1
- package/README.md +1 -0
- package/dist/App/MagixEvent/index.d.ts +29 -0
- package/dist/App/Storage/StorageEvent.d.ts +8 -0
- package/dist/App/Storage/index.d.ts +39 -0
- package/dist/App/Storage/typings.d.ts +22 -0
- package/dist/App/Storage/utils.d.ts +5 -0
- package/dist/AppContext.d.ts +40 -16
- package/dist/AppListener.d.ts +1 -1
- package/dist/AppManager.d.ts +15 -11
- package/dist/AppProxy.d.ts +7 -6
- package/dist/AttributesDelegate.d.ts +2 -2
- package/dist/BoxManager.d.ts +6 -3
- package/dist/BuiltinApps.d.ts +5 -0
- package/dist/ContainerResizeObserver.d.ts +10 -0
- package/dist/Cursor/Cursor.d.ts +8 -11
- package/dist/Cursor/index.d.ts +5 -16
- package/dist/Helper.d.ts +6 -0
- package/dist/ReconnectRefresher.d.ts +0 -1
- package/dist/Register/storage.d.ts +5 -1
- package/dist/Utils/Common.d.ts +7 -2
- package/dist/Utils/Reactive.d.ts +1 -1
- package/dist/Utils/RoomHacker.d.ts +1 -1
- package/dist/{MainView.d.ts → View/MainView.d.ts} +5 -6
- package/dist/View/ViewManager.d.ts +13 -0
- package/dist/constants.d.ts +3 -7
- package/dist/index.d.ts +25 -10
- package/dist/index.es.js +41 -1
- package/dist/index.es.js.map +1 -1
- package/dist/index.umd.js +41 -1
- package/dist/index.umd.js.map +1 -1
- package/dist/style.css +1 -1
- package/dist/typings.d.ts +3 -2
- package/docs/api.md +36 -6
- package/docs/concept.md +9 -0
- package/package.json +7 -6
- package/src/App/MagixEvent/index.ts +68 -0
- package/src/App/Storage/StorageEvent.ts +21 -0
- package/src/App/Storage/index.ts +289 -0
- package/src/App/Storage/typings.ts +23 -0
- package/src/App/Storage/utils.ts +17 -0
- package/src/AppContext.ts +66 -24
- package/src/AppListener.ts +15 -14
- package/src/AppManager.ts +146 -63
- package/src/AppProxy.ts +52 -53
- package/src/AttributesDelegate.ts +2 -2
- package/src/BoxManager.ts +40 -24
- package/src/BuiltinApps.ts +23 -0
- package/src/ContainerResizeObserver.ts +62 -0
- package/src/Cursor/Cursor.ts +22 -36
- package/src/Cursor/index.ts +39 -139
- package/src/Helper.ts +30 -0
- package/src/ReconnectRefresher.ts +0 -5
- package/src/Register/index.ts +25 -16
- package/src/Register/loader.ts +2 -2
- package/src/Register/storage.ts +6 -1
- package/src/Utils/Common.ts +66 -13
- package/src/Utils/Reactive.ts +9 -3
- package/src/Utils/RoomHacker.ts +42 -13
- package/src/{MainView.ts → View/MainView.ts} +25 -36
- package/src/View/ViewManager.ts +52 -0
- package/src/constants.ts +3 -4
- package/src/index.ts +96 -72
- package/src/shim.d.ts +5 -0
- package/src/style.css +7 -1
- package/src/typings.ts +3 -2
- package/vite.config.js +8 -2
- package/dist/Base/Context.d.ts +0 -13
- package/dist/Base/index.d.ts +0 -7
- package/dist/Utils/CameraStore.d.ts +0 -15
- package/dist/ViewManager.d.ts +0 -29
- package/dist/sdk.d.ts +0 -14
- package/src/Base/Context.ts +0 -49
- package/src/Base/index.ts +0 -10
- package/src/Utils/CameraStore.ts +0 -72
- package/src/sdk.ts +0 -39
- package/src/viewManager.ts +0 -177
package/src/Cursor/index.ts
CHANGED
@@ -1,13 +1,10 @@
|
|
1
|
-
import {
|
2
|
-
import { Base } from "../Base";
|
3
|
-
import { compact, debounce, get, uniq } from "lodash";
|
1
|
+
import { throttle } from "lodash";
|
4
2
|
import { Cursor } from "./Cursor";
|
5
|
-
import { CursorState } from "../constants";
|
3
|
+
import { CursorState, Events } from "../constants";
|
6
4
|
import { emitter, WindowManager } from "../index";
|
7
|
-
import { Fields } from "../AttributesDelegate";
|
8
|
-
import { onObjectInserted } from "../Utils/Reactive";
|
9
5
|
import { SideEffectManager } from "side-effect-manager";
|
10
|
-
import type {
|
6
|
+
import type { CursorMovePayload } from "../index";
|
7
|
+
import type { PositionType } from "../AttributesDelegate";
|
11
8
|
import type { Point, RoomMember, View } from "white-web-sdk";
|
12
9
|
import type { AppManager } from "../AppManager";
|
13
10
|
|
@@ -21,30 +18,42 @@ export type MoveCursorParams = {
|
|
21
18
|
x: number;
|
22
19
|
y: number;
|
23
20
|
};
|
24
|
-
export class CursorManager
|
21
|
+
export class CursorManager {
|
25
22
|
public containerRect?: DOMRect;
|
26
23
|
public wrapperRect?: DOMRect;
|
27
24
|
public cursorInstances: Map<string, Cursor> = new Map();
|
28
25
|
public roomMembers?: readonly RoomMember[];
|
29
26
|
private mainViewElement?: HTMLDivElement;
|
30
27
|
private sideEffectManager = new SideEffectManager();
|
28
|
+
private store = this.manager.store;
|
31
29
|
|
32
|
-
constructor(private
|
33
|
-
|
34
|
-
this.roomMembers = this.appManager.room?.state.roomMembers;
|
30
|
+
constructor(private manager: AppManager) {
|
31
|
+
this.roomMembers = this.manager.room?.state.roomMembers;
|
35
32
|
const wrapper = WindowManager.wrapper;
|
36
33
|
if (wrapper) {
|
37
34
|
this.setupWrapper(wrapper);
|
38
35
|
}
|
39
|
-
emitter.on("
|
40
|
-
this.
|
36
|
+
emitter.on("cursorMove", payload => {
|
37
|
+
let cursorInstance = this.cursorInstances.get(payload.uid);
|
38
|
+
if (!cursorInstance) {
|
39
|
+
cursorInstance = new Cursor(this.manager, payload.uid, this, WindowManager.wrapper);
|
40
|
+
this.cursorInstances.set(payload.uid, cursorInstance);
|
41
|
+
}
|
42
|
+
if (payload.state === CursorState.Leave) {
|
43
|
+
cursorInstance.leave();
|
44
|
+
} else {
|
45
|
+
cursorInstance.move(payload.position);
|
46
|
+
}
|
41
47
|
});
|
48
|
+
this.sideEffectManager.add(() => {
|
49
|
+
const unsubscribe = emitter.on("playgroundSizeChange", () => {
|
50
|
+
this.updateContainerRect();
|
51
|
+
});
|
52
|
+
return unsubscribe;
|
53
|
+
})
|
42
54
|
}
|
43
55
|
|
44
56
|
public setupWrapper(wrapper: HTMLElement) {
|
45
|
-
if (this.manager.refresher?.hasReactor("cursors")) {
|
46
|
-
this.destroy();
|
47
|
-
}
|
48
57
|
this.sideEffectManager.add(() => {
|
49
58
|
wrapper.addEventListener("pointerenter", this.mouseMoveListener);
|
50
59
|
wrapper.addEventListener("pointermove", this.mouseMoveListener);
|
@@ -56,77 +65,38 @@ export class CursorManager extends Base {
|
|
56
65
|
};
|
57
66
|
});
|
58
67
|
|
59
|
-
this.initCursorAttributes();
|
60
68
|
this.wrapperRect = wrapper.getBoundingClientRect();
|
61
|
-
this.startReaction(wrapper);
|
62
69
|
}
|
63
70
|
|
64
71
|
public setMainViewDivElement(div: HTMLDivElement) {
|
65
72
|
this.mainViewElement = div;
|
66
73
|
}
|
67
74
|
|
68
|
-
private startReaction(wrapper: HTMLElement) {
|
69
|
-
this.manager.refresher?.add("cursors", () => {
|
70
|
-
return onObjectInserted(this.cursors, () => {
|
71
|
-
this.handleRoomMembersChange(wrapper);
|
72
|
-
});
|
73
|
-
});
|
74
|
-
}
|
75
|
-
|
76
|
-
private getUids = (members: readonly RoomMember[] | undefined) => {
|
77
|
-
return compact(uniq(members?.map(member => member.payload?.uid)));
|
78
|
-
};
|
79
|
-
|
80
|
-
private handleRoomMembersChange = debounce((wrapper: HTMLElement) => {
|
81
|
-
const uids = this.getUids(this.roomMembers);
|
82
|
-
const cursors = Object.keys(this.cursors);
|
83
|
-
if (uids?.length) {
|
84
|
-
cursors.map(uid => {
|
85
|
-
if (uids.includes(uid) && !this.cursorInstances.has(uid)) {
|
86
|
-
if (uid === this.context.uid) {
|
87
|
-
return;
|
88
|
-
}
|
89
|
-
const component = new Cursor(
|
90
|
-
this.appManager,
|
91
|
-
this.addCursorChangeListener,
|
92
|
-
this.cursors,
|
93
|
-
uid,
|
94
|
-
this,
|
95
|
-
wrapper
|
96
|
-
);
|
97
|
-
this.cursorInstances.set(uid, component);
|
98
|
-
}
|
99
|
-
});
|
100
|
-
}
|
101
|
-
}, 100);
|
102
|
-
|
103
|
-
public get cursors() {
|
104
|
-
return this.manager.attributes?.[Fields.Cursors];
|
105
|
-
}
|
106
|
-
|
107
75
|
public get boxState() {
|
108
76
|
return this.store.getBoxState();
|
109
77
|
}
|
110
78
|
|
111
79
|
public get focusView() {
|
112
|
-
return this.
|
80
|
+
return this.manager.focusApp?.view;
|
113
81
|
}
|
114
82
|
|
115
|
-
private mouseMoveListener =
|
83
|
+
private mouseMoveListener = throttle((event: MouseEvent) => {
|
116
84
|
this.updateCursor(this.getType(event), event.clientX, event.clientY);
|
117
|
-
},
|
85
|
+
}, 16);
|
118
86
|
|
119
87
|
private updateCursor(event: EventType, clientX: number, clientY: number) {
|
120
88
|
if (this.wrapperRect && this.manager.canOperate) {
|
121
|
-
const view = event.type === "main" ? this.
|
89
|
+
const view = event.type === "main" ? this.manager.mainView : this.focusView;
|
122
90
|
const point = this.getPoint(view, clientX, clientY);
|
123
91
|
if (point) {
|
124
|
-
this.
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
92
|
+
this.manager.dispatchInternalEvent(Events.CursorMove, {
|
93
|
+
uid: this.manager.uid,
|
94
|
+
position: {
|
95
|
+
x: point.x,
|
96
|
+
y: point.y,
|
97
|
+
type: event.type,
|
98
|
+
},
|
99
|
+
} as CursorMovePayload);
|
130
100
|
}
|
131
101
|
}
|
132
102
|
}
|
@@ -151,7 +121,7 @@ export class CursorManager extends Base {
|
|
151
121
|
*/
|
152
122
|
private getType = (event: MouseEvent | Touch): EventType => {
|
153
123
|
const target = event.target as HTMLElement;
|
154
|
-
const focusApp = this.
|
124
|
+
const focusApp = this.manager.focusApp;
|
155
125
|
switch (target.parentElement) {
|
156
126
|
case this.mainViewElement: {
|
157
127
|
return { type: "main" };
|
@@ -165,25 +135,8 @@ export class CursorManager extends Base {
|
|
165
135
|
}
|
166
136
|
};
|
167
137
|
|
168
|
-
private initCursorAttributes() {
|
169
|
-
this.store.updateCursor(this.context.uid, {
|
170
|
-
x: 0,
|
171
|
-
y: 0,
|
172
|
-
type: "main",
|
173
|
-
});
|
174
|
-
this.store.updateCursorState(this.context.uid, CursorState.Leave);
|
175
|
-
}
|
176
|
-
|
177
|
-
private setNormalCursorState() {
|
178
|
-
const cursorState = this.store.getCursorState(this.context.uid);
|
179
|
-
if (cursorState !== CursorState.Normal) {
|
180
|
-
this.store.updateCursorState(this.context.uid, CursorState.Normal);
|
181
|
-
}
|
182
|
-
}
|
183
|
-
|
184
138
|
private mouseLeaveListener = () => {
|
185
|
-
this.hideCursor(this.
|
186
|
-
this.store.updateCursorState(this.context.uid, CursorState.Leave);
|
139
|
+
this.hideCursor(this.manager.uid);
|
187
140
|
};
|
188
141
|
|
189
142
|
public updateContainerRect() {
|
@@ -191,16 +144,6 @@ export class CursorManager extends Base {
|
|
191
144
|
this.wrapperRect = WindowManager.wrapper?.getBoundingClientRect();
|
192
145
|
}
|
193
146
|
|
194
|
-
public setRoomMembers(members: readonly RoomMember[]) {
|
195
|
-
this.roomMembers = members;
|
196
|
-
this.cursorInstances.forEach(cursor => {
|
197
|
-
cursor.setMember();
|
198
|
-
});
|
199
|
-
if (WindowManager.wrapper) {
|
200
|
-
this.handleRoomMembersChange(WindowManager.wrapper);
|
201
|
-
}
|
202
|
-
}
|
203
|
-
|
204
147
|
public deleteCursor(uid: string) {
|
205
148
|
this.store.cleanCursor(uid);
|
206
149
|
const cursor = this.cursorInstances.get(uid);
|
@@ -216,48 +159,6 @@ export class CursorManager extends Base {
|
|
216
159
|
}
|
217
160
|
}
|
218
161
|
|
219
|
-
public cleanMemberAttributes(members: readonly RoomMember[]) {
|
220
|
-
const uids = this.getUids(members);
|
221
|
-
const needDeleteIds: string[] = [];
|
222
|
-
const cursors = Object.keys(this.cursors);
|
223
|
-
cursors.map(cursorId => {
|
224
|
-
const index = uids.findIndex(id => id === cursorId);
|
225
|
-
if (index === -1) {
|
226
|
-
needDeleteIds.push(cursorId);
|
227
|
-
}
|
228
|
-
});
|
229
|
-
needDeleteIds.forEach(uid => {
|
230
|
-
this.deleteCursor(uid);
|
231
|
-
});
|
232
|
-
}
|
233
|
-
|
234
|
-
public onReconnect() {
|
235
|
-
if (this.cursorInstances.size) {
|
236
|
-
this.cursorInstances.forEach(cursor => cursor.destroy());
|
237
|
-
this.cursorInstances.clear();
|
238
|
-
}
|
239
|
-
this.roomMembers = this.appManager.room?.state.roomMembers;
|
240
|
-
if (WindowManager.wrapper) {
|
241
|
-
this.handleRoomMembersChange(WindowManager.wrapper);
|
242
|
-
}
|
243
|
-
}
|
244
|
-
|
245
|
-
public addCursorChangeListener = (
|
246
|
-
uid: string,
|
247
|
-
callback: (position: Position, state: CursorState) => void
|
248
|
-
) => {
|
249
|
-
this.manager.refresher?.add(uid, () => {
|
250
|
-
const disposer = autorun(() => {
|
251
|
-
const position = get(this.cursors, [uid, Fields.Position]);
|
252
|
-
const state = get(this.cursors, [uid, Fields.CursorState]);
|
253
|
-
if (position) {
|
254
|
-
callback(position, state);
|
255
|
-
}
|
256
|
-
});
|
257
|
-
return disposer;
|
258
|
-
});
|
259
|
-
};
|
260
|
-
|
261
162
|
public destroy() {
|
262
163
|
this.sideEffectManager.flushAll();
|
263
164
|
if (this.cursorInstances.size) {
|
@@ -266,6 +167,5 @@ export class CursorManager extends Base {
|
|
266
167
|
});
|
267
168
|
this.cursorInstances.clear();
|
268
169
|
}
|
269
|
-
this.manager.refresher?.remove("cursors");
|
270
170
|
}
|
271
171
|
}
|
package/src/Helper.ts
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
import { WindowManager } from "./index";
|
2
|
+
|
3
|
+
export const setupWrapper = (
|
4
|
+
root: HTMLElement
|
5
|
+
): {
|
6
|
+
playground: HTMLDivElement;
|
7
|
+
wrapper: HTMLDivElement;
|
8
|
+
sizer: HTMLDivElement;
|
9
|
+
mainViewElement: HTMLDivElement;
|
10
|
+
} => {
|
11
|
+
const playground = document.createElement("div");
|
12
|
+
playground.className = "netless-window-manager-playground";
|
13
|
+
|
14
|
+
const sizer = document.createElement("div");
|
15
|
+
sizer.className = "netless-window-manager-sizer";
|
16
|
+
|
17
|
+
const wrapper = document.createElement("div");
|
18
|
+
wrapper.className = "netless-window-manager-wrapper";
|
19
|
+
|
20
|
+
const mainViewElement = document.createElement("div");
|
21
|
+
mainViewElement.className = "netless-window-manager-main-view";
|
22
|
+
|
23
|
+
playground.appendChild(sizer);
|
24
|
+
sizer.appendChild(wrapper);
|
25
|
+
wrapper.appendChild(mainViewElement);
|
26
|
+
root.appendChild(playground);
|
27
|
+
WindowManager.wrapper = wrapper;
|
28
|
+
|
29
|
+
return { playground, wrapper, sizer, mainViewElement };
|
30
|
+
};
|
@@ -1,5 +1,4 @@
|
|
1
1
|
import { debounce, isFunction } from "lodash";
|
2
|
-
import { emitter } from "./index";
|
3
2
|
import { log } from "./Utils/log";
|
4
3
|
import { RoomPhase } from "white-web-sdk";
|
5
4
|
import type { Room } from "white-web-sdk";
|
@@ -85,7 +84,3 @@ export class ReconnectRefresher {
|
|
85
84
|
this.releaseDisposers();
|
86
85
|
}
|
87
86
|
}
|
88
|
-
|
89
|
-
export const reconnectRefresher = new ReconnectRefresher({
|
90
|
-
emitter: emitter,
|
91
|
-
});
|
package/src/Register/index.ts
CHANGED
@@ -10,34 +10,39 @@ class AppRegister {
|
|
10
10
|
|
11
11
|
public async register(params: RegisterParams): Promise<void> {
|
12
12
|
this.registered.set(params.kind, params);
|
13
|
-
|
14
|
-
const srcOrAppOrFunction = params.src
|
15
|
-
let downloadApp: () => Promise<NetlessApp
|
16
|
-
|
13
|
+
|
14
|
+
const srcOrAppOrFunction = params.src;
|
15
|
+
let downloadApp: () => Promise<NetlessApp>;
|
16
|
+
|
17
17
|
if (typeof srcOrAppOrFunction === "string") {
|
18
18
|
downloadApp = async () => {
|
19
|
-
|
19
|
+
let appClass = (await loadApp(srcOrAppOrFunction, params.kind)) as any;
|
20
20
|
if (appClass) {
|
21
|
-
|
21
|
+
if (appClass.__esModule) {
|
22
|
+
appClass = appClass.default;
|
23
|
+
}
|
24
|
+
return appClass;
|
22
25
|
} else {
|
23
|
-
throw new Error(
|
26
|
+
throw new Error(
|
27
|
+
`[WindowManager]: load remote script failed, ${srcOrAppOrFunction}`
|
28
|
+
);
|
24
29
|
}
|
25
|
-
}
|
30
|
+
};
|
26
31
|
} else if (typeof srcOrAppOrFunction === "function") {
|
27
|
-
downloadApp = srcOrAppOrFunction
|
32
|
+
downloadApp = srcOrAppOrFunction;
|
28
33
|
} else {
|
29
|
-
downloadApp = async () => srcOrAppOrFunction
|
34
|
+
downloadApp = async () => srcOrAppOrFunction;
|
30
35
|
}
|
31
36
|
|
32
37
|
this.appClasses.set(params.kind, async () => {
|
33
|
-
let app = this.appClassesCache.get(params.kind)
|
38
|
+
let app = this.appClassesCache.get(params.kind);
|
34
39
|
if (!app) {
|
35
|
-
app = downloadApp()
|
36
|
-
this.appClassesCache.set(params.kind, app)
|
40
|
+
app = downloadApp();
|
41
|
+
this.appClassesCache.set(params.kind, app);
|
37
42
|
}
|
38
|
-
return app
|
43
|
+
return app;
|
39
44
|
});
|
40
|
-
|
45
|
+
|
41
46
|
if (params.addHooks) {
|
42
47
|
const emitter = this.createKindEmitter(params.kind);
|
43
48
|
if (emitter) {
|
@@ -46,7 +51,11 @@ class AppRegister {
|
|
46
51
|
}
|
47
52
|
}
|
48
53
|
|
49
|
-
public async notifyApp<T extends keyof RegisterEvents>(
|
54
|
+
public async notifyApp<T extends keyof RegisterEvents>(
|
55
|
+
kind: string,
|
56
|
+
event: T,
|
57
|
+
payload: RegisterEvents[T]
|
58
|
+
) {
|
50
59
|
const emitter = this.kindEmitters.get(kind);
|
51
60
|
await emitter?.emit(event, payload);
|
52
61
|
}
|
package/src/Register/loader.ts
CHANGED
@@ -8,7 +8,7 @@ const TIMEOUT = 10000; // 10 秒超时
|
|
8
8
|
export const getScript = async (url: string): Promise<string> => {
|
9
9
|
const item = await getItem(url);
|
10
10
|
if (item) {
|
11
|
-
return item;
|
11
|
+
return item.sourceCode;
|
12
12
|
} else {
|
13
13
|
const result = await fetchWithTimeout(url, { timeout: TIMEOUT });
|
14
14
|
const text = await result.text();
|
@@ -18,7 +18,7 @@ export const getScript = async (url: string): Promise<string> => {
|
|
18
18
|
};
|
19
19
|
|
20
20
|
export const executeScript = (text: string, appName: string): NetlessApp => {
|
21
|
-
let result = Function(text +
|
21
|
+
let result = Function(text + `\n;return ${appName}`)();
|
22
22
|
if (typeof result === "undefined") {
|
23
23
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
24
24
|
// @ts-ignore
|
package/src/Register/storage.ts
CHANGED
@@ -3,6 +3,11 @@ const DatabaseName = "__WindowManagerAppCache";
|
|
3
3
|
let db: IDBDatabase;
|
4
4
|
let store: IDBObjectStore;
|
5
5
|
|
6
|
+
export type Item = {
|
7
|
+
kind: string;
|
8
|
+
sourceCode: string;
|
9
|
+
}
|
10
|
+
|
6
11
|
export const initDb = async () => {
|
7
12
|
db = await createDb();
|
8
13
|
}
|
@@ -12,7 +17,7 @@ export const setItem = (key: string, val: any) => {
|
|
12
17
|
return addRecord(db, { kind: key, sourceCode: val })
|
13
18
|
};
|
14
19
|
|
15
|
-
export const getItem = async (key: string): Promise<
|
20
|
+
export const getItem = async (key: string): Promise<Item | null> => {
|
16
21
|
if (!db) return null;
|
17
22
|
return await query(db, key);
|
18
23
|
};
|
package/src/Utils/Common.ts
CHANGED
@@ -1,7 +1,8 @@
|
|
1
|
-
import { appRegister } from
|
2
|
-
import { debounce } from
|
3
|
-
import { emitter } from
|
4
|
-
import {
|
1
|
+
import { appRegister } from "../Register";
|
2
|
+
import { debounce } from "lodash";
|
3
|
+
import { emitter } from "../index";
|
4
|
+
import { ScenePathType } from "white-web-sdk";
|
5
|
+
import { v4 } from "uuid";
|
5
6
|
import type { PublicEvent } from "../index";
|
6
7
|
import type { Displayer, ViewVisionMode, Room, View } from "white-web-sdk";
|
7
8
|
import type Emittery from "emittery";
|
@@ -17,6 +18,14 @@ export const genAppId = async (kind: string) => {
|
|
17
18
|
export const setViewFocusScenePath = (view: View, focusScenePath: string) => {
|
18
19
|
if (view.focusScenePath !== focusScenePath) {
|
19
20
|
view.focusScenePath = focusScenePath;
|
21
|
+
return view;
|
22
|
+
}
|
23
|
+
};
|
24
|
+
|
25
|
+
export const setViewSceneIndex = (view: View, index: number) => {
|
26
|
+
if (view.focusSceneIndex !== index) {
|
27
|
+
view.focusSceneIndex = index;
|
28
|
+
return view;
|
20
29
|
}
|
21
30
|
};
|
22
31
|
|
@@ -26,7 +35,30 @@ export const setScenePath = (room: Room | undefined, scenePath: string) => {
|
|
26
35
|
room.setScenePath(scenePath);
|
27
36
|
}
|
28
37
|
}
|
29
|
-
}
|
38
|
+
};
|
39
|
+
|
40
|
+
export const getScenePath = (
|
41
|
+
room: Room | undefined,
|
42
|
+
dir: string | undefined,
|
43
|
+
index: number
|
44
|
+
): string | undefined => {
|
45
|
+
if (room && dir) {
|
46
|
+
const scenes = entireScenes(room);
|
47
|
+
const scene = scenes[dir]?.[index];
|
48
|
+
if (scene) {
|
49
|
+
return `${dir}/${scene.name}`;
|
50
|
+
}
|
51
|
+
}
|
52
|
+
};
|
53
|
+
|
54
|
+
export const removeScenes = (room: Room | undefined, scenePath: string) => {
|
55
|
+
if (room) {
|
56
|
+
const type = room.scenePathType(scenePath);
|
57
|
+
if (type !== ScenePathType.None) {
|
58
|
+
room.removeScenes(scenePath);
|
59
|
+
}
|
60
|
+
}
|
61
|
+
};
|
30
62
|
|
31
63
|
export const setViewMode = (view: View, mode: ViewVisionMode) => {
|
32
64
|
if (!(view as any).didRelease && view.mode !== mode) {
|
@@ -44,7 +76,7 @@ export const emitError = (error: Error) => {
|
|
44
76
|
|
45
77
|
export const addEmitterOnceListener = (event: any, listener: any) => {
|
46
78
|
emitter.once(event).then(listener);
|
47
|
-
}
|
79
|
+
};
|
48
80
|
|
49
81
|
export const notifyMainViewModeChange = debounce(
|
50
82
|
(callbacks: Emittery<PublicEvent>, mode: ViewVisionMode) => {
|
@@ -53,9 +85,12 @@ export const notifyMainViewModeChange = debounce(
|
|
53
85
|
200
|
54
86
|
);
|
55
87
|
|
56
|
-
export const makeValidScenePath = (displayer: Displayer, scenePath: string) => {
|
57
|
-
const scenes =
|
58
|
-
|
88
|
+
export const makeValidScenePath = (displayer: Displayer, scenePath: string, index = 0) => {
|
89
|
+
const scenes = entireScenes(displayer)[scenePath];
|
90
|
+
if (!scenes) return;
|
91
|
+
const scene = scenes[index];
|
92
|
+
if (!scene) return;
|
93
|
+
const firstSceneName = scene.name;
|
59
94
|
if (scenePath === "/") {
|
60
95
|
return `/${firstSceneName}`;
|
61
96
|
} else {
|
@@ -63,9 +98,24 @@ export const makeValidScenePath = (displayer: Displayer, scenePath: string) => {
|
|
63
98
|
}
|
64
99
|
};
|
65
100
|
|
101
|
+
export const entireScenes = (displayer: Displayer) => {
|
102
|
+
return displayer.entireScenes();
|
103
|
+
};
|
104
|
+
|
66
105
|
export const isValidScenePath = (scenePath: string) => {
|
67
106
|
return scenePath.startsWith("/");
|
68
|
-
}
|
107
|
+
};
|
108
|
+
|
109
|
+
export const parseSceneDir = (scenePath: string) => {
|
110
|
+
const sceneList = scenePath.split("/");
|
111
|
+
sceneList.pop();
|
112
|
+
let sceneDir = sceneList.join("/");
|
113
|
+
// "/page1" 的 dir 为 "/"
|
114
|
+
if (sceneDir === "") {
|
115
|
+
sceneDir = "/";
|
116
|
+
}
|
117
|
+
return sceneDir;
|
118
|
+
};
|
69
119
|
|
70
120
|
export const ensureValidScenePath = (scenePath: string) => {
|
71
121
|
if (scenePath.endsWith("/")) {
|
@@ -73,11 +123,14 @@ export const ensureValidScenePath = (scenePath: string) => {
|
|
73
123
|
} else {
|
74
124
|
return scenePath;
|
75
125
|
}
|
76
|
-
}
|
126
|
+
};
|
77
127
|
|
78
128
|
export const getVersionNumber = (version: string) => {
|
79
|
-
const versionString = version
|
129
|
+
const versionString = version
|
130
|
+
.split(".")
|
131
|
+
.map(s => s.padStart(2, "0"))
|
132
|
+
.join("");
|
80
133
|
return parseInt(versionString);
|
81
134
|
};
|
82
135
|
|
83
|
-
export const wait = (time: number) => new Promise(
|
136
|
+
export const wait = (time: number) => new Promise(resolve => setTimeout(resolve, time));
|
package/src/Utils/Reactive.ts
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
import { listenUpdated, unlistenUpdated, reaction, UpdateEventKind } from "white-web-sdk";
|
2
2
|
import type { AkkoObjectUpdatedProperty , AkkoObjectUpdatedListener } from "white-web-sdk";
|
3
|
+
import { isObject } from "lodash";
|
3
4
|
|
4
5
|
// 兼容 13 和 14 版本 SDK
|
5
6
|
export const onObjectByEvent = (event: UpdateEventKind) => {
|
@@ -30,7 +31,8 @@ export const onObjectByEvent = (event: UpdateEventKind) => {
|
|
30
31
|
|
31
32
|
export const safeListenPropsUpdated = <T>(
|
32
33
|
getProps: () => T,
|
33
|
-
callback: AkkoObjectUpdatedListener<T
|
34
|
+
callback: AkkoObjectUpdatedListener<T>,
|
35
|
+
onDestroyed?: (props: unknown) => void
|
34
36
|
) => {
|
35
37
|
let disposeListenUpdated: (() => void) | null = null;
|
36
38
|
const disposeReaction = reaction(
|
@@ -41,8 +43,12 @@ export const safeListenPropsUpdated = <T>(
|
|
41
43
|
disposeListenUpdated = null;
|
42
44
|
}
|
43
45
|
const props = getProps();
|
44
|
-
|
45
|
-
|
46
|
+
if (isObject(props)) {
|
47
|
+
disposeListenUpdated = () => unlistenUpdated(props, callback);
|
48
|
+
listenUpdated(props, callback);
|
49
|
+
} else {
|
50
|
+
onDestroyed?.(props);
|
51
|
+
}
|
46
52
|
},
|
47
53
|
{ fireImmediately: true }
|
48
54
|
);
|
package/src/Utils/RoomHacker.ts
CHANGED
@@ -1,22 +1,13 @@
|
|
1
1
|
import { emitter } from "../index";
|
2
2
|
import { isPlayer } from "white-web-sdk";
|
3
|
-
import type { WindowManager } from
|
4
|
-
import type { Camera, Room
|
3
|
+
import type { WindowManager } from "../index";
|
4
|
+
import type { Camera, Room, Player, PlayerSeekingResult } from "white-web-sdk";
|
5
5
|
|
6
6
|
// 修改多窗口状态下一些失效的方法实现到 manager 的 mainview 上, 降低迁移成本
|
7
7
|
export const replaceRoomFunction = (room: Room, manager: WindowManager) => {
|
8
8
|
if (isPlayer(room)) {
|
9
9
|
const player = room as unknown as Player;
|
10
|
-
|
11
|
-
// eslint-disable-next-line no-inner-declarations
|
12
|
-
async function newSeek(time: number): Promise<PlayerSeekingResult> {
|
13
|
-
const seekResult = await originSeek.call(player, time);
|
14
|
-
if (seekResult === "success") {
|
15
|
-
emitter.emit("seek", time);
|
16
|
-
}
|
17
|
-
return seekResult;
|
18
|
-
}
|
19
|
-
player.seekToProgressTime = newSeek;
|
10
|
+
delegateSeekToProgressTime(player);
|
20
11
|
} else {
|
21
12
|
const descriptor = Object.getOwnPropertyDescriptor(room, "disableCameraTransform");
|
22
13
|
if (descriptor) return;
|
@@ -29,6 +20,18 @@ export const replaceRoomFunction = (room: Room, manager: WindowManager) => {
|
|
29
20
|
},
|
30
21
|
});
|
31
22
|
|
23
|
+
Object.defineProperty(room, "canUndoSteps", {
|
24
|
+
get() {
|
25
|
+
return manager.mainView.canUndoSteps;
|
26
|
+
},
|
27
|
+
});
|
28
|
+
|
29
|
+
Object.defineProperty(room, "canRedoSteps", {
|
30
|
+
get() {
|
31
|
+
return manager.mainView.canRedoSteps;
|
32
|
+
},
|
33
|
+
});
|
34
|
+
|
32
35
|
room.moveCamera = (camera: Camera) => manager.mainView.moveCamera(camera);
|
33
36
|
room.moveCameraToContain = (...args) => manager.moveCameraToContain(...args);
|
34
37
|
room.convertToPointInWorld = (...args) => manager.mainView.convertToPointInWorld(...args);
|
@@ -36,6 +39,32 @@ export const replaceRoomFunction = (room: Room, manager: WindowManager) => {
|
|
36
39
|
room.scenePreview = (...args) => manager.mainView.scenePreview(...args);
|
37
40
|
room.fillSceneSnapshot = (...args) => manager.mainView.fillSceneSnapshot(...args);
|
38
41
|
room.generateScreenshot = (...args) => manager.mainView.generateScreenshot(...args);
|
42
|
+
room.setMemberState = (...args) => manager.mainView.setMemberState(...args);
|
43
|
+
room.redo = () => manager.mainView.redo();
|
44
|
+
room.undo = () => manager.mainView.undo();
|
45
|
+
room.cleanCurrentScene = () => manager.mainView.cleanCurrentScene();
|
46
|
+
delegateRemoveScenes(room);
|
39
47
|
}
|
48
|
+
};
|
40
49
|
|
41
|
-
|
50
|
+
const delegateRemoveScenes = (room: Room) => {
|
51
|
+
const originRemoveScenes = room.removeScenes;
|
52
|
+
room.removeScenes = (scenePath: string) => {
|
53
|
+
const result = originRemoveScenes.call(room, scenePath);
|
54
|
+
emitter.emit("removeScenes", scenePath);
|
55
|
+
return result;
|
56
|
+
};
|
57
|
+
};
|
58
|
+
|
59
|
+
const delegateSeekToProgressTime = (player: Player) => {
|
60
|
+
const originSeek = player.seekToProgressTime;
|
61
|
+
// eslint-disable-next-line no-inner-declarations
|
62
|
+
async function newSeek(time: number): Promise<PlayerSeekingResult> {
|
63
|
+
const seekResult = await originSeek.call(player, time);
|
64
|
+
if (seekResult === "success") {
|
65
|
+
emitter.emit("seek", time);
|
66
|
+
}
|
67
|
+
return seekResult;
|
68
|
+
}
|
69
|
+
player.seekToProgressTime = newSeek;
|
70
|
+
};
|