@netless/window-manager 0.4.71-beta.0 → 0.4.71
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/dist/AppManager.d.ts +2 -1
- package/dist/Cursor/Cursor.d.ts +7 -3
- package/dist/Cursor/icons2.d.ts +4 -0
- package/dist/Cursor/index.d.ts +9 -4
- package/dist/index.d.ts +11 -0
- package/dist/index.js +14 -13
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +211 -54
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
- package/src/AppManager.ts +12 -1
- package/src/Cursor/Cursor.svelte +9 -4
- package/src/Cursor/Cursor.svelte.d.ts +21 -0
- package/src/Cursor/Cursor.ts +75 -19
- package/src/Cursor/icons2.ts +66 -0
- package/src/Cursor/index.ts +79 -21
- package/src/index.ts +46 -16
- package/src/style.css +0 -1
package/package.json
CHANGED
package/src/AppManager.ts
CHANGED
@@ -31,7 +31,14 @@ import {
|
|
31
31
|
} from "./Utils/Common";
|
32
32
|
import type { ReconnectRefresher } from "./ReconnectRefresher";
|
33
33
|
import type { BoxManager } from "./BoxManager";
|
34
|
-
import type {
|
34
|
+
import type {
|
35
|
+
Displayer,
|
36
|
+
Room,
|
37
|
+
ScenesCallbacksNode,
|
38
|
+
SceneState,
|
39
|
+
RoomState,
|
40
|
+
MemberState,
|
41
|
+
} from "white-web-sdk";
|
35
42
|
import type { AddAppParams, BaseInsertParams, TeleBoxRect } from "./index";
|
36
43
|
import type {
|
37
44
|
BoxClosePayload,
|
@@ -111,6 +118,10 @@ export class AppManager {
|
|
111
118
|
});
|
112
119
|
}
|
113
120
|
|
121
|
+
public getMemberState(): MemberState {
|
122
|
+
return this.room?.state.memberState || ({ strokeColor: [0, 0, 0] } as MemberState);
|
123
|
+
}
|
124
|
+
|
114
125
|
private onRemoveScenes = async (params: RemoveSceneParams) => {
|
115
126
|
const { scenePath } = params;
|
116
127
|
// 如果移除根目录就把 scenePath 设置为初始值
|
package/src/Cursor/Cursor.svelte
CHANGED
@@ -15,7 +15,8 @@
|
|
15
15
|
export let color: string;
|
16
16
|
export let cursorTagBackgroundColor: string;
|
17
17
|
export let opacity: number;
|
18
|
-
export let pencilEraserSize: number;
|
18
|
+
export let pencilEraserSize: number | undefined;
|
19
|
+
export let custom: boolean | undefined;
|
19
20
|
|
20
21
|
$: hasName = !isEmpty(cursorName);
|
21
22
|
$: hasTagName = !isEmpty(tagName);
|
@@ -40,9 +41,9 @@
|
|
40
41
|
</script>
|
41
42
|
|
42
43
|
<div
|
43
|
-
class="netless-window-manager-cursor-mid"
|
44
|
+
class={"netless-window-manager-cursor-mid" + (custom ? " netless-window-manager-cursor-custom" : "")}
|
44
45
|
style="transform: translateX({x}px) translateY({y}px);display: {display}"
|
45
|
-
>
|
46
|
+
>
|
46
47
|
{#if !isLaserPointer}
|
47
48
|
<div class="netless-window-manager-cursor-name {offset} {pencilEraserSize3ImageOffset}">
|
48
49
|
<div
|
@@ -67,6 +68,10 @@
|
|
67
68
|
</div>
|
68
69
|
{/if}
|
69
70
|
<div class="cursor-image-wrapper">
|
70
|
-
<img
|
71
|
+
<img
|
72
|
+
class="netless-window-manager-cursor-{appliance}-image {pencilEraserSize3ImageOffset}"
|
73
|
+
{src}
|
74
|
+
alt={appliance}
|
75
|
+
/>
|
71
76
|
</div>
|
72
77
|
</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
|
}
|
@@ -145,6 +169,7 @@ export class Cursor {
|
|
145
169
|
appliance: this.memberApplianceName as string,
|
146
170
|
avatar: this.memberAvatar,
|
147
171
|
src: this.getIcon(),
|
172
|
+
custom: this.isCustomIcon(),
|
148
173
|
visible: false,
|
149
174
|
backgroundColor: this.memberColor,
|
150
175
|
cursorName: this.memberCursorName,
|
@@ -157,18 +182,49 @@ export class Cursor {
|
|
157
182
|
};
|
158
183
|
}
|
159
184
|
|
160
|
-
private getIcon() {
|
161
|
-
if (this.member)
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
}
|
170
|
-
return applianceSrc || icons[ApplianceNames.shape];
|
185
|
+
private getIcon(): string | undefined {
|
186
|
+
if (!this.member) return;
|
187
|
+
|
188
|
+
const { memberApplianceName, memberColorHex } = this;
|
189
|
+
const { userApplianceIcons, applianceIcons } = this.cursorManager;
|
190
|
+
|
191
|
+
let iconsKey: string | undefined = this.memberApplianceName;
|
192
|
+
if (iconsKey === ApplianceNames.pencilEraser) {
|
193
|
+
iconsKey = `${iconsKey}${this.member?.memberState.pencilEraserSize || 1}`;
|
171
194
|
}
|
195
|
+
|
196
|
+
const userApplianceSrc = iconsKey && userApplianceIcons[iconsKey];
|
197
|
+
if (userApplianceSrc) return userApplianceSrc;
|
198
|
+
|
199
|
+
if (this.style === "custom" && memberApplianceName) {
|
200
|
+
const customApplianceSrc = remoteIcon(memberApplianceName, memberColorHex);
|
201
|
+
if (customApplianceSrc) return customApplianceSrc;
|
202
|
+
}
|
203
|
+
|
204
|
+
const applianceSrc = applianceIcons[iconsKey || ApplianceNames.shape];
|
205
|
+
return applianceSrc || applianceIcons[ApplianceNames.shape];
|
206
|
+
}
|
207
|
+
|
208
|
+
private isCustomIcon(): boolean {
|
209
|
+
if (!this.member) return false;
|
210
|
+
|
211
|
+
const { memberApplianceName, memberColorHex } = this;
|
212
|
+
const { userApplianceIcons } = this.cursorManager;
|
213
|
+
|
214
|
+
let iconsKey: string | undefined = this.memberApplianceName;
|
215
|
+
if (iconsKey === ApplianceNames.pencilEraser) {
|
216
|
+
iconsKey = `${iconsKey}${this.member?.memberState.pencilEraserSize || 1}`;
|
217
|
+
}
|
218
|
+
|
219
|
+
const userApplianceSrc = iconsKey && userApplianceIcons[iconsKey];
|
220
|
+
if (userApplianceSrc) return false;
|
221
|
+
|
222
|
+
if (this.style === "custom" && memberApplianceName) {
|
223
|
+
const customApplianceSrc = remoteIcon(memberApplianceName, memberColorHex);
|
224
|
+
if (customApplianceSrc) return true;
|
225
|
+
}
|
226
|
+
|
227
|
+
return false;
|
172
228
|
}
|
173
229
|
|
174
230
|
public updateMember() {
|
@@ -0,0 +1,66 @@
|
|
1
|
+
import type { MemberState } from "white-web-sdk";
|
2
|
+
import { ApplianceNames } from "white-web-sdk";
|
3
|
+
|
4
|
+
type Color = string;
|
5
|
+
|
6
|
+
const staticCircle = `data:image/svg+xml,%3Csvg width='24' height='24' xmlns='http://www.w3.org/2000/svg'%3E%3Cg fill='none' fill-rule='evenodd'%3E%3Ccircle cx='12' cy='12' r='2.5' stroke='%23000' stroke-linejoin='square'/%3E%3Ccircle cx='12' cy='12' r='3.5' stroke='%23FFF'/%3E%3C/g%3E%3C/svg%3E`;
|
7
|
+
|
8
|
+
function circleUrl(color: Color): string {
|
9
|
+
return `data:image/svg+xml,%3Csvg width='24' height='24' xmlns='http://www.w3.org/2000/svg'%3E%3Cg fill='none' fill-rule='evenodd'%3E%3Ccircle cx='12' cy='12' r='2.5' stroke='%23${color}' stroke-linejoin='square'/%3E%3Ccircle cx='12' cy='12' r='3.5' stroke='%23${color}'/%3E%3C/g%3E%3C/svg%3E`;
|
10
|
+
}
|
11
|
+
|
12
|
+
function crossUrl(color: Color): string {
|
13
|
+
return `data:image/svg+xml,%3Csvg width='24' height='24' xmlns='http://www.w3.org/2000/svg' fill='none'%3E%3Cpath d='M5 12H19' stroke='%23${color}' stroke-linejoin='round'/%3E%3Cpath d='M12 5V19' stroke='%23${color}' stroke-linejoin='round'/%3E%3C/svg%3E`;
|
14
|
+
}
|
15
|
+
|
16
|
+
function cssCursor(url: string): string {
|
17
|
+
return `url("${url}") 12 12, auto`;
|
18
|
+
}
|
19
|
+
|
20
|
+
function makeStyleContent(config: { [cursor: string]: string }): string {
|
21
|
+
let result = "";
|
22
|
+
for (const cursor in config) {
|
23
|
+
result += `.netless-whiteboard.${cursor} {cursor: ${config[cursor]}}\n`;
|
24
|
+
}
|
25
|
+
return result;
|
26
|
+
}
|
27
|
+
|
28
|
+
const $style = document.createElement("style");
|
29
|
+
|
30
|
+
export function enableLocal(memberState: MemberState): () => void {
|
31
|
+
const [r, g, b] = memberState.strokeColor;
|
32
|
+
const hex = ((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1);
|
33
|
+
$style.textContent = makeStyleContent({
|
34
|
+
"cursor-pencil": cssCursor(circleUrl(hex)),
|
35
|
+
"cursor-eraser": cssCursor(staticCircle),
|
36
|
+
"cursor-rectangle": cssCursor(crossUrl(hex)),
|
37
|
+
"cursor-ellipse": cssCursor(crossUrl(hex)),
|
38
|
+
"cursor-straight": cssCursor(crossUrl(hex)),
|
39
|
+
"cursor-arrow": cssCursor(crossUrl(hex)),
|
40
|
+
"cursor-shape": cssCursor(crossUrl(hex)),
|
41
|
+
});
|
42
|
+
document.head.appendChild($style);
|
43
|
+
|
44
|
+
return () => {
|
45
|
+
if ($style.parentNode == null) return;
|
46
|
+
document.head.removeChild($style);
|
47
|
+
};
|
48
|
+
}
|
49
|
+
|
50
|
+
const shapeAppliances: Set<ApplianceNames> = new Set([
|
51
|
+
ApplianceNames.rectangle,
|
52
|
+
ApplianceNames.ellipse,
|
53
|
+
ApplianceNames.straight,
|
54
|
+
ApplianceNames.arrow,
|
55
|
+
ApplianceNames.shape,
|
56
|
+
]);
|
57
|
+
|
58
|
+
export function remoteIcon(applianceName: ApplianceNames, hex: string): string | undefined {
|
59
|
+
if (applianceName === ApplianceNames.pencil) {
|
60
|
+
return circleUrl(hex);
|
61
|
+
} else if (applianceName === ApplianceNames.eraser) {
|
62
|
+
return staticCircle;
|
63
|
+
} else if (shapeAppliances.has(applianceName)) {
|
64
|
+
return crossUrl(hex);
|
65
|
+
}
|
66
|
+
}
|
package/src/Cursor/index.ts
CHANGED
@@ -4,12 +4,13 @@ import { CursorState, Events } from "../constants";
|
|
4
4
|
import { internalEmitter } from "../InternalEmitter";
|
5
5
|
import { SideEffectManager } from "side-effect-manager";
|
6
6
|
import { WindowManager } from "../index";
|
7
|
-
import type { CursorMovePayload, ApplianceIcons } from "../index";
|
7
|
+
import type { CursorMovePayload, ApplianceIcons, CursorOptions } from "../index";
|
8
8
|
import type { PositionType } from "../AttributesDelegate";
|
9
|
-
import type { Point, Room, RoomMember, View } from "white-web-sdk";
|
9
|
+
import type { Point, Room, RoomMember, RoomState, View } from "white-web-sdk";
|
10
10
|
import type { AppManager } from "../AppManager";
|
11
11
|
import { ApplianceMap } from "./icons";
|
12
12
|
import { findMemberByUid } from "../Helper";
|
13
|
+
import { enableLocal } from "./icons2";
|
13
14
|
|
14
15
|
export type EventType = {
|
15
16
|
type: PositionType;
|
@@ -22,19 +23,27 @@ export type MoveCursorParams = {
|
|
22
23
|
y: number;
|
23
24
|
};
|
24
25
|
|
26
|
+
const LocalCursorSideEffectId = "local-cursor";
|
27
|
+
|
25
28
|
export class CursorManager {
|
26
29
|
public containerRect?: DOMRect;
|
27
30
|
public wrapperRect?: DOMRect;
|
28
31
|
public cursorInstances: Map<string, Cursor> = new Map();
|
29
32
|
public roomMembers?: readonly RoomMember[];
|
33
|
+
public userApplianceIcons: ApplianceIcons = {};
|
34
|
+
|
30
35
|
private mainViewElement?: HTMLDivElement;
|
31
36
|
private sideEffectManager = new SideEffectManager();
|
32
37
|
private store = this.manager.store;
|
33
|
-
|
34
|
-
private
|
38
|
+
private leaveFlag = true;
|
39
|
+
private _style: CursorOptions["style"] & string = "default";
|
35
40
|
|
36
|
-
|
37
|
-
|
41
|
+
constructor(
|
42
|
+
private manager: AppManager,
|
43
|
+
private enableCursor: boolean,
|
44
|
+
cursorOptions?: CursorOptions,
|
45
|
+
applianceIcons?: ApplianceIcons
|
46
|
+
) {
|
38
47
|
this.roomMembers = this.manager.room?.state.roomMembers;
|
39
48
|
const wrapper = WindowManager.wrapper;
|
40
49
|
if (wrapper) {
|
@@ -43,12 +52,44 @@ export class CursorManager {
|
|
43
52
|
this.sideEffectManager.add(() => {
|
44
53
|
return internalEmitter.on("cursorMove", this.onCursorMove);
|
45
54
|
});
|
46
|
-
|
47
55
|
this.sideEffectManager.add(() => {
|
48
56
|
return internalEmitter.on("playgroundSizeChange", () => this.updateContainerRect());
|
49
57
|
});
|
58
|
+
const room = this.manager.room;
|
59
|
+
if (room) {
|
60
|
+
this.sideEffectManager.add(() => {
|
61
|
+
const update = (state: RoomState) => {
|
62
|
+
if (this.style === "custom" && state.memberState) this.enableCustomCursor();
|
63
|
+
};
|
64
|
+
room.callbacks.on("onRoomStateChanged", update);
|
65
|
+
return () => room.callbacks.off("onRoomStateChanged", update);
|
66
|
+
});
|
67
|
+
}
|
50
68
|
if (applianceIcons) {
|
51
|
-
this.
|
69
|
+
this.userApplianceIcons = applianceIcons;
|
70
|
+
}
|
71
|
+
this.style = cursorOptions?.style || "default";
|
72
|
+
}
|
73
|
+
|
74
|
+
public get applianceIcons(): ApplianceIcons {
|
75
|
+
return { ...ApplianceMap, ...this.userApplianceIcons };
|
76
|
+
}
|
77
|
+
|
78
|
+
public get style() {
|
79
|
+
return this._style;
|
80
|
+
}
|
81
|
+
|
82
|
+
public set style(value) {
|
83
|
+
if (this._style !== value) {
|
84
|
+
this._style = value;
|
85
|
+
this.cursorInstances.forEach(cursor => {
|
86
|
+
cursor.setStyle(value);
|
87
|
+
});
|
88
|
+
if (value === "custom") {
|
89
|
+
this.enableCustomCursor();
|
90
|
+
} else {
|
91
|
+
this.sideEffectManager.flush(LocalCursorSideEffectId);
|
92
|
+
}
|
52
93
|
}
|
53
94
|
}
|
54
95
|
|
@@ -73,6 +114,13 @@ export class CursorManager {
|
|
73
114
|
return cursorInstance;
|
74
115
|
};
|
75
116
|
|
117
|
+
private enableCustomCursor() {
|
118
|
+
this.sideEffectManager.add(
|
119
|
+
() => enableLocal(this.manager.getMemberState()),
|
120
|
+
LocalCursorSideEffectId
|
121
|
+
);
|
122
|
+
}
|
123
|
+
|
76
124
|
private canMoveCursor(member: RoomMember | undefined) {
|
77
125
|
const isLaserPointer =
|
78
126
|
member?.memberState.currentApplianceName === ApplianceNames.laserPointer;
|
@@ -111,38 +159,48 @@ export class CursorManager {
|
|
111
159
|
const type = this.getType(event);
|
112
160
|
this.updateCursor(type, event.clientX, event.clientY);
|
113
161
|
isTouch && this.showPencilEraserIfNeeded(type, event.clientX, event.clientY);
|
114
|
-
}
|
162
|
+
};
|
115
163
|
|
116
164
|
private mouseMoveTimer = 0;
|
117
165
|
private mouseMoveListener = (event: PointerEvent) => {
|
118
166
|
const isTouch = event.pointerType === "touch";
|
119
167
|
if (isTouch && !event.isPrimary) return;
|
120
|
-
const now = Date.now()
|
168
|
+
const now = Date.now();
|
121
169
|
if (now - this.mouseMoveTimer > 48) {
|
122
170
|
this.mouseMoveTimer = now;
|
123
|
-
if (
|
124
|
-
|
171
|
+
if (
|
172
|
+
WindowManager.supportTeachingAidsPlugin &&
|
173
|
+
isRoom(WindowManager.displayer) &&
|
174
|
+
(WindowManager.displayer as Room).disableDeviceInputs
|
175
|
+
) {
|
176
|
+
if (this.leaveFlag) {
|
125
177
|
this.manager.dispatchInternalEvent(Events.CursorMove, {
|
126
178
|
uid: this.manager.uid,
|
127
|
-
state: CursorState.Leave
|
179
|
+
state: CursorState.Leave,
|
128
180
|
} as CursorMovePayload);
|
129
|
-
this.
|
181
|
+
this.leaveFlag = false;
|
130
182
|
}
|
131
|
-
return
|
183
|
+
return;
|
132
184
|
}
|
133
185
|
this.mouseMoveListener_(event, isTouch);
|
134
|
-
this.
|
186
|
+
this.leaveFlag = true;
|
135
187
|
}
|
136
|
-
}
|
137
|
-
|
188
|
+
};
|
189
|
+
|
138
190
|
private mouseLeaveListener = () => {
|
139
191
|
this.hideCursor(this.manager.uid);
|
140
|
-
}
|
192
|
+
};
|
141
193
|
|
142
194
|
private showPencilEraserIfNeeded(event: EventType, clientX: number, clientY: number) {
|
143
195
|
const self = findMemberByUid(this.manager.room, this.manager.uid);
|
144
|
-
const isPencilEraser =
|
145
|
-
|
196
|
+
const isPencilEraser =
|
197
|
+
self?.memberState.currentApplianceName === ApplianceNames.pencilEraser;
|
198
|
+
if (
|
199
|
+
this.wrapperRect &&
|
200
|
+
this.manager.canOperate &&
|
201
|
+
this.canMoveCursor(self) &&
|
202
|
+
isPencilEraser
|
203
|
+
) {
|
146
204
|
const view = event.type === "main" ? this.manager.mainView : this.focusView;
|
147
205
|
const point = this.getPoint(view, clientX, clientY);
|
148
206
|
if (point) {
|
package/src/index.ts
CHANGED
@@ -126,6 +126,15 @@ export type AppInitState = {
|
|
126
126
|
|
127
127
|
export type CursorMovePayload = { uid: string; state?: "leave"; position: Position };
|
128
128
|
|
129
|
+
export type CursorOptions = {
|
130
|
+
/**
|
131
|
+
* If `"custom"`, it will render the pencil / eraser cursor as a circle and shapes cursor as a cross.
|
132
|
+
*
|
133
|
+
* @default "default"
|
134
|
+
*/
|
135
|
+
style?: "default" | "custom";
|
136
|
+
};
|
137
|
+
|
129
138
|
export type MountParams = {
|
130
139
|
room: Room | Player;
|
131
140
|
container?: HTMLElement;
|
@@ -137,6 +146,7 @@ export type MountParams = {
|
|
137
146
|
collectorStyles?: Partial<CSSStyleDeclaration>;
|
138
147
|
overwriteStyles?: string;
|
139
148
|
cursor?: boolean;
|
149
|
+
cursorOptions?: CursorOptions;
|
140
150
|
debug?: boolean;
|
141
151
|
disableCameraTransform?: boolean;
|
142
152
|
prefersColorScheme?: TeleBoxColorScheme;
|
@@ -148,7 +158,10 @@ export type MountParams = {
|
|
148
158
|
|
149
159
|
export const reconnectRefresher = new ReconnectRefresher({ emitter: internalEmitter });
|
150
160
|
|
151
|
-
export class WindowManager
|
161
|
+
export class WindowManager
|
162
|
+
extends InvisiblePlugin<WindowMangerAttributes, any>
|
163
|
+
implements PageController
|
164
|
+
{
|
152
165
|
public static kind = "WindowManager";
|
153
166
|
public static displayer: Displayer;
|
154
167
|
public static wrapper?: HTMLElement;
|
@@ -249,7 +262,12 @@ export class WindowManager extends InvisiblePlugin<WindowMangerAttributes, any>
|
|
249
262
|
manager.appManager = new AppManager(manager);
|
250
263
|
manager.appManager.polling = params.polling || false;
|
251
264
|
manager._pageState = new PageStateImpl(manager.appManager);
|
252
|
-
manager.cursorManager = new CursorManager(
|
265
|
+
manager.cursorManager = new CursorManager(
|
266
|
+
manager.appManager,
|
267
|
+
Boolean(cursor),
|
268
|
+
params.cursorOptions,
|
269
|
+
params.applianceIcons
|
270
|
+
);
|
253
271
|
if (containerSizeRatio) {
|
254
272
|
manager.containerSizeRatio = containerSizeRatio;
|
255
273
|
}
|
@@ -296,16 +314,12 @@ export class WindowManager extends InvisiblePlugin<WindowMangerAttributes, any>
|
|
296
314
|
manager: WindowManager,
|
297
315
|
container: HTMLElement,
|
298
316
|
params: {
|
299
|
-
chessboard?: boolean
|
300
|
-
overwriteStyles?: string
|
301
|
-
fullscreen?: boolean
|
317
|
+
chessboard?: boolean;
|
318
|
+
overwriteStyles?: string;
|
319
|
+
fullscreen?: boolean;
|
302
320
|
}
|
303
321
|
) {
|
304
|
-
const {
|
305
|
-
chessboard,
|
306
|
-
overwriteStyles,
|
307
|
-
fullscreen,
|
308
|
-
} = params;
|
322
|
+
const { chessboard, overwriteStyles, fullscreen } = params;
|
309
323
|
if (!WindowManager.container) {
|
310
324
|
WindowManager.container = container;
|
311
325
|
}
|
@@ -370,7 +384,7 @@ export class WindowManager extends InvisiblePlugin<WindowMangerAttributes, any>
|
|
370
384
|
this.appManager?.resetMaximized();
|
371
385
|
this.appManager?.resetMinimized();
|
372
386
|
this.appManager?.displayerWritableListener(!this.room.isWritable);
|
373
|
-
WindowManager.container = container;
|
387
|
+
WindowManager.container = container;
|
374
388
|
}
|
375
389
|
|
376
390
|
public bindCollectorContainer(container: HTMLElement) {
|
@@ -581,7 +595,7 @@ export class WindowManager extends InvisiblePlugin<WindowMangerAttributes, any>
|
|
581
595
|
console.warn(`[WindowManager]: index ${index} out of range`);
|
582
596
|
return false;
|
583
597
|
}
|
584
|
-
return this.appManager.removeSceneByIndex(needRemoveIndex)
|
598
|
+
return this.appManager.removeSceneByIndex(needRemoveIndex);
|
585
599
|
} else {
|
586
600
|
return false;
|
587
601
|
}
|
@@ -629,7 +643,10 @@ export class WindowManager extends InvisiblePlugin<WindowMangerAttributes, any>
|
|
629
643
|
*
|
630
644
|
* 返回一个用于撤销此监听的函数
|
631
645
|
*/
|
632
|
-
public onAppEvent(
|
646
|
+
public onAppEvent(
|
647
|
+
kind: string,
|
648
|
+
listener: (args: { kind: string; appId: string; type: string; value: any }) => void
|
649
|
+
): () => void {
|
633
650
|
return internalEmitter.on(`custom-${kind}` as any, listener);
|
634
651
|
}
|
635
652
|
|
@@ -753,6 +770,17 @@ export class WindowManager extends InvisiblePlugin<WindowMangerAttributes, any>
|
|
753
770
|
}
|
754
771
|
}
|
755
772
|
|
773
|
+
public get cursorStyle(): "default" | "custom" {
|
774
|
+
return this.cursorManager?.style || "default";
|
775
|
+
}
|
776
|
+
|
777
|
+
public set cursorStyle(value: "default" | "custom") {
|
778
|
+
if (!this.cursorManager) {
|
779
|
+
throw new Error("[WindowManager]: cursor is not enabled, please set { cursor: true }.");
|
780
|
+
}
|
781
|
+
this.cursorManager.style = value;
|
782
|
+
}
|
783
|
+
|
756
784
|
public get mainViewSceneIndex(): number {
|
757
785
|
return this._pageState?.index || 0;
|
758
786
|
}
|
@@ -982,8 +1010,8 @@ export class WindowManager extends InvisiblePlugin<WindowMangerAttributes, any>
|
|
982
1010
|
}
|
983
1011
|
|
984
1012
|
public refresh() {
|
985
|
-
|
986
|
-
|
1013
|
+
this._refresh();
|
1014
|
+
this.appManager?.dispatchInternalEvent(Events.Refresh);
|
987
1015
|
}
|
988
1016
|
|
989
1017
|
/** @inner */
|
@@ -997,7 +1025,9 @@ export class WindowManager extends InvisiblePlugin<WindowMangerAttributes, any>
|
|
997
1025
|
|
998
1026
|
public setContainerSizeRatio(ratio: number) {
|
999
1027
|
if (!isNumber(ratio) || !(ratio > 0)) {
|
1000
|
-
throw new Error(
|
1028
|
+
throw new Error(
|
1029
|
+
`[WindowManager]: updateContainerSizeRatio error, ratio must be a positive number. but got ${ratio}`
|
1030
|
+
);
|
1001
1031
|
}
|
1002
1032
|
WindowManager.containerSizeRatio = ratio;
|
1003
1033
|
this.containerSizeRatio = ratio;
|