@netless/window-manager 0.4.70 → 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/typings.d.ts CHANGED
@@ -78,3 +78,7 @@ export type { SceneState, SceneDefinition, View, AnimationMode, Displayer, Room,
78
78
  export type { Storage, StorageStateChangedEvent, StorageStateChangedListener } from "./App/Storage";
79
79
  export * from "./Page";
80
80
  export * from "./Utils/error";
81
+ export declare type AppPayload = {
82
+ appId: string;
83
+ view: View;
84
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@netless/window-manager",
3
- "version": "0.4.70",
3
+ "version": "0.4.71",
4
4
  "description": "Multi-window mode for Netless Whiteboard",
5
5
  "author": "l1shen <lishen1635@gmail.com> (https://github.com/l1shen)",
6
6
  "license": "MIT",
@@ -29,6 +29,8 @@ import type {
29
29
  } from "./MagixEvent";
30
30
  import type { AddPageParams, PageController, PageState } from "../Page";
31
31
  import { internalEmitter } from "../InternalEmitter";
32
+ import { WindowManager } from "../index";
33
+ import { callbacks } from "../callback";
32
34
 
33
35
  export class AppContext<TAttributes extends {} = any, TMagixEventPayloads = any, TAppOptions = any>
34
36
  implements PageController
@@ -90,6 +92,9 @@ export class AppContext<TAttributes extends {} = any, TMagixEventPayloads = any,
90
92
  setTimeout(() => {
91
93
  // 渲染需要时间,延迟 refresh
92
94
  this.getRoom()?.refreshViewSize();
95
+ if (WindowManager.supportTeachingAidsPlugin) {
96
+ callbacks.emit("onAppViewMounted", {appId: this.appId, view});
97
+ }
93
98
  }, 1000);
94
99
  }
95
100
  };
@@ -30,6 +30,8 @@ import type { ReadonlyTeleBox } from "@netless/telebox-insider";
30
30
  import type { PageRemoveService, PageState } from "../Page";
31
31
  import { calculateNextIndex } from "../Page";
32
32
  import { boxEmitter } from "../BoxEmitter";
33
+ import { WindowManager } from "../index";
34
+ import { callbacks } from "../callback";
33
35
 
34
36
  export type AppEmitter = Emittery<AppEmitterEvent>;
35
37
 
@@ -194,6 +196,9 @@ export class AppProxy implements PageRemoveService {
194
196
  appRegister.notifyApp(this.kind, "created", { appId, result });
195
197
  this.afterSetupApp(boxInitState);
196
198
  this.fixMobileSize();
199
+ if (WindowManager.supportTeachingAidsPlugin) {
200
+ callbacks.emit("onAppSetup", appId);
201
+ }
197
202
  }, SETUP_APP_DELAY);
198
203
  });
199
204
  this.boxManager?.createBox({
@@ -391,6 +396,9 @@ export class AppProxy implements PageRemoveService {
391
396
  private setFocusScenePathHandler = debounce((fullPath: string | undefined) => {
392
397
  if (this.view && fullPath && fullPath !== this.view?.focusScenePath) {
393
398
  setViewFocusScenePath(this.view, fullPath);
399
+ if (WindowManager.supportTeachingAidsPlugin) {
400
+ callbacks.emit("onAppScenePathChange", {appId: this.id, view:this.view});
401
+ }
394
402
  }
395
403
  }, 50);
396
404
 
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 { Displayer, Room, ScenesCallbacksNode, SceneState, RoomState } from "white-web-sdk";
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 设置为初始值
@@ -373,6 +384,9 @@ export class AppManager {
373
384
  x: payload.x,
374
385
  y: payload.y,
375
386
  });
387
+ if (WindowManager.supportTeachingAidsPlugin) {
388
+ callbacks.emit("onBoxMove", payload);
389
+ }
376
390
  };
377
391
 
378
392
  private onBoxResize = (payload: BoxResizePayload) => {
@@ -382,11 +396,18 @@ export class AppManager {
382
396
  width: payload.width,
383
397
  height: payload.height,
384
398
  });
399
+ if (WindowManager.supportTeachingAidsPlugin) {
400
+ callbacks.emit("onBoxResize", payload);
401
+ }
385
402
  }
