@netless/telebox-insider 1.0.0-alpha.2 → 1.0.0-alpha.20

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.
@@ -9,8 +9,13 @@ import type {
9
9
  ReadonlyValEnhancedResult,
10
10
  ValEnhancedResult,
11
11
  } from "value-enhancer";
12
- import { withValueEnhancer } from "value-enhancer";
13
- import { combine, Val, withReadonlyValueEnhancer } from "value-enhancer";
12
+ import {
13
+ combine,
14
+ Val,
15
+ withReadonlyValueEnhancer,
16
+ withValueEnhancer,
17
+ ValManager,
18
+ } from "value-enhancer";
14
19
  import type { TeleTitleBar } from "../TeleTitleBar";
15
20
  import { DefaultTitleBar } from "../TeleTitleBar";
16
21
  import { ResizeObserver as ResizeObserverPolyfill } from "@juggle/resize-observer";
@@ -38,7 +43,7 @@ import type {
38
43
  TeleBoxDelegateEventConfig,
39
44
  TeleBoxRect,
40
45
  } from "./typings";
41
- import { TeleStage } from "../TeleStage";
46
+ import { calcStageRect } from "./utils";
42
47
 
43
48
  export * from "./constants";
44
49
  export * from "./typings";
@@ -52,10 +57,13 @@ type ValConfig = {
52
57
  visible: Val<RequiredTeleBoxConfig["visible"], boolean>;
53
58
  resizable: Val<RequiredTeleBoxConfig["resizable"], boolean>;
54
59
  draggable: Val<RequiredTeleBoxConfig["draggable"], boolean>;
55
- ratio: Val<RequiredTeleBoxConfig["ratio"], boolean>;
60
+ boxRatio: Val<RequiredTeleBoxConfig["boxRatio"], boolean>;
61
+ stageRatio: Val<RequiredTeleBoxConfig["stageRatio"], boolean>;
62
+ stageStyle: Val<RequiredTeleBoxConfig["stageStyle"], boolean>;
63
+ bodyStyle: Val<RequiredTeleBoxConfig["bodyStyle"], boolean>;
56
64
  };
57
65
 
