@netless/telebox-insider 0.2.10 → 0.2.14

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@netless/telebox-insider",
3
- "version": "0.2.10",
3
+ "version": "0.2.14",
4
4
  "private": false,
5
5
  "description": "Window widget for Whiteboard",
6
6
  "license": "MIT",
@@ -21,6 +21,7 @@ export enum TELE_BOX_EVENT {
21
21
  IntrinsicMove = "intrinsic_move",
22
22
  IntrinsicResize = "intrinsic_resize",
23
23
  VisualResize = "visual_resize",
24
+ ZIndex = "z_index",
24
25
  State = "state",
25
26
  Minimized = "minimized",
26
27
  Maximized = "maximized",
@@ -197,7 +197,13 @@ export class TeleBox {
197
197
  const draggable$ = createVal(draggable);
198
198
  const fence$ = createVal(fence);
199
199
  const fixRatio$ = createVal(fixRatio);
200
+
200
201
  const zIndex$ = createVal(zIndex);
202
+ zIndex$.reaction((zIndex, _, skipUpdate) => {
203
+ if (!skipUpdate) {
204
+ this.events.emit(TELE_BOX_EVENT.ZIndex, zIndex);
205
+ }
206
+ });
201
207
 
202
208
  const focus$ = createVal(focus);
203
209
  focus$.reaction((focus, _, skipUpdate) => {
@@ -96,6 +96,7 @@ export type TeleBoxEventConfig = CheckTeleBoxConfig<{
96
96
  intrinsic_move: { x: number; y: number };
97
97
  intrinsic_resize: { width: number; height: number };
98
98
  visual_resize: { width: number; height: number };
99
+ z_index: number;
99
100
  state: TeleBoxState;
100
101
  minimized: boolean;
101
102
  maximized: boolean;
@@ -25,10 +25,6 @@ export class MaxTitleBar extends DefaultTitleBar {
25
25
  }
26
26
 
27
27
  public focusBox(box?: MaxTitleBarTeleBox): void {
28
- if (!box) {
29
- box = this.boxes[this.boxes.length - 1];
30
- }
31
-
32
28
  if (this.focusedBox && this.focusedBox === box) {
33
29
  return;
34
30
  }
@@ -200,7 +196,7 @@ export class MaxTitleBar extends DefaultTitleBar {
200
196
 
201
197
  protected boxes: MaxTitleBarTeleBox[];
202
198
 
203
- protected focusedBox: MaxTitleBarTeleBox | undefined;
199
+ public focusedBox: MaxTitleBarTeleBox | undefined;
204
200
 
205
201
  protected containerRect: TeleBoxRect;
206
202
  }
@@ -1,5 +1,6 @@
1
1
  export enum TELE_BOX_MANAGER_EVENT {
2
2
  Focused = "focused",
3
+ Blurred = "blurred",
3
4
  Created = "created",
4
5
  Removed = "removed",
5
6
  State = "state",
@@ -10,6 +11,7 @@ export enum TELE_BOX_MANAGER_EVENT {
10
11
  IntrinsicMove = "intrinsic_move",
11
12
  IntrinsicResize = "intrinsic_resize",
12
13
  VisualResize = "visual_resize",
14
+ ZIndex = "z_index",
13
15
  PrefersColorScheme = "prefers_color_scheme",
14
16
  DarkMode = "dark_mode",
15
17
  }
@@ -59,7 +59,6 @@ export class TeleBoxManager {
59
59
  },
60
60
  collector,
61
61
  namespace = "telebox",
62
- zIndex = 100,
63
62
  readonly = false,
64
63
  }: TeleBoxManagerConfig = {}) {
65
64
  this._sideEffect = new SideEffectManager();
@@ -67,7 +66,17 @@ export class TeleBoxManager {
67
66
 
68
67
  this.root = root;
69
68
  this.namespace = namespace;
70
- this.zIndex = zIndex;
69
+
70
+ this.boxes$ = createVal<TeleBox[]>([]);
71
+ this.topBox$ = this.boxes$.derive((boxes) => {
72
+ if (boxes.length > 0) {
73
+ const topBox = boxes.reduce((topBox, box) =>
74
+ topBox.zIndex > box.zIndex ? topBox : box
75
+ );
76
+ return topBox;
77
+ }
78
+ return;
79
+ });
71
80
 
72
81
  const prefersDark = window.matchMedia("(prefers-color-scheme: dark)");
73
82
  const prefersDark$ = createVal(false);
@@ -221,6 +230,8 @@ export class TeleBoxManager {
221
230
  }
222
231
  });
223
232
 
233
+ const closeBtnClassName = this.wrapClassName("titlebar-icon-close");
234
+
224
235
  const checkFocusBox = (ev: MouseEvent | TouchEvent): void => {
225
236
  if (readonly$.value) {
226
237
  return;
@@ -236,11 +247,14 @@ export class TeleBoxManager {
236
247
  el;
237
248
  el = el.parentElement
238
249
  ) {
250
+ if (el.classList && el.classList.contains(closeBtnClassName)) {
251
+ return;
252
+ }
239
253
  const id = el.dataset?.teleBoxID;
240
254
  if (id) {
241
- const box = this.boxes.find((box) => box.id === id);
255
+ const box = this.getBox(id);
242
256
  if (box) {
243
- this.focusBox({ focus: true, box });
257
+ this.focusBox(box);
244
258
  return;
245
259
  }
246
260
  }
@@ -265,8 +279,7 @@ export class TeleBoxManager {
265
279
  readonly: readonly$.value,
266
280
  namespace: this.namespace,
267
281
  state: state$.value,
268
- boxes: this.boxes,
269
- focusedBox: this._focusedBox,
282
+ boxes: this.boxes$.value,
270
283
  containerRect: containerRect$.value,
271
284
  onEvent: (event): void => {
272
285
  switch (event.type) {
@@ -279,12 +292,7 @@ export class TeleBoxManager {
279
292
  break;
280
293
  }
281
294
  case TELE_BOX_EVENT.Close: {
282
- const box =
283
- this._focusedBox ??
284
- this.boxes[this.boxes.length - 1];
285
- if (box) {
286
- this.remove(box.id);
287
- }
295
+ this.removeTopBox();
288
296
  break;
289
297
  }
290
298
  default: {
@@ -299,6 +307,9 @@ export class TeleBoxManager {
299
307
  this._darkMode$.subscribe((darkMode) => {
300
308
  this.maxTitleBar.setDarkMode(darkMode);
301
309
  });
310
+ this.boxes$.reaction((boxes) => {
311
+ this.maxTitleBar.setBoxes(boxes);
312
+ });
302
313
 
303
314
  const valConfig: ValConfig = {
304
315
  prefersColorScheme: prefersColorScheme$,
@@ -317,6 +328,14 @@ export class TeleBoxManager {
317
328
  this.root.appendChild(this.maxTitleBar.render());
318
329
  }
319
330
 
331
+ public get boxes(): ReadonlyArray<TeleBox> {
332
+ return this.boxes$.value;
333
+ }
334
+
335
+ public get topBox(): TeleBox | undefined {
336
+ return this.topBox$.value;
337
+ }
338
+
320
339
  public readonly events = new EventEmitter() as TeleBoxManagerEvents;
321
340
 
322
341
  protected _sideEffect: SideEffectManager;
@@ -325,8 +344,6 @@ export class TeleBoxManager {
325
344
 
326
345
  public readonly namespace: string;
327
346
 
328
- public zIndex: number;
329
-
330
347
  public _darkMode$: Val<boolean, boolean>;
331
348
 
332
349
  public get darkMode(): boolean {
@@ -361,16 +378,30 @@ export class TeleBoxManager {
361
378
  return this;
362
379
  }
363
380
 
364
- public create(config?: TeleBoxManagerCreateConfig): ReadonlyTeleBox {
365
- const box = new TeleBox(this.wrapCreateConfig(config));
381
+ public create(
382
+ config: TeleBoxManagerCreateConfig = {},
383
+ smartPosition = true
384
+ ): ReadonlyTeleBox {
385
+ const box = new TeleBox({
386
+ zIndex: this.topBox ? this.topBox.zIndex + 1 : 100,
387
+ ...(smartPosition ? this.smartPosition(config) : config),
388
+ darkMode: this.darkMode,
389
+ prefersColorScheme: this.prefersColorScheme,
390
+ maximized: this.maximized,
391
+ minimized: this.minimized,
392
+ fence: this.fence,
393
+ namespace: this.namespace,
394
+ containerRect: this.containerRect,
395
+ readonly: this.readonly,
396
+ });
397
+
366
398
  box.mount(this.root);
367
- this.boxes.push(box);
368
399
 
369
400
  if (box.focus) {
370
- this.focusBox({ focus: true, box, increaseZIndex: false });
401
+ this.focusBox(box);
371
402
  }
372
403
 
373
- this.maxTitleBar.setBoxes(this.boxes);
404
+ this.boxes$.setValue([...this.boxes, box]);
374
405
 
375
406
  box._delegateEvents.on(TELE_BOX_DELEGATE_EVENT.Maximize, () => {
376
407
  this.setMaximized(!this.maximized);
@@ -379,8 +410,7 @@ export class TeleBoxManager {
379
410
  this.setMinimized(true);
380
411
  });
381
412
  box._delegateEvents.on(TELE_BOX_DELEGATE_EVENT.Close, () => {
382
- this.focusBox({ focus: false, box });
383
- this.remove(box.id);
413
+ this.remove(box);
384
414
  });
385
415
  box.events.on(TELE_BOX_EVENT.Move, () => {
386
416
  this.events.emit(TELE_BOX_MANAGER_EVENT.Move, box);
@@ -437,57 +467,52 @@ export class TeleBoxManager {
437
467
  }
438
468
 
439
469
  public remove(
440
- boxID: string,
470
+ boxOrID: string | TeleBox,
441
471
  skipUpdate = false
442
472
  ): ReadonlyTeleBox | undefined {
443
- const index = this.boxes.findIndex((box) => box.id === boxID);
473
+ const index = this.getBoxIndex(boxOrID);
444
474
  if (index >= 0) {
445
- const boxes = this.boxes.splice(index, 1);
446
- this.maxTitleBar.setBoxes(this.boxes);
447
- const box = boxes[0];
448
- this.focusBox({ focus: false, box });
449
- box.destroy();
475
+ const boxes = this.boxes.slice();
476
+ const deletedBoxes = boxes.splice(index, 1);
477
+ this.boxes$.setValue(boxes);
478
+ this.focusTopBox();
479
+ deletedBoxes.forEach((box) => box.destroy());
450
480
  if (!skipUpdate) {
451
481
  if (this.boxes.length <= 0) {
452
482
  this.setMaximized(false);
453
483
  this.setMinimized(false);
454
484
  }
455
- this.events.emit(TELE_BOX_MANAGER_EVENT.Removed, boxes);
485
+ this.events.emit(TELE_BOX_MANAGER_EVENT.Removed, deletedBoxes);
456
486
  }
457
- return box;
487
+ return deletedBoxes[0];
458
488
  }
459
489
  return;
460
490
  }
461
491
 
462
- public removeAll(skipUpdate = false): ReadonlyTeleBox[] {
463
- if (this._focusedBox) {
464
- const box = this._focusedBox;
465
- this._focusedBox = void 0;
466
- if (!skipUpdate) {
467
- this.events.emit(
468
- TELE_BOX_MANAGER_EVENT.Focused,
469
- undefined,
470
- box
471
- );
472
- }
492
+ public removeTopBox(): ReadonlyTeleBox | undefined {
493
+ if (this.topBox) {
494
+ return this.remove(this.topBox);
473
495
  }
474
- const boxes = this.boxes.splice(0, this.boxes.length);
475
- this.maxTitleBar.setBoxes(this.boxes);
476
- boxes.forEach((box) => box.destroy());
496
+ return;
497
+ }
498
+
499
+ public removeAll(skipUpdate = false): ReadonlyTeleBox[] {
500
+ const deletedBoxes = this.boxes$.value;
501
+ this.boxes$.setValue([]);
502
+ deletedBoxes.forEach((box) => box.destroy());
477
503
  if (!skipUpdate) {
478
504
  if (this.boxes.length <= 0) {
479
505
  this.setMaximized(false);
480
506
  this.setMinimized(false);
481
507
  }
482
- this.events.emit(TELE_BOX_MANAGER_EVENT.Removed, boxes);
508
+ this.events.emit(TELE_BOX_MANAGER_EVENT.Removed, deletedBoxes);
483
509
  }
484
- return boxes;
510
+ return deletedBoxes;
485
511
  }
486
512
 
487
513
  public destroy(skipUpdate = false): void {
488
514
  this.events.removeAllListeners();
489
515
  this._sideEffect.flushAll();
490
- this._focusedBox = void 0;
491
516
  this.removeAll(skipUpdate);
492
517
 
493
518
  Object.keys(this).forEach((key) => {
@@ -502,13 +527,70 @@ export class TeleBoxManager {
502
527
  return `${this.namespace}-${className}`;
503
528
  }
504
529
 
505
- protected maxTitleBar: MaxTitleBar;
530
+ public focusBox(boxOrID: string | TeleBox, skipUpdate = false): void {
531
+ const targetBox = this.getBox(boxOrID);
532
+ if (targetBox) {
533
+ this.boxes.forEach((box) => {
534
+ if (targetBox === box) {
535
+ let focusChanged = false;
536
+ if (!targetBox.focus) {
537
+ focusChanged = true;
538
+ targetBox.setFocus(true, skipUpdate);
539
+ }
540
+ this.makeBoxTop(targetBox, skipUpdate);
541
+ if (focusChanged && !skipUpdate) {
542
+ this.events.emit(
543
+ TELE_BOX_MANAGER_EVENT.Focused,
544
+ targetBox
545
+ );
546
+ }
547
+ } else if (box.focus) {
548
+ this.blurBox(box, skipUpdate);
549
+ }
550
+ });
551
+ this.maxTitleBar.focusBox(targetBox);
552
+ }
553
+ }
506
554
 
507
- protected _focusedBox: TeleBox | undefined;
555
+ public focusTopBox(): void {
556
+ if (this.topBox && !this.topBox.focus) {
557
+ return this.focusBox(this.topBox);
558
+ }
559
+ }
508
560
 
509
- protected boxes: TeleBox[] = [];
561
+ public blurBox(boxOrID: string | TeleBox, skipUpdate = false): void {
562
+ const targetBox = this.getBox(boxOrID);
563
+ if (targetBox) {
564
+ if (targetBox.focus) {
565
+ targetBox.setFocus(false, skipUpdate);
566
+ if (!skipUpdate) {
567
+ this.events.emit(TELE_BOX_MANAGER_EVENT.Blurred, targetBox);
568
+ }
569
+ }
570
+ if (this.maxTitleBar.focusedBox === targetBox) {
571
+ this.maxTitleBar.focusBox();
572
+ }
573
+ }
574
+ }
510
575
 
511
- protected lastState: TeleBoxState | undefined;
576
+ public blurAll(skipUpdate = false): void {
577
+ this.boxes.forEach((box) => {
578
+ if (box.focus) {
579
+ box.setFocus(false, skipUpdate);
580
+ if (!skipUpdate) {
581
+ this.events.emit(TELE_BOX_MANAGER_EVENT.Blurred, box);
582
+ }
583
+ }
584
+ });
585
+ if (this.maxTitleBar.focusedBox) {
586
+ this.maxTitleBar.focusBox();
587
+ }
588
+ }
589
+
590
+ protected maxTitleBar: MaxTitleBar;
591
+
592
+ protected boxes$: Val<TeleBox[]>;
593
+ protected topBox$: Val<TeleBox | undefined>;
512
594
 
513
595
  protected teleBoxMatcher(
514
596
  config: TeleBoxManagerQueryConfig
@@ -561,9 +643,6 @@ export class TeleBoxManager {
561
643
  if (config.fixRatio != null) {
562
644
  box.setFixRatio(config.fixRatio, skipUpdate);
563
645
  }
564
- if (config.focus != null) {
565
- this.focusBox({ focus: config.focus, box, skipUpdate });
566
- }
567
646
  if (config.content != null) {
568
647
  box.mountContent(config.content);
569
648
  }
@@ -572,119 +651,67 @@ export class TeleBoxManager {
572
651
  }
573
652
  }
574
653
 
575
- protected focusBox({
576
- focus,
577
- box,
578
- skipUpdate = false,
579
- increaseZIndex = true,
580
- }: {
581
- focus: boolean;
582
- box: TeleBox;
583
- skipUpdate?: boolean;
584
- increaseZIndex?: boolean;
585
- }): void {
586
- box.setFocus(focus, skipUpdate);
587
- if (box.focus) {
588
- if (this._focusedBox !== box) {
589
- const lastFocusedBox = this._focusedBox;
590
- if (this._focusedBox) {
591
- this._focusedBox.setFocus(false, skipUpdate);
592
- }
593
- this._focusedBox = box;
594
- if (increaseZIndex) {
595
- box.setZIndex(++this.zIndex);
596
- }
597
- if (!skipUpdate) {
598
- this.events.emit(
599
- TELE_BOX_MANAGER_EVENT.Focused,
600
- box,
601
- lastFocusedBox
602
- );
603
- }
604
- }
605
- } else {
606
- if (this._focusedBox === box) {
607
- this._focusedBox = void 0;
654
+ protected smartPosition(config: TeleBoxConfig = {}): TeleBoxConfig {
655
+ let { x, y } = config;
656
+ const { width = 0.5, height = 0.5 } = config;
608
657
 
609
- if (!skipUpdate) {
610
- this.events.emit(
611
- TELE_BOX_MANAGER_EVENT.Focused,
612
- undefined,
613
- box
614
- );
658
+ if (x == null) {
659
+ let vx = 20;
660
+ if (this.topBox) {
661
+ vx = this.topBox.intrinsicX * this.containerRect.width + 20;
662
+
663
+ if (
664
+ vx >
665
+ this.containerRect.width - width * this.containerRect.width
666
+ ) {
667
+ vx = 20;
615
668
  }
616
669
  }
670
+ x = vx / this.containerRect.width;
617
671
  }
618
- this.maxTitleBar.focusBox(this._focusedBox);
619
- }
620
-
621
- protected getInitialPosition(
622
- width: number,
623
- height: number
624
- ): { x: number; y: number } {
625
- const upMostBox =
626
- this.boxes.length > 0 &&
627
- this.boxes.reduce((box1, box2) =>
628
- box1.zIndex > box2.zIndex ? box1 : box2
629
- );
630
672
 
631
- let x = 20;
632
- let y = 20;
673
+ if (y == null) {
674
+ let vy = 20;
633
675
 
634
- if (upMostBox) {
635
- x = upMostBox.intrinsicX * this.containerRect.width + 20;
636
- y = upMostBox.intrinsicY * this.containerRect.height + 20;
676
+ if (this.topBox) {
677
+ vy = this.topBox.intrinsicY * this.containerRect.height + 20;
637
678
 
638
- if (
639
- x >
640
- this.containerRect.width -
641
- width * this.containerRect.width ||
642
- y >
679
+ if (
680
+ vy >
643
681
  this.containerRect.height -
644
682
  height * this.containerRect.height
645
- ) {
646
- x = 20;
647
- y = 20;
683
+ ) {
684
+ vy = 20;
685
+ }
648
686
  }
687
+
688
+ y = vy / this.containerRect.height;
649
689
  }
650
690
 
651
- return {
652
- x: x / this.containerRect.width,
653
- y: y / this.containerRect.height,
654
- };
691
+ return { ...config, x, y, width, height };
655
692
  }
656
693
 
657
- protected wrapCreateConfig(config: TeleBoxConfig = {}): TeleBoxConfig {
658
- let { x, y } = config;
659
- const { width = 0.5, height = 0.5 } = config;
660
-
661
- if (x == null || y == null) {
662
- const initialPos = this.getInitialPosition(width, height);
663
-
664
- if (x == null) {
665
- x = initialPos.x;
666
- }
667
-
668
- if (y == null) {
669
- y = initialPos.y;
694
+ protected makeBoxTop(box: TeleBox, skipUpdate = false): void {
695
+ if (this.topBox) {
696
+ if (box !== this.topBox) {
697
+ box.setZIndex(this.topBox.zIndex + 1, skipUpdate);
698
+ this.topBox$.setValue(box);
699
+ if (!skipUpdate) {
700
+ this.events.emit(TELE_BOX_MANAGER_EVENT.ZIndex, box);
701
+ }
670
702
  }
671
703
  }
704
+ }
672
705
 
673
- return {
674
- ...config,
675
- x,
676
- y,
677
- width,
678
- height,
679
- darkMode: this.darkMode,
680
- prefersColorScheme: this.prefersColorScheme,
681
- maximized: this.maximized,
682
- minimized: this.minimized,
683
- fence: this.fence,
684
- zIndex: this.zIndex,
685
- namespace: this.namespace,
686
- containerRect: this.containerRect,
687
- readonly: this.readonly,
688
- };
706
+ protected getBoxIndex(boxOrID: TeleBox | string): number {
707
+ return typeof boxOrID === "string"
708
+ ? this.boxes.findIndex((box) => box.id === boxOrID)
709
+ : this.boxes.findIndex((box) => box === boxOrID);
710
+ }
711
+
712
+ protected getBox(boxOrID: TeleBox | string): TeleBox | undefined {
713
+ return typeof boxOrID === "string"
714
+ ? this.boxes.find((box) => box.id === boxOrID)
715
+ : boxOrID;
689
716
  }
690
717
  }
@@ -14,7 +14,6 @@ export interface TeleBoxManagerConfig
14
14
  | "maximized"
15
15
  | "minimized"
16
16
  | "namespace"
17
- | "zIndex"
18
17
  | "readonly"
19
18
  > {
20
19
  /** Element to mount boxes. */
@@ -35,16 +34,16 @@ type TeleBoxManagerBoxConfigBaseProps =
35
34
  | "resizable"
36
35
  | "draggable"
37
36
  | "fixRatio"
38
- | "focus";
37
+ | "zIndex";
39
38
 
40
39
  export type TeleBoxManagerCreateConfig = Pick<
41
40
  TeleBoxConfig,
42
- TeleBoxManagerBoxConfigBaseProps | "content" | "footer" | "id"
41
+ TeleBoxManagerBoxConfigBaseProps | "content" | "footer" | "id" | "focus"
43
42
  >;
44
43
 
45
44
  export type TeleBoxManagerQueryConfig = Pick<
46
45
  TeleBoxConfig,
47
- TeleBoxManagerBoxConfigBaseProps | "id"
46
+ TeleBoxManagerBoxConfigBaseProps | "id" | "focus"
48
47
  >;
49
48
 
50
49
  export type TeleBoxManagerUpdateConfig = Pick<
@@ -57,8 +56,8 @@ type CheckTeleBoxManagerConfig<
57
56
  > = T;
58
57
 
59
58
  export type TeleBoxManagerEventConfig = CheckTeleBoxManagerConfig<{
60
- /** current focused box and last focused box */
61
- focused: [ReadonlyTeleBox | undefined, ReadonlyTeleBox | undefined];
59
+ focused: [ReadonlyTeleBox | undefined];
60
+ blurred: [ReadonlyTeleBox | undefined];
62
61
  created: [ReadonlyTeleBox];
63
62
  removed: [ReadonlyTeleBox[]];
64
63
  state: [TeleBoxState];
@@ -69,6 +68,7 @@ export type TeleBoxManagerEventConfig = CheckTeleBoxManagerConfig<{
69
68
  intrinsic_move: [ReadonlyTeleBox];
70
69
  intrinsic_resize: [ReadonlyTeleBox];
71
70
  visual_resize: [ReadonlyTeleBox];
71
+ z_index: [ReadonlyTeleBox];
72
72
  prefers_color_scheme: [TeleBoxColorScheme];
73
73
  dark_mode: [boolean];
74
74
  }>;