@netless/window-manager 1.0.0-canary.9 → 1.0.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/LICENSE.txt +21 -0
- package/README.md +90 -64
- package/README.zh-cn.md +224 -0
- package/dist/index.d.ts +1133 -40
- package/dist/index.js +62 -0
- package/dist/index.js.map +1 -0
- package/dist/{index.es.js → index.mjs} +9480 -6984
- package/dist/index.mjs.map +1 -0
- package/dist/style.css +1 -1
- package/docs/advanced.md +55 -55
- package/docs/api.md +124 -113
- package/docs/app-context.md +248 -209
- package/docs/basic.md +25 -26
- package/docs/camera.md +19 -20
- package/docs/cn/advanced.md +137 -0
- package/docs/cn/api.md +309 -0
- package/docs/cn/app-context.md +369 -0
- package/docs/cn/basic.md +64 -0
- package/docs/cn/camera.md +53 -0
- package/docs/cn/concept.md +9 -0
- package/docs/cn/custom-max-bar.md +31 -0
- package/docs/cn/develop-app.md +94 -0
- package/docs/cn/export-pdf.md +48 -0
- package/docs/cn/migrate.md +60 -0
- package/docs/cn/replay.md +40 -0
- package/docs/concept.md +6 -5
- package/docs/custom-max-bar.md +31 -0
- package/docs/develop-app.md +22 -19
- package/docs/export-pdf.md +48 -0
- package/docs/migrate.md +25 -27
- package/docs/quickstart.md +50 -0
- package/docs/replay.md +20 -20
- package/package.json +32 -22
- package/src/App/AppContext.ts +105 -73
- package/src/App/AppPageStateImpl.ts +6 -25
- package/src/App/AppProxy.ts +41 -166
- package/src/App/MagixEvent/index.ts +38 -38
- package/src/App/Storage/StorageEvent.ts +13 -13
- package/src/App/Storage/index.ts +269 -245
- package/src/App/Storage/typings.ts +4 -2
- package/src/App/Storage/utils.ts +3 -3
- package/src/App/index.ts +0 -1
- package/src/AppListener.ts +8 -8
- package/src/AppManager.ts +88 -77
- package/src/AttributesDelegate.ts +42 -22
- package/src/BoxEmitter.ts +12 -6
- package/src/BoxManager.ts +128 -108
- package/src/ContainerResizeObserver.ts +75 -0
- package/src/Cursor/Cursor.svelte +16 -5
- package/src/Cursor/Cursor.svelte.d.ts +21 -0
- package/src/Cursor/Cursor.ts +77 -13
- package/src/Cursor/icons.ts +6 -0
- package/src/Cursor/icons2.ts +66 -0
- package/src/Cursor/index.ts +127 -26
- package/src/Helper.ts +94 -14
- package/src/InternalEmitter.ts +2 -7
- package/src/Page/index.ts +1 -1
- package/src/PageState.ts +6 -5
- package/src/ReconnectRefresher.ts +9 -4
- package/src/RedoUndo.ts +3 -3
- package/src/Register/index.ts +22 -17
- package/src/Register/loader.ts +26 -22
- package/src/Register/storage.ts +13 -13
- package/src/Utils/Common.ts +18 -14
- package/src/Utils/Reactive.ts +26 -25
- package/src/Utils/RoomHacker.ts +4 -4
- package/src/Utils/error.ts +0 -1
- package/src/View/IframeBridge.ts +680 -0
- package/src/View/MainView.ts +127 -53
- package/src/callback.ts +21 -1
- package/src/constants.ts +0 -2
- package/src/image/pencil-eraser-1.svg +3 -0
- package/src/image/pencil-eraser-2.svg +3 -0
- package/src/image/pencil-eraser-3.svg +3 -0
- package/src/index.ts +220 -83
- package/src/style.css +27 -10
- package/src/typings.ts +20 -10
- package/.prettierignore +0 -7
- package/.prettierrc.json +0 -9
- package/CHANGELOG.md +0 -196
- package/__mocks__/white-web-sdk.ts +0 -50
- package/dist/App/AppContext.d.ts +0 -76
- package/dist/App/AppPageStateImpl.d.ts +0 -21
- package/dist/App/AppProxy.d.ts +0 -86
- package/dist/App/AppViewSync.d.ts +0 -11
- package/dist/App/MagixEvent/index.d.ts +0 -29
- package/dist/App/Storage/StorageEvent.d.ts +0 -8
- package/dist/App/Storage/index.d.ts +0 -39
- package/dist/App/Storage/typings.d.ts +0 -22
- package/dist/App/Storage/utils.d.ts +0 -5
- package/dist/App/WhiteboardView.d.ts +0 -22
- package/dist/App/index.d.ts +0 -3
- package/dist/AppListener.d.ts +0 -21
- package/dist/AppManager.d.ts +0 -107
- package/dist/AttributesDelegate.d.ts +0 -80
- package/dist/BoxEmitter.d.ts +0 -34
- package/dist/BoxManager.d.ts +0 -99
- package/dist/BuiltinApps.d.ts +0 -5
- package/dist/Cursor/Cursor.d.ts +0 -39
- package/dist/Cursor/icons.d.ts +0 -3
- package/dist/Cursor/index.d.ts +0 -46
- package/dist/Helper.d.ts +0 -17
- package/dist/InternalEmitter.d.ts +0 -39
- package/dist/Page/PageController.d.ts +0 -21
- package/dist/Page/index.d.ts +0 -3
- package/dist/PageState.d.ts +0 -9
- package/dist/ReconnectRefresher.d.ts +0 -24
- package/dist/RedoUndo.d.ts +0 -18
- package/dist/Register/index.d.ts +0 -28
- package/dist/Register/loader.d.ts +0 -4
- package/dist/Register/storage.d.ts +0 -8
- package/dist/Utils/AppCreateQueue.d.ts +0 -15
- package/dist/Utils/Common.d.ts +0 -23
- package/dist/Utils/Reactive.d.ts +0 -6
- package/dist/Utils/RoomHacker.d.ts +0 -3
- package/dist/Utils/error.d.ts +0 -27
- package/dist/Utils/log.d.ts +0 -1
- package/dist/View/CameraSynchronizer.d.ts +0 -16
- package/dist/View/MainView.d.ts +0 -47
- package/dist/View/ViewManager.d.ts +0 -13
- package/dist/callback.d.ts +0 -24
- package/dist/constants.d.ts +0 -49
- package/dist/index.cjs.js +0 -46
- package/dist/index.umd.js +0 -46
- package/dist/typings.d.ts +0 -82
- package/jest.config.js +0 -27
- package/pnpm-lock.yaml +0 -6302
- package/src/App/AppViewSync.ts +0 -68
- package/src/App/WhiteboardView.ts +0 -83
- package/src/View/CameraSynchronizer.ts +0 -56
- package/vite.config.js +0 -51
- /package/docs/{qickstart.md → cn/quickstart.md} +0 -0
package/src/BoxManager.ts
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
import { AppAttributes, Events, MIN_HEIGHT, MIN_WIDTH } from "./constants";
|
2
2
|
import { debounce } from "lodash";
|
3
|
-
import { TELE_BOX_STATE, TeleBoxManager } from "@netless/telebox-insider";
|
3
|
+
import { TELE_BOX_STATE, TeleBoxCollector, TeleBoxManager } from "@netless/telebox-insider";
|
4
4
|
import { WindowManager } from "./index";
|
5
5
|
import type { BoxEmitterType } from "./BoxEmitter";
|
6
6
|
import type { AddAppOptions, AppInitState } from "./index";
|
@@ -18,7 +18,6 @@ import type { NetlessApp } from "./typings";
|
|
18
18
|
import type { View } from "white-web-sdk";
|
19
19
|
import type { CallbacksType } from "./callback";
|
20
20
|
import type { EmitterType } from "./InternalEmitter";
|
21
|
-
import { SideEffectManager } from "side-effect-manager";
|
22
21
|
|
23
22
|
export { TELE_BOX_STATE };
|
24
23
|
|
@@ -46,12 +45,11 @@ export type CreateTeleBoxManagerConfig = {
|
|
46
45
|
collectorContainer?: HTMLElement;
|
47
46
|
collectorStyles?: Partial<CSSStyleDeclaration>;
|
48
47
|
prefersColorScheme?: TeleBoxColorScheme;
|
49
|
-
stageRatio?: number;
|
50
|
-
highlightStage?: boolean;
|
51
48
|
};
|
52
49
|
|
53
50
|
export type BoxManagerContext = {
|
54
51
|
safeSetAttributes: (attributes: any) => void;
|
52
|
+
getMainView: () => View;
|
55
53
|
updateAppState: (appId: string, field: AppAttributes, value: any) => void;
|
56
54
|
emitter: EmitterType;
|
57
55
|
boxEmitter: BoxEmitterType;
|
@@ -72,6 +70,7 @@ export const createBoxManager = (
|
|
72
70
|
return new BoxManager(
|
73
71
|
{
|
74
72
|
safeSetAttributes: (attributes: any) => manager.safeSetAttributes(attributes),
|
73
|
+
getMainView: () => manager.mainView,
|
75
74
|
updateAppState: (...args) => manager.appManager?.store.updateAppState(...args),
|
76
75
|
canOperate: () => manager.canOperate,
|
77
76
|
notifyContainerRectUpdate: (rect: TeleBoxRect) =>
|
@@ -80,7 +79,7 @@ export const createBoxManager = (
|
|
80
79
|
setAppFocus: (appId: string) => manager.appManager?.store.setAppFocus(appId, true),
|
81
80
|
callbacks,
|
82
81
|
emitter,
|
83
|
-
boxEmitter
|
82
|
+
boxEmitter,
|
84
83
|
},
|
85
84
|
options
|
86
85
|
);
|
@@ -88,93 +87,95 @@ export const createBoxManager = (
|
|
88
87
|
|
89
88
|
export class BoxManager {
|
90
89
|
public teleBoxManager: TeleBoxManager;
|
91
|
-
protected sideEffectManager: SideEffectManager;
|
92
90
|
|
93
91
|
constructor(
|
94
92
|
private context: BoxManagerContext,
|
95
|
-
createTeleBoxManagerConfig?: CreateTeleBoxManagerConfig
|
93
|
+
private createTeleBoxManagerConfig?: CreateTeleBoxManagerConfig
|
96
94
|
) {
|
97
|
-
this.sideEffectManager = new SideEffectManager();
|
98
95
|
const { emitter, callbacks, boxEmitter } = context;
|
99
96
|
this.teleBoxManager = this.setupBoxManager(createTeleBoxManagerConfig);
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
this.
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
this.
|
129
|
-
|
130
|
-
|
97
|
+
|
98
|
+
// 使用 _xxx$.reaction 订阅修改的值, 不管有没有 skipUpdate, 修改值都会触发回调
|
99
|
+
this.teleBoxManager._state$.reaction(state => {
|
100
|
+
callbacks.emit("boxStateChange", state);
|
101
|
+
emitter.emit("boxStateChange", state);
|
102
|
+
});
|
103
|
+
|
104
|
+
this.teleBoxManager._darkMode$.reaction(darkMode => {
|
105
|
+
callbacks.emit("darkModeChange", darkMode);
|
106
|
+
});
|
107
|
+
this.teleBoxManager._prefersColorScheme$.reaction(colorScheme => {
|
108
|
+
callbacks.emit("prefersColorSchemeChange", colorScheme);
|
109
|
+
});
|
110
|
+
|
111
|
+
// ppt 在最小化后刷新恢复正常大小,拿不到正确的宽高,需要手动触发一下窗口的 resize
|
112
|
+
this.teleBoxManager._minimized$.reaction(minimized => {
|
113
|
+
if (!minimized) {
|
114
|
+
setTimeout(() => {
|
115
|
+
const offset = 0.001 * (Math.random() > 0.5 ? 1 : -1);
|
116
|
+
this.teleBoxManager.boxes.forEach(box => {
|
117
|
+
box.resize(box.intrinsicWidth + offset, box.intrinsicHeight + offset, true);
|
118
|
+
});
|
119
|
+
}, 400);
|
120
|
+
}
|
121
|
+
});
|
122
|
+
|
123
|
+
// events.on 的值则会根据 skipUpdate 来决定是否触发回调
|
124
|
+
this.teleBoxManager.events.on("minimized", minimized => {
|
125
|
+
this.context.safeSetAttributes({ minimized });
|
126
|
+
if (minimized) {
|
127
|
+
this.context.cleanFocus();
|
128
|
+
this.blurAllBox();
|
129
|
+
} else {
|
130
|
+
const topBox = this.getTopBox();
|
131
|
+
if (topBox) {
|
132
|
+
this.context.setAppFocus(topBox.id);
|
133
|
+
this.focusBox({ appId: topBox.id }, false);
|
131
134
|
}
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
135
|
+
}
|
136
|
+
});
|
137
|
+
this.teleBoxManager.events.on("maximized", maximized => {
|
138
|
+
this.context.safeSetAttributes({ maximized });
|
139
|
+
});
|
140
|
+
this.teleBoxManager.events.on("removed", boxes => {
|
141
|
+
boxes.forEach(box => {
|
142
|
+
boxEmitter.emit("close", { appId: box.id });
|
143
|
+
});
|
144
|
+
});
|
145
|
+
this.teleBoxManager.events.on(
|
146
|
+
"intrinsic_move",
|
147
|
+
debounce((box: ReadonlyTeleBox): void => {
|
148
|
+
boxEmitter.emit("move", { appId: box.id, x: box.intrinsicX, y: box.intrinsicY });
|
149
|
+
}, 50)
|
150
|
+
);
|
151
|
+
this.teleBoxManager.events.on(
|
152
|
+
"intrinsic_resize",
|
153
|
+
debounce((box: ReadonlyTeleBox): void => {
|
154
|
+
boxEmitter.emit("resize", {
|
155
|
+
appId: box.id,
|
156
|
+
width: box.intrinsicWidth,
|
157
|
+
height: box.intrinsicHeight,
|
137
158
|
});
|
138
|
-
})
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
"intrinsic_resize",
|
147
|
-
debounce((box: ReadonlyTeleBox): void => {
|
148
|
-
boxEmitter.emit("resize", {
|
149
|
-
appId: box.id,
|
150
|
-
width: box.intrinsicWidth,
|
151
|
-
height: box.intrinsicHeight,
|
152
|
-
});
|
153
|
-
}, 200)
|
154
|
-
),
|
155
|
-
this.teleBoxManager.events.on("focused", box => {
|
156
|
-
if (box) {
|
157
|
-
if (this.canOperate) {
|
158
|
-
boxEmitter.emit("focus", { appId: box.id });
|
159
|
-
} else {
|
160
|
-
this.teleBoxManager.blurBox(box.id);
|
161
|
-
}
|
159
|
+
}, 200)
|
160
|
+
);
|
161
|
+
this.teleBoxManager.events.on("focused", box => {
|
162
|
+
if (box) {
|
163
|
+
if (this.canOperate) {
|
164
|
+
boxEmitter.emit("focus", { appId: box.id });
|
165
|
+
} else {
|
166
|
+
this.teleBoxManager.blurBox(box.id);
|
162
167
|
}
|
163
|
-
}
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
emitter.on("containerSizeRatioUpdate", ratio => {
|
175
|
-
this.teleBoxManager._stageRatio$.setValue(ratio);
|
176
|
-
}),
|
177
|
-
]);
|
168
|
+
}
|
169
|
+
});
|
170
|
+
this.teleBoxManager.events.on("z_index", box => {
|
171
|
+
this.context.updateAppState(box.id, AppAttributes.ZIndex, box.zIndex);
|
172
|
+
});
|
173
|
+
emitter.on("playgroundSizeChange", () => this.updateManagerRect());
|
174
|
+
emitter.on("updateManagerRect", () => this.updateManagerRect());
|
175
|
+
}
|
176
|
+
|
177
|
+
private get mainView() {
|
178
|
+
return this.context.getMainView();
|
178
179
|
}
|
179
180
|
|
180
181
|
private get canOperate() {
|
@@ -205,16 +206,12 @@ export class BoxManager {
|
|
205
206
|
return this.teleBoxManager.boxes.length;
|
206
207
|
}
|
207
208
|
|
208
|
-
public
|
209
|
-
return this.teleBoxManager.stageRect;
|
210
|
-
}
|
211
|
-
|
212
|
-
public createBox(params: CreateBoxParams): ReadonlyTeleBox | undefined {
|
209
|
+
public createBox(params: CreateBoxParams): void {
|
213
210
|
if (!this.teleBoxManager) return;
|
214
211
|
let { minwidth = MIN_WIDTH, minheight = MIN_HEIGHT } = params.app.config ?? {};
|
215
212
|
const { width, height } = params.app.config ?? {};
|
216
213
|
const title = params.options?.title || params.appId;
|
217
|
-
const rect = this.teleBoxManager.
|
214
|
+
const rect = this.teleBoxManager.containerRect;
|
218
215
|
|
219
216
|
if (minwidth > 1) {
|
220
217
|
minwidth = minwidth / rect.width;
|
@@ -232,21 +229,40 @@ export class BoxManager {
|
|
232
229
|
height,
|
233
230
|
id: params.appId,
|
234
231
|
};
|
235
|
-
|
232
|
+
this.teleBoxManager.create(createBoxConfig, params.smartPosition);
|
236
233
|
this.context.emitter.emit(`${params.appId}${Events.WindowCreated}` as any);
|
237
|
-
|
234
|
+
}
|
235
|
+
|
236
|
+
public setBoxInitState(appId: string): void {
|
237
|
+
const box = this.teleBoxManager.queryOne({ id: appId });
|
238
|
+
if (box) {
|
239
|
+
if (box.state === TELE_BOX_STATE.Maximized) {
|
240
|
+
this.context.boxEmitter.emit("resize", {
|
241
|
+
appId: appId,
|
242
|
+
x: box.x,
|
243
|
+
y: box.y,
|
244
|
+
width: box.intrinsicWidth,
|
245
|
+
height: box.intrinsicHeight,
|
246
|
+
});
|
247
|
+
}
|
248
|
+
}
|
238
249
|
}
|
239
250
|
|
240
251
|
public setupBoxManager(
|
241
252
|
createTeleBoxManagerConfig?: CreateTeleBoxManagerConfig
|
242
253
|
): TeleBoxManager {
|
243
|
-
const root = WindowManager.
|
254
|
+
const root = WindowManager.wrapper ? WindowManager.wrapper : document.body;
|
255
|
+
const rect = root.getBoundingClientRect();
|
244
256
|
const initManagerState: TeleBoxManagerConfig = {
|
245
|
-
stageRatio: createTeleBoxManagerConfig?.stageRatio,
|
246
257
|
root: root,
|
258
|
+
containerRect: {
|
259
|
+
x: 0,
|
260
|
+
y: 0,
|
261
|
+
width: rect.width,
|
262
|
+
height: rect.height,
|
263
|
+
},
|
247
264
|
fence: false,
|
248
265
|
prefersColorScheme: createTeleBoxManagerConfig?.prefersColorScheme,
|
249
|
-
highlightStage: createTeleBoxManagerConfig?.highlightStage,
|
250
266
|
};
|
251
267
|
|
252
268
|
const manager = new TeleBoxManager(initManagerState);
|
@@ -254,16 +270,20 @@ export class BoxManager {
|
|
254
270
|
this.teleBoxManager.destroy();
|
255
271
|
}
|
256
272
|
this.teleBoxManager = manager;
|
257
|
-
const container = createTeleBoxManagerConfig?.collectorContainer;
|
273
|
+
const container = createTeleBoxManagerConfig?.collectorContainer || WindowManager.wrapper;
|
258
274
|
if (container) {
|
259
|
-
this.
|
260
|
-
}
|
261
|
-
if (createTeleBoxManagerConfig?.collectorStyles) {
|
262
|
-
this.teleBoxManager.collector.setStyles(createTeleBoxManagerConfig.collectorStyles);
|
275
|
+
this.setCollectorContainer(container);
|
263
276
|
}
|
264
277
|
return manager;
|
265
278
|
}
|
266
279
|
|
280
|
+
public setCollectorContainer(container: HTMLElement) {
|
281
|
+
const collector = new TeleBoxCollector({
|
282
|
+
styles: this.createTeleBoxManagerConfig?.collectorStyles,
|
283
|
+
}).mount(container);
|
284
|
+
this.teleBoxManager.setCollector(collector);
|
285
|
+
}
|
286
|
+
|
267
287
|
public getBox(appId: string): ReadonlyTeleBox | undefined {
|
268
288
|
return this.teleBoxManager.queryOne({ id: appId });
|
269
289
|
}
|
@@ -316,6 +336,15 @@ export class BoxManager {
|
|
316
336
|
}
|
317
337
|
}
|
318
338
|
|
339
|
+
public updateManagerRect(): void {
|
340
|
+
const rect = this.mainView.divElement?.getBoundingClientRect();
|
341
|
+
if (rect && rect.width > 0 && rect.height > 0) {
|
342
|
+
const containerRect = { x: 0, y: 0, width: rect.width, height: rect.height };
|
343
|
+
this.teleBoxManager.setContainerRect(containerRect);
|
344
|
+
this.context.notifyContainerRectUpdate(this.teleBoxManager.containerRect);
|
345
|
+
}
|
346
|
+
}
|
347
|
+
|
319
348
|
public moveBox({ appId, x, y }: MoveBoxParams): void {
|
320
349
|
this.teleBoxManager.update(appId, { x, y }, true);
|
321
350
|
}
|
@@ -387,16 +416,7 @@ export class BoxManager {
|
|
387
416
|
this.teleBoxManager.update(id, { zIndex }, skipUpdate);
|
388
417
|
}
|
389
418
|
|
390
|
-
public setRoot(root: HTMLElement) {
|
391
|
-
this.teleBoxManager._root$.setValue(root);
|
392
|
-
}
|
393
|
-
|
394
|
-
public setCollector(collector: HTMLElement) {
|
395
|
-
this.teleBoxManager.collector.set$collector(collector);
|
396
|
-
}
|
397
|
-
|
398
419
|
public destroy() {
|
399
|
-
this.sideEffectManager.flushAll();
|
400
420
|
this.teleBoxManager.destroy();
|
401
421
|
}
|
402
422
|
}
|
@@ -0,0 +1,75 @@
|
|
1
|
+
import { ResizeObserver as ResizeObserverPolyfill } from "@juggle/resize-observer";
|
2
|
+
import { isFunction } from "lodash";
|
3
|
+
import { WindowManager } from "./index";
|
4
|
+
import type { EmitterType } from "./InternalEmitter";
|
5
|
+
import type { UnsubscribeFn } from "emittery";
|
6
|
+
|
7
|
+
const ResizeObserver = window.ResizeObserver || ResizeObserverPolyfill;
|
8
|
+
|
9
|
+
export class ContainerResizeObserver {
|
10
|
+
private containerResizeObserver?: ResizeObserver;
|
11
|
+
private disposer?: UnsubscribeFn;
|
12
|
+
|
13
|
+
constructor(private emitter: EmitterType) {}
|
14
|
+
|
15
|
+
public static create(
|
16
|
+
container: HTMLElement,
|
17
|
+
sizer: HTMLElement,
|
18
|
+
wrapper: HTMLDivElement,
|
19
|
+
emitter: EmitterType
|
20
|
+
) {
|
21
|
+
const containerResizeObserver = new ContainerResizeObserver(emitter);
|
22
|
+
containerResizeObserver.observePlaygroundSize(container, sizer, wrapper);
|
23
|
+
return containerResizeObserver;
|
24
|
+
}
|
25
|
+
|
26
|
+
public observePlaygroundSize(
|
27
|
+
container: HTMLElement,
|
28
|
+
sizer: HTMLElement,
|
29
|
+
wrapper: HTMLDivElement
|
30
|
+
) {
|
31
|
+
this.updateSizer(container.getBoundingClientRect(), sizer, wrapper);
|
32
|
+
|
33
|
+
this.containerResizeObserver = new ResizeObserver(entries => {
|
34
|
+
const containerRect = entries[0]?.contentRect;
|
35
|
+
if (containerRect) {
|
36
|
+
this.updateSizer(containerRect, sizer, wrapper);
|
37
|
+
this.emitter.emit("playgroundSizeChange", containerRect);
|
38
|
+
}
|
39
|
+
});
|
40
|
+
|
41
|
+
this.disposer = this.emitter.on("containerSizeRatioUpdate", () => {
|
42
|
+
const containerRect = container.getBoundingClientRect();
|
43
|
+
this.updateSizer(containerRect, sizer, wrapper);
|
44
|
+
this.emitter.emit("playgroundSizeChange", containerRect);
|
45
|
+
});
|
46
|
+
|
47
|
+
this.containerResizeObserver.observe(container);
|
48
|
+
}
|
49
|
+
|
50
|
+
public updateSizer(
|
51
|
+
{ width, height }: DOMRectReadOnly,
|
52
|
+
sizer: HTMLElement,
|
53
|
+
wrapper: HTMLDivElement
|
54
|
+
) {
|
55
|
+
if (width && height) {
|
56
|
+
if (height / width > WindowManager.containerSizeRatio) {
|
57
|
+
height = width * WindowManager.containerSizeRatio;
|
58
|
+
sizer.classList.toggle("netless-window-manager-sizer-horizontal", true);
|
59
|
+
} else {
|
60
|
+
width = height / WindowManager.containerSizeRatio;
|
61
|
+
sizer.classList.toggle("netless-window-manager-sizer-horizontal", false);
|
62
|
+
}
|
63
|
+
wrapper.style.width = `${width}px`;
|
64
|
+
wrapper.style.height = `${height}px`;
|
65
|
+
}
|
66
|
+
}
|
67
|
+
|
68
|
+
public disconnect() {
|
69
|
+
this.containerResizeObserver?.disconnect();
|
70
|
+
if (isFunction(this.disposer)) {
|
71
|
+
this.disposer();
|
72
|
+
this.disposer = undefined;
|
73
|
+
}
|
74
|
+
}
|
75
|
+
}
|
package/src/Cursor/Cursor.svelte
CHANGED
@@ -2,6 +2,7 @@
|
|
2
2
|
import { isEmpty } from "lodash";
|
3
3
|
import { ApplianceNames } from "white-web-sdk";
|
4
4
|
|
5
|
+
export let uid: string;
|
5
6
|
export let cursorName: string;
|
6
7
|
export let tagName: string | undefined;
|
7
8
|
export let backgroundColor: string;
|
@@ -15,12 +16,17 @@
|
|
15
16
|
export let color: string;
|
16
17
|
export let cursorTagBackgroundColor: string;
|
17
18
|
export let opacity: number;
|
19
|
+
export let pencilEraserSize: number | undefined;
|
20
|
+
export let custom: boolean | undefined;
|
18
21
|
|
19
22
|
$: hasName = !isEmpty(cursorName);
|
20
23
|
$: hasTagName = !isEmpty(tagName);
|
21
24
|
$: hasAvatar = !isEmpty(avatar);
|
22
|
-
$: display = visible ? "
|
25
|
+
$: display = visible ? "" : "none";
|
23
26
|
$: isLaserPointer = appliance === ApplianceNames.laserPointer;
|
27
|
+
$: isLaserPointerPencilEraser = isLaserPointer || appliance === ApplianceNames.pencilEraser;
|
28
|
+
$: offset = isLaserPointerPencilEraser ? "netless-window-manager-laserPointer-pencilEraser-offset" : "";
|
29
|
+
$: pencilEraserSize3ImageOffset = pencilEraserSize === 3 ? "netless-window-manager-pencilEraser-3-offset" : "";
|
24
30
|
|
25
31
|
const computedAvatarStyle = () => {
|
26
32
|
return Object.entries({
|
@@ -36,11 +42,12 @@
|
|
36
42
|
</script>
|
37
43
|
|
38
44
|
<div
|
39
|
-
class="netless-window-manager-cursor-mid"
|
45
|
+
class={"netless-window-manager-cursor-mid" + (custom ? " netless-window-manager-cursor-custom" : "")}
|
40
46
|
style="transform: translateX({x}px) translateY({y}px);display: {display}"
|
41
|
-
|
47
|
+
data-cursor-uid={uid}
|
48
|
+
>
|
42
49
|
{#if !isLaserPointer}
|
43
|
-
<div class="netless-window-manager-cursor-name">
|
50
|
+
<div class="netless-window-manager-cursor-name {offset} {pencilEraserSize3ImageOffset}">
|
44
51
|
<div
|
45
52
|
class={theme}
|
46
53
|
style="background-color: {backgroundColor};color: {color};opacity: {opacity}"
|
@@ -63,6 +70,10 @@
|
|
63
70
|
</div>
|
64
71
|
{/if}
|
65
72
|
<div class="cursor-image-wrapper">
|
66
|
-
<img
|
73
|
+
<img
|
74
|
+
class="netless-window-manager-cursor-{appliance}-image {pencilEraserSize3ImageOffset}"
|
75
|
+
{src}
|
76
|
+
alt={appliance}
|
77
|
+
/>
|
67
78
|
</div>
|
68
79
|
</div>
|
@@ -0,0 +1,21 @@
|
|
1
|
+
import { SvelteComponentTyped } from "svelte";
|
2
|
+
|
3
|
+
declare class Cursor extends SvelteComponentTyped<{
|
4
|
+
readonly cursorName: string;
|
5
|
+
readonly tagName?: string;
|
6
|
+
readonly backgroundColor: string;
|
7
|
+
readonly appliance: string;
|
8
|
+
readonly x: number;
|
9
|
+
readonly y: number;
|
10
|
+
readonly src?: string;
|
11
|
+
readonly visible: boolean;
|
12
|
+
readonly avatar: string;
|
13
|
+
readonly theme: string;
|
14
|
+
readonly color: string;
|
15
|
+
readonly cursorTagBackgroundColor: string;
|
16
|
+
readonly opacity: number;
|
17
|
+
readonly pencilEraserSize?: number;
|
18
|
+
readonly custom?: boolean;
|
19
|
+
}> {}
|
20
|
+
|
21
|
+
export default Cursor;
|
package/src/Cursor/Cursor.ts
CHANGED
@@ -1,12 +1,15 @@
|
|
1
|
-
import App from "./Cursor.svelte";
|
2
|
-
import { ApplianceNames } from "white-web-sdk";
|
3
|
-
import { findMemberByUid } from "../Helper";
|
4
|
-
import { omit } from "lodash";
|
5
|
-
import type { Position } from "../AttributesDelegate";
|
6
1
|
import type { RoomMember } from "white-web-sdk";
|
7
|
-
import type {
|
8
|
-
import type { SvelteComponent } from "svelte";
|
2
|
+
import type { CursorOptions } from "../index";
|
9
3
|
import type { AppManager } from "../AppManager";
|
4
|
+
import type { Position } from "../AttributesDelegate";
|
5
|
+
import type { CursorManager } from "./index";
|
6
|
+
|
7
|
+
import { omit } from "lodash";
|
8
|
+
import { ApplianceNames } from "white-web-sdk";
|
9
|
+
|
10
|
+
import { findMemberByUid } from "../Helper";
|
11
|
+
import App from "./Cursor.svelte";
|
12
|
+
import { remoteIcon } from "./icons2";
|
10
13
|
|
11
14
|
export type Payload = {
|
12
15
|
[key: string]: any;
|
@@ -15,7 +18,8 @@ export type Payload = {
|
|
15
18
|
export class Cursor {
|
16
19
|
private member?: RoomMember;
|
17
20
|
private timer?: number;
|
18
|
-
private component?:
|
21
|
+
private component?: App;
|
22
|
+
private style: CursorOptions["style"] & string = "default";
|
19
23
|
|
20
24
|
constructor(
|
21
25
|
private manager: AppManager,
|
@@ -26,6 +30,7 @@ export class Cursor {
|
|
26
30
|
this.updateMember();
|
27
31
|
this.createCursor();
|
28
32
|
this.autoHidden();
|
33
|
+
this.setStyle(cursorManager.style);
|
29
34
|
}
|
30
35
|
|
31
36
|
public move = (position: Position) => {
|
@@ -46,6 +51,16 @@ export class Cursor {
|
|
46
51
|
}
|
47
52
|
};
|
48
53
|
|
54
|
+
public setStyle = (style: typeof this.style) => {
|
55
|
+
this.style = style;
|
56
|
+
if (this.component) {
|
57
|
+
this.component.$set({
|
58
|
+
src: this.getIcon(),
|
59
|
+
custom: this.isCustomIcon(),
|
60
|
+
});
|
61
|
+
}
|
62
|
+
};
|
63
|
+
|
49
64
|
public leave = () => {
|
50
65
|
this.hide();
|
51
66
|
};
|
@@ -56,6 +71,10 @@ export class Cursor {
|
|
56
71
|
if (point) {
|
57
72
|
let translateX = point.x - 2;
|
58
73
|
let translateY = point.y - 18;
|
74
|
+
if (this.isCustomIcon()) {
|
75
|
+
translateX -= 11;
|
76
|
+
translateY += 4;
|
77
|
+
}
|
59
78
|
if (type === "app") {
|
60
79
|
const wrapperRect = this.cursorManager.wrapperRect;
|
61
80
|
if (wrapperRect) {
|
@@ -80,6 +99,11 @@ export class Cursor {
|
|
80
99
|
return `rgb(${rgb})`;
|
81
100
|
}
|
82
101
|
|
102
|
+
public get memberColorHex(): string {
|
103
|
+
const [r, g, b] = this.member?.memberState?.strokeColor || [236, 52, 85];
|
104
|
+
return ((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1);
|
105
|
+
}
|
106
|
+
|
83
107
|
private get payload(): Payload | undefined {
|
84
108
|
return this.member?.payload;
|
85
109
|
}
|
@@ -140,11 +164,13 @@ export class Cursor {
|
|
140
164
|
|
141
165
|
private initProps() {
|
142
166
|
return {
|
167
|
+
uid: this.memberId,
|
143
168
|
x: 0,
|
144
169
|
y: 0,
|
145
170
|
appliance: this.memberApplianceName as string,
|
146
171
|
avatar: this.memberAvatar,
|
147
172
|
src: this.getIcon(),
|
173
|
+
custom: this.isCustomIcon(),
|
148
174
|
visible: false,
|
149
175
|
backgroundColor: this.memberColor,
|
150
176
|
cursorName: this.memberCursorName,
|
@@ -153,15 +179,53 @@ export class Cursor {
|
|
153
179
|
cursorTagBackgroundColor: this.memberCursorTagBackgroundColor,
|
154
180
|
opacity: this.memberOpacity,
|
155
181
|
tagName: this.memberTagName,
|
182
|
+
pencilEraserSize: this.member?.memberState.pencilEraserSize,
|
156
183
|
};
|
157
184
|
}
|
158
185
|
|
159
|
-
private getIcon() {
|
160
|
-
if (this.member)
|
161
|
-
|
162
|
-
|
163
|
-
|
186
|
+
private getIcon(): string | undefined {
|
187
|
+
if (!this.member) return;
|
188
|
+
|
189
|
+
const { memberApplianceName, memberColorHex } = this;
|
190
|
+
const { userApplianceIcons, applianceIcons } = this.cursorManager;
|
191
|
+
|
192
|
+
let iconsKey: string | undefined = this.memberApplianceName;
|
193
|
+
if (iconsKey === ApplianceNames.pencilEraser) {
|
194
|
+
iconsKey = `${iconsKey}${this.member?.memberState.pencilEraserSize || 1}`;
|
195
|
+
}
|
196
|
+
|
197
|
+
const userApplianceSrc = iconsKey && userApplianceIcons[iconsKey];
|
198
|
+
if (userApplianceSrc) return userApplianceSrc;
|
199
|
+
|
200
|
+
if (this.style === "custom" && memberApplianceName) {
|
201
|
+
const customApplianceSrc = remoteIcon(memberApplianceName, memberColorHex);
|
202
|
+
if (customApplianceSrc) return customApplianceSrc;
|
203
|
+
}
|
204
|
+
|
205
|
+
const applianceSrc = applianceIcons[iconsKey || ApplianceNames.shape];
|
206
|
+
return applianceSrc || applianceIcons[ApplianceNames.shape];
|
207
|
+
}
|
208
|
+
|
209
|
+
private isCustomIcon(): boolean {
|
210
|
+
if (!this.member) return false;
|
211
|
+
|
212
|
+
const { memberApplianceName, memberColorHex } = this;
|
213
|
+
const { userApplianceIcons } = this.cursorManager;
|
214
|
+
|
215
|
+
let iconsKey: string | undefined = this.memberApplianceName;
|
216
|
+
if (iconsKey === ApplianceNames.pencilEraser) {
|
217
|
+
iconsKey = `${iconsKey}${this.member?.memberState.pencilEraserSize || 1}`;
|
164
218
|
}
|
219
|
+
|
220
|
+
const userApplianceSrc = iconsKey && userApplianceIcons[iconsKey];
|
221
|
+
if (userApplianceSrc) return false;
|
222
|
+
|
223
|
+
if (this.style === "custom" && memberApplianceName) {
|
224
|
+
const customApplianceSrc = remoteIcon(memberApplianceName, memberColorHex);
|
225
|
+
if (customApplianceSrc) return true;
|
226
|
+
}
|
227
|
+
|
228
|
+
return false;
|
165
229
|
}
|
166
230
|
|
167
231
|
public updateMember() {
|
package/src/Cursor/icons.ts
CHANGED
@@ -5,6 +5,9 @@ import eraser from "../image/eraser-cursor.png";
|
|
5
5
|
import shape from "../image/shape-cursor.svg";
|
6
6
|
import text from "../image/text-cursor.svg";
|
7
7
|
import laser from "../image/laser-pointer-cursor.svg";
|
8
|
+
import pencilEraser1 from "../image/pencil-eraser-1.svg";
|
9
|
+
import pencilEraser2 from "../image/pencil-eraser-2.svg";
|
10
|
+
import pencilEraser3 from "../image/pencil-eraser-3.svg";
|
8
11
|
|
9
12
|
export const ApplianceMap: {
|
10
13
|
[key: string]: string;
|
@@ -15,4 +18,7 @@ export const ApplianceMap: {
|
|
15
18
|
[ApplianceNames.shape]: shape,
|
16
19
|
[ApplianceNames.text]: text,
|
17
20
|
[ApplianceNames.laserPointer]: laser,
|
21
|
+
["pencilEraser1"]: pencilEraser1,
|
22
|
+
["pencilEraser2"]: pencilEraser2,
|
23
|
+
["pencilEraser3"]: pencilEraser3,
|
18
24
|
};
|