58
- type ReadonlyValConfig = {
66
+ type PropsValConfig = {
59
67
  darkMode: RequiredTeleBoxConfig["darkMode$"];
60
68
  fence: RequiredTeleBoxConfig["fence$"];
61
69
  minimized: RequiredTeleBoxConfig["minimized$"];
@@ -63,15 +71,15 @@ type ReadonlyValConfig = {
63
71
  readonly: RequiredTeleBoxConfig["readonly$"];
64
72
  rootRect: RequiredTeleBoxConfig["rootRect$"];
65
73
  managerStageRect: RequiredTeleBoxConfig["managerStageRect$"];
74
+ defaultBoxStageStyle: RequiredTeleBoxConfig["defaultBoxStageStyle$"];
75
+ defaultBoxBodyStyle: RequiredTeleBoxConfig["defaultBoxBodyStyle$"];
66
76
  collectorRect: RequiredTeleBoxConfig["collectorRect$"];
77
+ };
67
78
 
79
+ type MyReadonlyValConfig = {
68
80
  zIndex: Val<RequiredTeleBoxConfig["zIndex"], boolean>;
69
81
  focus: Val<RequiredTeleBoxConfig["focus"], boolean>;
70
82
 
71
- $userContent: Val<TeleBoxConfig["content"], boolean>;
72
- $userFooter: Val<TeleBoxConfig["footer"], boolean>;
73
- $userStyles: Val<TeleBoxConfig["styles"], boolean>;
74
-
75
83
  minSize: Val<TeleBoxSize, boolean>;
76
84
  intrinsicSize: Val<TeleBoxSize, boolean>;
77
85
  intrinsicCoord: Val<TeleBoxCoord, boolean>;
@@ -79,13 +87,13 @@ type ReadonlyValConfig = {
79
87
  pxIntrinsicSize: ReadonlyVal<TeleBoxSize, boolean>;
80
88
  pxIntrinsicCoord: ReadonlyVal<TeleBoxCoord, boolean>;
81
89
  state: ReadonlyVal<TeleBoxState, boolean>;
82
- highlightStage: ReadonlyVal<boolean, boolean>;
83
- boxHighlightStage: Val<boolean | null, boolean>;
84
- contentRect: Val<TeleBoxRect>;
85
- contentStageRect: ReadonlyVal<TeleBoxRect | null>;
90
+ bodyRect: Val<TeleBoxRect>;
91
+ stageRect: ReadonlyVal<TeleBoxRect>;
86
92
  };
87
93
 
88
- type CombinedValEnhancedResult = ReadonlyValEnhancedResult<ReadonlyValConfig> &
94
+ type CombinedValEnhancedResult = ReadonlyValEnhancedResult<
95
+ PropsValConfig & MyReadonlyValConfig
96
+ > &
89
97
  ValEnhancedResult<ValConfig>;
90
98
 
91
99
  export interface TeleBox extends CombinedValEnhancedResult {}
@@ -104,41 +112,46 @@ export class TeleBox {
104
112
  y = 0.1,
105
113
  resizable = true,
106
114
  draggable = true,
107
- ratio = -1,
115
+ boxRatio = -1,
108
116
  focus = false,
109
117
  zIndex = 100,
118
+ stageRatio = null,
110
119
  titleBar,
111
120
  content,
121
+ stage,
112
122
  footer,
113
123
  styles,
114
- highlightStage = null,
124
+ userStyles,
125
+ bodyStyle = null,
126
+ stageStyle = null,
115
127
  darkMode$,
116
128
  fence$,
117
129
  minimized$,
118
130
  maximized$,
119
131
  readonly$,
120
- root$,
132
+ root,
121
133
  rootRect$,
122
134
  managerStageRect$,
123
- stageRatio$,
135
+ managerStageRatio$,
136
+ defaultBoxBodyStyle$,
137
+ defaultBoxStageStyle$,
124
138
  collectorRect$,
125
- managerHighlightStage$,
126
139
  }: TeleBoxConfig) {
127
140
  this._sideEffect = new SideEffectManager();
128
141
 
129
142
  this.id = id;
130
143
  this.namespace = namespace;
131
144
 
145
+ const valManager = new ValManager();
146
+ this._sideEffect.addDisposer(() => valManager.destroy());
147
+
132
148
  const title$ = new Val(title);
133
149
  const visible$ = new Val(visible);
134
150
  const resizable$ = new Val(resizable);
135
151
  const draggable$ = new Val(draggable);
136
- const ratio$ = new Val(ratio);
152
+ const boxRatio$ = new Val(boxRatio);
137
153
  const zIndex$ = new Val(zIndex);
138
154
  const focus$ = new Val(focus);
139
- const $userContent$ = new Val(content);
140
- const $userFooter$ = new Val(footer);
141
- const $userStyles$ = new Val(styles);
142
155
 
143
156
  const state$ = combine(
144
157
  [minimized$, maximized$],
@@ -199,44 +212,31 @@ export class TeleBox {
199
212
  const pxIntrinsicCoord$ = combine(
200
213
  [intrinsicCoord$, managerStageRect$],
201
214
  ([intrinsicCoord, managerStageRect]) => ({
202
- x:
203
- intrinsicCoord.x * managerStageRect.width +
204
- managerStageRect.x,
205
- y:
206
- intrinsicCoord.y * managerStageRect.height +
207
- managerStageRect.y,
215
+ x: intrinsicCoord.x * managerStageRect.width,
216
+ y: intrinsicCoord.y * managerStageRect.height,
208
217
  }),
209
218
  { compare: shallowequal }
210
219
  );
211
220
 
212
- const boxHighlightStage$ = new Val<boolean | null, boolean>(
213
- highlightStage
214
- );
215
-
216
- const highlightStage$ = combine(
217
- [maximized$, boxHighlightStage$, managerHighlightStage$],
218
- ([maximized, boxHighlightStage, managerHighlightStage]) =>
219
- boxHighlightStage === null
220
- ? managerHighlightStage && maximized
221
- : boxHighlightStage
222
- );
221
+ const bodyStyle$ = new Val<string | null>(bodyStyle);
222
+ const stageStyle$ = new Val<string | null>(stageStyle);
223
223
 
224
224
  const contentRoot$ = new Val<HTMLElement | null>(null);
225
-
226
- const contentRect$ = new Val<TeleBoxRect>(rootRect$.value, {
225
+ const bodyRect$ = new Val<TeleBoxRect>(managerStageRect$.value, {
227
226
  compare: shallowequal,
228
227
  });
228
+ const stageRatio$ = new Val(stageRatio);
229
+ const finalStageRatio$ = combine(
230
+ [stageRatio$, managerStageRatio$],
231
+ ([stageRatio, managerStageRatio]) => stageRatio ?? managerStageRatio
232
+ );
233
+ const stageRect$ = combine(
234
+ [bodyRect$, finalStageRatio$],
235
+ calcStageRect,
236
+ { compare: shallowequal }
237
+ );
229
238
 
230
- const teleStage = new TeleStage({
231
- namespace,
232
- root$: contentRoot$,
233
- rootRect$: contentRect$,
234
- ratio$: stageRatio$,
235
- highlightStage$,
236
- });
237
- this._sideEffect.addDisposer(() => teleStage.destroy());
238
-
239
- const readonlyValConfig: ReadonlyValConfig = {
239
+ const propsValConfig: PropsValConfig = {
240
240
  darkMode: darkMode$,
241
241
  fence: fence$,
242
242
  minimized: minimized$,
@@ -244,15 +244,17 @@ export class TeleBox {
244
244
  readonly: readonly$,
245
245
  rootRect: rootRect$,
246
246
  managerStageRect: managerStageRect$,
247
+ defaultBoxBodyStyle: defaultBoxBodyStyle$,
248
+ defaultBoxStageStyle: defaultBoxStageStyle$,
247
249
  collectorRect: collectorRect$,
250
+ };
248
251
 
252
+ withReadonlyValueEnhancer(this, propsValConfig);
253
+
254
+ const myReadonlyValConfig: MyReadonlyValConfig = {
249
255
  zIndex: zIndex$,
250
256
  focus: focus$,
251
257
 
252
- $userContent: $userContent$,
253
- $userFooter: $userFooter$,
254
- $userStyles: $userStyles$,
255
-
256
258
  state: state$,
257
259
  minSize: minSize$,
258
260
  pxMinSize: pxMinSize$,
@@ -260,44 +262,44 @@ export class TeleBox {
260
262
  intrinsicCoord: intrinsicCoord$,
261
263
  pxIntrinsicSize: pxIntrinsicSize$,
262
264
  pxIntrinsicCoord: pxIntrinsicCoord$,
263
- highlightStage: highlightStage$,
264
- boxHighlightStage: boxHighlightStage$,
265
- contentRect: contentRect$,
266
- contentStageRect: teleStage.stageRect$,
265
+ bodyRect: bodyRect$,
266
+ stageRect: stageRect$,
267
267
  };
268
268
 
269
- withReadonlyValueEnhancer(this, readonlyValConfig);
269
+ withReadonlyValueEnhancer(this, myReadonlyValConfig, valManager);
270
270
 
271
271
  const valConfig: ValConfig = {
272
272
  title: title$,
273
273
  visible: visible$,
274
274
  resizable: resizable$,
275
275
  draggable: draggable$,
276
- ratio: ratio$,
276
+ boxRatio: boxRatio$,
277
+ stageRatio: stageRatio$,
278
+ bodyStyle: bodyStyle$,
279
+ stageStyle: stageStyle$,
277
280
  };
278
281
 
279
- withValueEnhancer(this, valConfig);
282
+ withValueEnhancer(this, valConfig, valManager);
280
283
 
281
284
  this.titleBar =
282
285
  titleBar ||
283
286
  new DefaultTitleBar({
284
287
  readonly$: readonly$,
285
288
  state$: state$,
286
- title: title$.value,
289
+ title$: title$,
287
290
  namespace: this.namespace,
288
291
  onDragStart: (event) => this._handleTrackStart?.(event),
289
292
  onEvent: (event) => this._delegateEvents.emit(event.type),
290
293
  });
291
294
 
292
295
  this._sideEffect.addDisposer(
293
- ratio$.subscribe((ratio) => {
294
- if (ratio > 0) {
296
+ boxRatio$.subscribe((boxRatio) => {
297
+ if (boxRatio > 0) {
295
298
  this.transform(
296
299
  pxIntrinsicCoord$.value.x,
297
300
  pxIntrinsicCoord$.value.y,
298
301
  pxIntrinsicSize$.value.width,
299
- pxIntrinsicSize$.value.height,
300
- true
302
+ pxIntrinsicSize$.value.height
301
303
  );
302
304
  }
303
305
  })
@@ -308,15 +310,20 @@ export class TeleBox {
308
310
  if (fence) {
309
311
  this.move(
310
312
  pxIntrinsicCoord$.value.x,
311
- pxIntrinsicCoord$.value.y,
312
- true
313
+ pxIntrinsicCoord$.value.y
313
314
  );
314
315
  }
315
316
  })
316
317
  );
317
318
 
318
- this.$box = this.render();
319
+ this.$box = this._render();
319
320
  contentRoot$.setValue(this.$content.parentElement);
321
+ content && this.mountContent(content);
322
+ stage && this.mountStage(stage);
323
+ footer && this.mountFooter(footer);
324
+ styles && this.mountStyles(styles);
325
+ userStyles && this.mountUserStyles(userStyles);
326
+ root.appendChild(this.$box);
320
327
 
321
328
  const watchValEvent = <E extends TeleBoxEvent>(
322
329
  val: ReadonlyVal<TeleBoxEventConfig[E], boolean>,
@@ -353,13 +360,6 @@ export class TeleBox {
353
360
  );
354
361
  }
355
362
  }),
356
- root$.subscribe((root) => {
357
- if (root) {
358
- root.appendChild(this.$box);
359
- } else if (this.$box.parentNode) {
360
- this.$box.remove();
361
- }
362
- }),
363
363
  ]);
364
364
  }
365
365
 
@@ -465,34 +465,25 @@ export class TeleBox {
465
465
  const pxIntrinsicSize = this.pxIntrinsicSize;
466
466
 
467
467
  if (this.fence) {
468
- safeX = clamp(
469
- x,
470
- managerStageRect.x,
471
- managerStageRect.x +
472
- managerStageRect.width -
473
- pxIntrinsicSize.width
474
- );
468
+ safeX = clamp(x, 0, managerStageRect.width - pxIntrinsicSize.width);
475
469
  safeY = clamp(
476
470
  y,
477
- managerStageRect.y,
478
- managerStageRect.y +
479
- managerStageRect.height -
480
- pxIntrinsicSize.height
471
+ 0,
472
+ managerStageRect.height - pxIntrinsicSize.height
481
473
  );
482
474
  } else {
483
- const rootRect = this.rootRect;
484
475
  safeX = clamp(
485
476
  x,
486
- rootRect.x - pxIntrinsicSize.width + 20,
487
- rootRect.x + rootRect.width - 20
477
+ -(pxIntrinsicSize.width - 120),
478
+ 0 + managerStageRect.width - 20
488
479
  );
489
- safeY = clamp(y, rootRect.y, rootRect.y + rootRect.height - 20);
480
+ safeY = clamp(y, 0, 0 + managerStageRect.height - 20);
490
481
  }
491
482
 
492
483
  this._intrinsicCoord$.setValue(
493
484
  {
494
- x: (safeX - managerStageRect.x) / managerStageRect.width,
495
- y: (safeY - managerStageRect.y) / managerStageRect.height,
485
+ x: safeX / managerStageRect.width,
486
+ y: safeY / managerStageRect.height,
496
487
  },
497
488
  skipUpdate
498
489
  );
@@ -515,21 +506,20 @@ export class TeleBox {
515
506
  skipUpdate = false
516
507
  ): void {
517
508
  const managerStageRect = this.managerStageRect;
518
- const rootRect = this.rootRect;
519
509
 
520
510
  width = Math.max(width, this.pxMinSize.width);
521
511
  height = Math.max(height, this.pxMinSize.height);
522
512
 
523
- if (this.ratio > 0) {
524
- const newHeight = this.ratio * width;
513
+ if (this.boxRatio > 0) {
514
+ const newHeight = this.boxRatio * width;
525
515
  if (y !== this.pxIntrinsicCoord.y) {
526
516
  y -= newHeight - height;
527
517
  }
528
518
  height = newHeight;
529
519
  }
530
520
 
531
- if (y < rootRect.y) {
532
- y = rootRect.y;
521
+ if (y < 0) {
522
+ y = 0;
533
523
  height = this.pxIntrinsicSize.height;
534
524
  }
535
525
 
@@ -543,71 +533,109 @@ export class TeleBox {
543
533
  );
544
534
  }
545
535
 
546
- /**
547
- * Mount dom to box content.
548
- */
536
+ private $authorContent?: HTMLElement;
537
+
538
+ /** Mount dom to box content. */
549
539
  public mountContent(content: HTMLElement): void {
550
- this._$userContent$.setValue(content);
540
+ this.$authorContent?.remove();
541
+ this.$authorContent = content;
542
+ this.$content.appendChild(content);
551
543
  }
552
544
 
553
- /**
554
- * Unmount content from the box.
555
- */
545
+ /** Unmount content from the box. */
556
546
  public unmountContent(): void {
557
- this._$userContent$.setValue(undefined);
547
+ if (this.$authorContent) {
548
+ this.$authorContent.remove();
549
+ this.$authorContent = undefined;
550
+ }
558
551
  }
559
552
 
560
- /**
561
- * Mount dom to box Footer.
562
- */
563
- public mountFooter(footer: HTMLElement): void {
564
- this._$userFooter$.setValue(footer);
553
+ private $authorStage?: HTMLElement;
554
+
555
+ /** Mount dom to box stage. */
556
+ public mountStage(stage: HTMLElement): void {
557
+ this.$authorStage?.remove();
558
+ this.$authorStage = stage;
559
+ if (!this.$stage) {
560
+ this.$stage = this._renderStage();
561
+ }
562
+ this.$stage.appendChild(stage);
563
+ if (!this.$stage.parentElement) {
564
+ this.$body.appendChild(this.$stage);
565
+ }
565
566
  }
566
567
 
567
- /**
568
- * Unmount Footer from the box.
569
- */
570
- public unmountFooter(): void {
571
- this._$userFooter$.setValue(undefined);
568
+ /** Unmount content from the box. */
569
+ public unmountStage(): void {
570
+ if (this.$authorStage) {
571
+ this.$authorStage.remove();
572
+ this.$authorStage = undefined;
573
+ }
574
+ this.$stage?.remove();
572
575
  }
573
576
 
574
- public getUserStyles(): HTMLStyleElement | undefined {
575
- return this.$userStyles;
577
+ private $authorFooter?: HTMLElement;
578
+
579
+ /** Mount dom to box Footer. */
580
+ public mountFooter(footer: HTMLElement): void {
581
+ this.$authorFooter?.remove();
582
+ this.$authorFooter = footer;
583
+ this.$footer.appendChild(footer);
576
584
  }
577
585
 
578
- public mountStyles(styles: string | HTMLStyleElement): void {
579
- let $styles: HTMLStyleElement;
580
- if (typeof styles === "string") {
581
- $styles = document.createElement("style");
582
- $styles.textContent = styles;
583
- } else {
584
- $styles = styles;
586
+ /** Unmount Footer from the box. */
587
+ public unmountFooter(): void {
588
+ if (this.$authorFooter) {
589
+ this.$authorFooter.remove();
590
+ this.$authorFooter = undefined;
585
591
  }
586
- this._$userStyles$.setValue($styles);
587
592
  }
588
593
 
594
+ /** Mount styles for box content */
595
+ public mountStyles(styles: string): void {
596
+ this.$styles.textContent = styles;
597
+ }
598
+
599
+ /** Umount styles for box content */
589
600
  public unmountStyles(): void {
590
- this._$userStyles$.setValue(undefined);
601
+ this.$styles.textContent = "";
591
602
  }
592
603
 
593
- /** Show stage frame and grey-out the non-stage area. Inherit setting from manager if null. */
594
- setHighlightStage(highlightStage: boolean | null): void {
595
- this._boxHighlightStage$.setValue(highlightStage);
604
+ /** Mount user styles for box content */
605
+ public mountUserStyles(styles: string): void {
606
+ this.$userStyles.textContent = styles;
607
+ }
608
+
609
+ /** Umount user styles for box content */
610
+ public unmountUserStyles(): void {
611
+ this.$userStyles.textContent = "";
596
612
  }
597
613
 
598
614
  /** DOM of the box */
599
615
  public $box: HTMLElement;
600
616
 
601
- /** DOM of the box content */
617
+ /** DOM of the box body */
618
+ public $body!: HTMLElement;
619
+
620
+ /** DOM of the box content container inside box body */
602
621
  public $content!: HTMLElement;
603
622
 
604
- /** DOM of the box title bar */
623
+ /** DOM of the box stage area inside box body */
624
+ public $stage?: HTMLElement;
625
+
626
+ /** DOM of custom box content styles */
627
+ public $styles!: HTMLStyleElement;
628
+
629
+ /** DOM of end user custom box content styles */
630
+ public $userStyles!: HTMLStyleElement;
631
+
632
+ /** DOM of the box title bar container */
605
633
  public $titleBar!: HTMLElement;
606
634
 
607
- /** DOM of the box footer */
635
+ /** DOM of the box footer container */
608
636
  public $footer!: HTMLElement;
609
637
 
610
- protected render(): HTMLElement {
638
+ private _render(): HTMLElement {
611
639
  if (this.$box) {
612
640
  return this.$box;
613
641
  }
@@ -695,6 +723,8 @@ export class TeleBox {
695
723
  this._pxIntrinsicSize$,
696
724
  this._pxIntrinsicCoord$,
697
725
  this._collectorRect$,
726
+ this._rootRect$,
727
+ this._managerStageRect$,
698
728
  ],
699
729
  ([
700
730
  maximized,
@@ -702,42 +732,58 @@ export class TeleBox {
702
732
  pxIntrinsicSize,
703
733
  pxIntrinsicCoord,
704
734
  collectorRect,
735
+ rootRect,
736
+ managerStageRect,
705
737
  ]) => {
738
+ const styles: {
739
+ x: number;
740
+ y: number;
741
+ width: number;
742
+ height: number;
743
+ scaleX: number;
744
+ scaleY: number;
745
+ } = maximized
746
+ ? {
747
+ x: -managerStageRect.x,
748
+ y: -managerStageRect.y,
749
+ width: rootRect.width,
750
+ height: rootRect.height,
751
+ scaleX: 1,
752
+ scaleY: 1,
753
+ }
754
+ : {
755
+ x: pxIntrinsicCoord.x,
756
+ y: pxIntrinsicCoord.y,
757
+ width: pxIntrinsicSize.width,
758
+ height: pxIntrinsicSize.height,
759
+ scaleX: 1,
760
+ scaleY: 1,
761
+ };
706
762
  if (minimized && collectorRect) {
707
- return {
708
- x: collectorRect.x + collectorRect.width / 2,
709
- y: collectorRect.y + collectorRect.height / 2,
710
- width: pxIntrinsicSize.width + "px",
711
- height: pxIntrinsicSize.height + "px",
712
- scaleX: collectorRect.width / pxIntrinsicSize.width,
713
- scaleY: collectorRect.height / pxIntrinsicSize.height,
714
- };
763
+ const { width: boxWidth, height: boxHeight } = maximized
764
+ ? this.rootRect
765
+ : pxIntrinsicSize;
766
+ styles.x =
767
+ collectorRect.x -
768
+ boxWidth / 2 +
769
+ collectorRect.width / 2 -
770
+ managerStageRect.x;
771
+ styles.y =
772
+ collectorRect.y -
773
+ boxHeight / 2 +
774
+ collectorRect.height / 2 -
775
+ managerStageRect.y;
776
+ styles.scaleX = collectorRect.width / boxWidth;
777
+ styles.scaleY = collectorRect.height / boxHeight;
715
778
  }
716
- if (maximized) {
717
- return {
718
- x: 0,
719
- y: 0,
720
- width: "100%",
721
- height: "100%",
722
- scaleX: 1,
723
- scaleY: 1,
724
- };
725
- }
726
- return {
727
- x: pxIntrinsicCoord.x,
728
- y: pxIntrinsicCoord.y,
729
- width: pxIntrinsicSize.width + "px",
730
- height: pxIntrinsicSize.height + "px",
731
- scaleX: 1,
732
- scaleY: 1,
733
- };
779
+ return styles;
734
780
  },
735
781
  { compare: shallowequal }
736
782
  );
737
783
 
738
784
  const boxStyles = boxStyles$.value;
739
- this.$box.style.width = boxStyles.width;
740
- this.$box.style.height = boxStyles.height;
785
+ this.$box.style.width = boxStyles.width + "px";
786
+ this.$box.style.height = boxStyles.height + "px";
741
787
  // Add 10px offset on first frame
742
788
  // which creates a subtle moving effect
743
789
  this.$box.style.transform = `translate(${boxStyles.x - 10}px,${
@@ -759,91 +805,110 @@ export class TeleBox {
759
805
  $titleBar.appendChild(this.titleBar.render());
760
806
  this.$titleBar = $titleBar;
761
807
 
762
- const $contentWrap = document.createElement("div");
763
- $contentWrap.className = this.wrapClassName("content-wrap");
808
+ const $body = document.createElement("div");
809
+ $body.className = this.wrapClassName("content-wrap");
810
+ this.$body = $body;
811
+
812
+ const $styles = document.createElement("style");
813
+ this.$styles = $styles;
814
+ $body.appendChild($styles);
815
+
816
+ const $userStyles = document.createElement("style");
817
+ this.$userStyles = $userStyles;
818
+ $body.appendChild($userStyles);
764
819
 
765
820
  const $content = document.createElement("div");
766
821
  $content.className =
767
822
  this.wrapClassName("content") + " tele-fancy-scrollbar";
768
823
  this.$content = $content;
824
+ this._sideEffect.addDisposer(
825
+ combine(
826
+ [this._bodyStyle$, this._defaultBoxBodyStyle$],
827
+ ([bodyStyle, defaultBoxBodyStyle]) =>
828
+ bodyStyle ?? defaultBoxBodyStyle
829
+ ).subscribe((style) => ($content.style.cssText = style || ""))
830
+ );
769
831
 
770
- this._sideEffect.add(() => {
771
- const observer = new ResizeObserver((entries) => {
772
- const rect = entries[0]?.contentRect;
773
- if (rect) {
774
- this._contentRect$.setValue({
775
- x: rect.x,
776
- y: rect.y,
777
- width: rect.width,
778
- height: rect.height,
779
- });
780
- }
781
- });
782
- observer.observe($content);
783
- return () => observer.disconnect();
784
- });
785
-
786
- this._sideEffect.add(() => {
787
- let last$userStyles: HTMLStyleElement | undefined;
788
- return this._$userStyles$.subscribe(($userStyles) => {
789
- if (last$userStyles) {
790
- last$userStyles.remove();
791
- }
792
- last$userStyles = $userStyles;
793
- if ($userStyles) {
794
- $contentWrap.appendChild($userStyles);
795
- }
796
- });
797
- });
798
-
799
- this._sideEffect.add(() => {
800
- let last$userContent: HTMLElement | undefined;
801
- return this._$userContent$.subscribe(($userContent) => {
802
- if (last$userContent) {
803
- last$userContent.remove();
804
- }
805
- last$userContent = $userContent;
806
- if ($userContent) {
807
- $content.appendChild($userContent);
808
- }
809
- });
810
- });
811
-
812
- $contentWrap.appendChild($content);
832
+ $body.appendChild($content);
813
833
 
814
834
  const $footer = document.createElement("div");
815
835
  $footer.className = this.wrapClassName("footer-wrap");
816
836
  this.$footer = $footer;
817
837
 
838
+ $boxMain.appendChild($titleBar);
839
+ $boxMain.appendChild($body);
840
+ $boxMain.appendChild($footer);
841
+
842
+ this._renderResizeHandlers();
843
+
844
+ const updateBodyRect = (): void => {
845
+ const rect = $body.getBoundingClientRect();
846
+ this._bodyRect$.setValue({
847
+ x: 0,
848
+ y: 0,
849
+ width: rect.width,
850
+ height: rect.height,
851
+ });
852
+ };
818
853
  this._sideEffect.add(() => {
819
- let last$userFooter: HTMLElement | undefined;
820
- return this._$userFooter$.subscribe(($userFooter) => {
821
- if (last$userFooter) {
822
- last$userFooter.remove();
823
- }
824
- last$userFooter = $userFooter;
825
- if ($userFooter) {
826
- $footer.appendChild($userFooter);
854
+ const observer = new ResizeObserver(() => {
855
+ if (!this.minimized) {
856
+ updateBodyRect();
827
857
  }
828
858
  });
859
+ observer.observe($body);
860
+ return () => observer.disconnect();
829
861
  });
862
+ this._sideEffect.addDisposer(
863
+ this._minimized$.reaction((minimized) => {
864
+ // correct content size when restoring from minimized
865
+ if (!minimized) {
866
+ this._sideEffect.setTimeout(
867
+ updateBodyRect,
868
+ 400,
869
+ "minimized-content-rect-fix"
870
+ );
871
+ }
872
+ })
873
+ );
830
874
 
831
- $boxMain.appendChild($titleBar);
832
- $boxMain.appendChild($contentWrap);
833
- $boxMain.appendChild($footer);
875
+ return this.$box;
876
+ }
834
877
 
835
- this._renderResizeHandlers();
878
+ private _renderStage(): HTMLDivElement {
879
+ const $stage = document.createElement("div");
836
880
 
837
- return this.$box;
881
+ $stage.className = this.wrapClassName("content-stage");
882
+ const updateStageRect = (stageRect: TeleBoxRect): void => {
883
+ $stage.style.top = stageRect.y + "px";
884
+ $stage.style.left = stageRect.x + "px";
885
+ $stage.style.width = stageRect.width + "px";
886
+ $stage.style.height = stageRect.height + "px";
887
+ };
888
+ this._sideEffect.addDisposer(
889
+ [
890
+ combine(
891
+ [this._stageStyle$, this._defaultBoxStageStyle$],
892
+ ([stageStyle, defaultBoxStageStyle]) =>
893
+ stageStyle ?? defaultBoxStageStyle
894
+ ).subscribe((styles) => {
895
+ $stage.style.cssText = styles || "";
896
+ updateStageRect(this._stageRect$.value);
897
+ }),
898
+ this._stageRect$.subscribe(updateStageRect),
899
+ ],
900
+ "content-stage-styles"
901
+ );
902
+ return $stage;
838
903
  }
839
904
 
840
- protected _handleTrackStart?: (ev: MouseEvent | TouchEvent) => void;
905
+ private _handleTrackStart?: (ev: MouseEvent | TouchEvent) => void;
841
906
 
842
907
  public handleTrackStart: (ev: MouseEvent | TouchEvent) => void = (ev) => {
843
908
  return this._handleTrackStart?.(ev);
844
909
  };
845
910
 
846
- protected _renderResizeHandlers(): void {
911
+ private _renderResizeHandlers(): void {
847
912
  const $resizeHandles = document.createElement("div");
848
913
  $resizeHandles.className = this.wrapClassName("resize-handles");
849
914
 
@@ -884,8 +949,8 @@ export class TeleBox {
884
949
  preventEvent(ev);
885
950
 
886
951
  let { pageX, pageY } = flattenEvent(ev);
887
- if (pageY < this.rootRect.y) {
888
- pageY = this.rootRect.y;
952
+ if (pageY < 0) {
953
+ pageY = 0;
889
954
  }
890
955
 
891
956
  const offsetX = pageX - trackStartPageX;
@@ -1090,7 +1155,21 @@ export type ReadonlyTeleBox = Pick<
1090
1155
  | PropKeys
1091
1156
  | "wrapClassName"
1092
1157
  | "mountContent"
1158
+ | "unmountContent"
1093
1159
  | "mountFooter"
1160
+ | "unmountFooter"
1161
+ | "mountStage"
1162
+ | "unmountStage"
1094
1163
  | "mountStyles"
1164
+ | "unmountStyles"
1165
+ | "setTitle"
1166
+ | "setDraggable"
1167
+ | "setResizable"
1168
+ | "setVisible"
1169
+ | "setBoxRatio"
1170
+ | "setStageRatio"
1171
+ | "setStageStyle"
1172
+ | "setBodyStyle"
1095
1173
  | "handleTrackStart"
1174
+ | "onValChanged"
1096
1175
  >;