386
403
  };
387
404
 
388
405
  private onBoxFocus = (payload: BoxFocusPayload) => {
389
406
  this.windowManger.safeSetAttributes({ focus: payload.appId });
407
+ if (WindowManager.supportTeachingAidsPlugin) {
408
+ // (WindowManager.externalNotifyManager as any).emit('onBoxFocus', payload)
409
+ callbacks.emit("onBoxFocus", payload);
410
+ }
390
411
  };
391
412
 
392
413
  private onBoxClose = (payload: BoxClosePayload) => {
@@ -394,10 +415,16 @@ export class AppManager {
394
415
  if (appProxy) {
395
416
  appProxy.destroy(false, true, true, payload.error);
396
417
  }
418
+ if (WindowManager.supportTeachingAidsPlugin) {
419
+ callbacks.emit("onBoxClose", payload);
420
+ }
397
421
  };
398
422
 
399
423
  private onBoxStateChange = (payload: BoxStateChangePayload) => {
400
424
  this.dispatchInternalEvent(Events.AppBoxStateChange, payload);
425
+ if (WindowManager.supportTeachingAidsPlugin) {
426
+ callbacks.emit("onBoxStateChange", payload);
427
+ }
401
428
  };
402
429
 
403
430
  public addAppsChangeListener = () => {
@@ -581,6 +608,9 @@ export class AppManager {
581
608
  this.setMainViewFocusPath();
582
609
  }
583
610
  internalEmitter.emit("mainViewMounted");
611
+ if (WindowManager.supportTeachingAidsPlugin) {
612
+ callbacks.emit("onMainViewMounted", mainView);
613
+ }
584
614
  }
585
615
 
586
616
  public setMainViewFocusPath(scenePath?: string) {
@@ -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 class="netless-window-manager-cursor-{appliance}-image {pencilEraserSize3ImageOffset}" {src} alt={appliance} />
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;
@@ -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 { CursorManager } from "./index";
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?: SvelteComponent;
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
- const icons = this.cursorManager.applianceIcons;
163
- let applianceSrc = icons[ApplianceNames.shape];
164
- if (this.memberApplianceName === ApplianceNames.pencilEraser) {
165
- const size = this.member?.memberState.pencilEraserSize || 1;
166
- applianceSrc = icons[`${this.memberApplianceName}${size}`];
167
- } else {
168
- applianceSrc = icons[this.memberApplianceName || ApplianceNames.shape];
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
+ }
@@ -1,15 +1,16 @@
1
- import { ApplianceNames } from "white-web-sdk";
1
+ import { ApplianceNames, isRoom } from "white-web-sdk";
2
2
  import { Cursor } from "./Cursor";
3
3
  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, 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,17 +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
- public applianceIcons: ApplianceIcons = ApplianceMap;
38
+ private leaveFlag = true;
39
+ private _style: CursorOptions["style"] & string = "default";
34
40
 
35
- constructor(private manager: AppManager, private enableCursor: boolean, applianceIcons?: ApplianceIcons) {
41
+ constructor(
42
+ private manager: AppManager,
43
+ private enableCursor: boolean,
44
+ cursorOptions?: CursorOptions,
45
+ applianceIcons?: ApplianceIcons
46
+ ) {
36
47
  this.roomMembers = this.manager.room?.state.roomMembers;
37
48
  const wrapper = WindowManager.wrapper;
38
49
  if (wrapper) {
@@ -41,12 +52,44 @@ export class CursorManager {
41
52
  this.sideEffectManager.add(() => {
42
53
  return internalEmitter.on("cursorMove", this.onCursorMove);
43
54
  });
44
-
45
55
  this.sideEffectManager.add(() => {
46
56
  return internalEmitter.on("playgroundSizeChange", () => this.updateContainerRect());
47
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
+ }
48
68
  if (applianceIcons) {
49
- this.applianceIcons = { ...ApplianceMap, ...applianceIcons };
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
+ }
50
93
  }
51
94
  }
52
95
 
@@ -71,6 +114,13 @@ export class CursorManager {
71
114
  return cursorInstance;
72
115
  };
73
116
 
117
+ private enableCustomCursor() {
118
+ this.sideEffectManager.add(
119
+ () => enableLocal(this.manager.getMemberState()),
120
+ LocalCursorSideEffectId
121
+ );
122
+ }
123
+
74
124
  private canMoveCursor(member: RoomMember | undefined) {
75
125
  const isLaserPointer =
76
126
  member?.memberState.currentApplianceName === ApplianceNames.laserPointer;
@@ -109,28 +159,48 @@ export class CursorManager {
109
159
  const type = this.getType(event);
110
160
  this.updateCursor(type, event.clientX, event.clientY);
111
161
  isTouch && this.showPencilEraserIfNeeded(type, event.clientX, event.clientY);
112
- }
162
+ };
113
163
 
114
164
  private mouseMoveTimer = 0;
115
165
  private mouseMoveListener = (event: PointerEvent) => {
116
166
  const isTouch = event.pointerType === "touch";
117
167
  if (isTouch && !event.isPrimary) return;
118
-
119
- const now = Date.now()
168
+ const now = Date.now();
120
169
  if (now - this.mouseMoveTimer > 48) {
121
170
  this.mouseMoveTimer = now;
171
+ if (
172
+ WindowManager.supportTeachingAidsPlugin &&
173
+ isRoom(WindowManager.displayer) &&
174
+ (WindowManager.displayer as Room).disableDeviceInputs
175
+ ) {
176
+ if (this.leaveFlag) {
177
+ this.manager.dispatchInternalEvent(Events.CursorMove, {
178
+ uid: this.manager.uid,
179
+ state: CursorState.Leave,
180
+ } as CursorMovePayload);
181
+ this.leaveFlag = false;
182
+ }
183
+ return;
184
+ }
122
185
  this.mouseMoveListener_(event, isTouch);
186
+ this.leaveFlag = true;
123
187
  }
124
- }
188
+ };
125
189
 
126
190
  private mouseLeaveListener = () => {
127
191
  this.hideCursor(this.manager.uid);
128
- }
192
+ };
129
193
 
130
194
  private showPencilEraserIfNeeded(event: EventType, clientX: number, clientY: number) {
131
195
  const self = findMemberByUid(this.manager.room, this.manager.uid);
132
- const isPencilEraser = self?.memberState.currentApplianceName === ApplianceNames.pencilEraser;
133
- if (this.wrapperRect && this.manager.canOperate && this.canMoveCursor(self) && isPencilEraser) {
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
+ ) {
134
204
  const view = event.type === "main" ? this.manager.mainView : this.focusView;
135
205
  const point = this.getPoint(view, clientX, clientY);
136
206
  if (point) {
package/src/callback.ts CHANGED
@@ -1,8 +1,10 @@
1
1
  import Emittery from "emittery";
2
2
  import type { TeleBoxColorScheme, TELE_BOX_STATE } from "@netless/telebox-insider";
3
- import type { CameraState, SceneState, ViewVisionMode } from "white-web-sdk";
3
+ import type { CameraState, SceneState, View, ViewVisionMode } from "white-web-sdk";
4
4
  import type { LoadAppEvent } from "./Register";
5
5
  import type { PageState } from "./Page";
6
+ import type { BoxClosePayload, BoxFocusPayload, BoxMovePayload, BoxResizePayload, BoxStateChangePayload } from "./BoxEmitter";
7
+ import type { AppPayload } from "./typings";
6
8
 
7
9
  export type PublicEvent = {
8
10
  mainViewModeChange: ViewVisionMode;
@@ -22,6 +24,15 @@ export type PublicEvent = {
22
24
  pageStateChange: PageState;
23
25
  fullscreenChange: boolean;
24
26
  appsChange: string[]; // APP 列表变化时触发
27
+ onBoxMove: BoxMovePayload;
28
+ onBoxResize: BoxResizePayload;
29
+ onBoxFocus: BoxFocusPayload;
30
+ onBoxClose: BoxClosePayload;
31
+ onBoxStateChange: BoxStateChangePayload;
32
+ onMainViewMounted: View;
33
+ onAppViewMounted: AppPayload;
34
+ onAppSetup: string;
35
+ onAppScenePathChange: AppPayload;
25
36
  };
26
37
 
27
38
  export type CallbacksType = Emittery<PublicEvent>;