@netless/telebox-insider 1.0.0-alpha.3 → 1.0.0-alpha.32

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.
Files changed (38) hide show
  1. package/dist/TeleBox/index.d.ts +62 -38
  2. package/dist/TeleBox/typings.d.ts +28 -16
  3. package/dist/TeleBox/utils.d.ts +5 -0
  4. package/dist/TeleBoxCollector/index.d.ts +7 -8
  5. package/dist/TeleBoxManager/MaxTitleBar/index.d.ts +1 -1
  6. package/dist/TeleBoxManager/index.d.ts +15 -5
  7. package/dist/TeleBoxManager/typings.d.ts +50 -6
  8. package/dist/TeleTitleBar/DefaultTitleBar/index.d.ts +4 -12
  9. package/dist/TeleTitleBar/typings.d.ts +2 -2
  10. package/dist/index.d.ts +0 -1
  11. package/dist/style.css +650 -1
  12. package/dist/telebox-insider.cjs.js +1659 -1
  13. package/dist/telebox-insider.cjs.js.map +1 -1
  14. package/dist/telebox-insider.es.js +1641 -1
  15. package/dist/telebox-insider.es.js.map +1 -1
  16. package/dist/utils.d.ts +0 -1
  17. package/package.json +67 -67
  18. package/src/TeleBox/index.ts +443 -300
  19. package/src/TeleBox/style.scss +13 -25
  20. package/src/TeleBox/style.shadow.scss +77 -0
  21. package/src/TeleBox/typings.ts +28 -16
  22. package/src/TeleBox/utils.ts +32 -0
  23. package/src/TeleBoxCollector/index.ts +41 -38
  24. package/src/TeleBoxCollector/style.scss +6 -4
  25. package/src/TeleBoxManager/MaxTitleBar/index.ts +3 -28
  26. package/src/TeleBoxManager/MaxTitleBar/style.scss +18 -16
  27. package/src/TeleBoxManager/index.ts +187 -80
  28. package/src/TeleBoxManager/style.scss +55 -0
  29. package/src/TeleBoxManager/typings.ts +69 -7
  30. package/src/TeleTitleBar/DefaultTitleBar/index.ts +47 -61
  31. package/src/TeleTitleBar/DefaultTitleBar/style.scss +30 -10
  32. package/src/TeleTitleBar/typings.ts +2 -2
  33. package/src/index.ts +0 -2
  34. package/src/scss/variables.scss +72 -0
  35. package/src/utils.ts +0 -6
  36. package/dist/TeleStage/index.d.ts +0 -21
  37. package/src/TeleStage/index.ts +0 -178
  38. package/src/TeleStage/style.scss +0 -49
@@ -1,4 +1,5 @@
1
1
  import "./style.scss";
2
+ import shadowStyles from "./style.shadow.scss?inline";
2
3
 
3
4
  import Emittery from "emittery";
4
5
  import styler from "stylefire";
@@ -9,19 +10,17 @@ import type {
9
10
  ReadonlyValEnhancedResult,
10
11
  ValEnhancedResult,
11
12
  } from "value-enhancer";
12
- import { withValueEnhancer } from "value-enhancer";
13
- import { combine, Val, withReadonlyValueEnhancer } from "value-enhancer";
13
+ import {
14
+ combine,
15
+ Val,
16
+ withReadonlyValueEnhancer,
17
+ withValueEnhancer,
18
+ ValManager,
19
+ } from "value-enhancer";
14
20
  import type { TeleTitleBar } from "../TeleTitleBar";
15
21
  import { DefaultTitleBar } from "../TeleTitleBar";
16
22
  import { ResizeObserver as ResizeObserverPolyfill } from "@juggle/resize-observer";
17
- import {
18
- clamp,
19
- flattenEvent,
20
- getBoxDefaultName,
21
- isFalsy,
22
- isTruthy,
23
- preventEvent,
24
- } from "../utils";
23
+ import { clamp, getBoxDefaultName, preventEvent } from "../utils";
25
24
  import {
26
25
  TELE_BOX_EVENT,
27
26
  TELE_BOX_STATE,
@@ -38,7 +37,7 @@ import type {
38
37
  TeleBoxDelegateEventConfig,
39
38
  TeleBoxRect,
40
39
  } from "./typings";
41
- import { TeleStage } from "../TeleStage";
40
+ import { calcStageRect } from "./utils";
42
41
 
43
42
  export * from "./constants";
44
43
  export * from "./typings";
@@ -52,26 +51,35 @@ type ValConfig = {
52
51
  visible: Val<RequiredTeleBoxConfig["visible"], boolean>;
53
52
  resizable: Val<RequiredTeleBoxConfig["resizable"], boolean>;
54
53
  draggable: Val<RequiredTeleBoxConfig["draggable"], boolean>;
55
- ratio: Val<RequiredTeleBoxConfig["ratio"], boolean>;
54
+ boxRatio: Val<RequiredTeleBoxConfig["boxRatio"], boolean>;
55
+ boxMinimized: Val<boolean | null, boolean>;
56
+ boxMaximized: Val<boolean | null, boolean>;
57
+ boxReadonly: Val<boolean | null, boolean>;
58
+ stageRatio: Val<RequiredTeleBoxConfig["stageRatio"], boolean>;
59
+ stageStyle: Val<RequiredTeleBoxConfig["stageStyle"], boolean>;
60
+ bodyStyle: Val<RequiredTeleBoxConfig["bodyStyle"], boolean>;
56
61
  };
57
62
 
58
- type ReadonlyValConfig = {
63
+ type PropsValConfig = {
59
64
  darkMode: RequiredTeleBoxConfig["darkMode$"];
60
65
  fence: RequiredTeleBoxConfig["fence$"];
61
- minimized: RequiredTeleBoxConfig["minimized$"];
62
- maximized: RequiredTeleBoxConfig["maximized$"];
63
- readonly: RequiredTeleBoxConfig["readonly$"];
64
66
  rootRect: RequiredTeleBoxConfig["rootRect$"];
67
+ managerMinimized: RequiredTeleBoxConfig["managerMinimized$"];
68
+ managerMaximized: RequiredTeleBoxConfig["managerMaximized$"];
69
+ managerReadonly: RequiredTeleBoxConfig["managerReadonly$"];
65
70
  managerStageRect: RequiredTeleBoxConfig["managerStageRect$"];
71
+ managerStageRatio: RequiredTeleBoxConfig["managerStageRatio$"];
72
+ defaultBoxStageStyle: RequiredTeleBoxConfig["defaultBoxStageStyle$"];
73
+ defaultBoxBodyStyle: RequiredTeleBoxConfig["defaultBoxBodyStyle$"];
66
74
  collectorRect: RequiredTeleBoxConfig["collectorRect$"];
75
+ };
67
76
 
77
+ type MyReadonlyValConfig = {
68
78
  zIndex: Val<RequiredTeleBoxConfig["zIndex"], boolean>;
69
79
  focus: Val<RequiredTeleBoxConfig["focus"], boolean>;
70
-
71
- $userContent: Val<TeleBoxConfig["content"], boolean>;
72
- $userFooter: Val<TeleBoxConfig["footer"], boolean>;
73
- $userStyles: Val<TeleBoxConfig["styles"], boolean>;
74
-
80
+ minimized: ReadonlyVal<boolean, boolean>;
81
+ maximized: ReadonlyVal<boolean, boolean>;
82
+ readonly: ReadonlyVal<boolean, boolean>;
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,67 @@ 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,
119
+ enableShadowDOM = true,
110
120
  titleBar,
111
121
  content,
122
+ stage,
112
123
  footer,
113
124
  styles,
114
- highlightStage = null,
125
+ userStyles,
126
+ bodyStyle = null,
127
+ stageStyle = null,
115
128
  darkMode$,
116
129
  fence$,
117
- minimized$,
118
- maximized$,
119
- readonly$,
120
- root$,
130
+ root,
121
131
  rootRect$,
132
+ managerMinimized$,
133
+ managerMaximized$,
134
+ managerReadonly$,
122
135
  managerStageRect$,
123
- stageRatio$,
136
+ managerStageRatio$,
137
+ defaultBoxBodyStyle$,
138
+ defaultBoxStageStyle$,
124
139
  collectorRect$,
125
- managerHighlightStage$,
126
140
  }: TeleBoxConfig) {
127
141
  this._sideEffect = new SideEffectManager();
128
142
 
129
143
  this.id = id;
130
144
  this.namespace = namespace;
145
+ this.enableShadowDOM = enableShadowDOM;
146
+
147
+ const valManager = new ValManager();
148
+ this._sideEffect.addDisposer(() => valManager.destroy());
131
149
 
132
150
  const title$ = new Val(title);
133
151
  const visible$ = new Val(visible);
134
152
  const resizable$ = new Val(resizable);
135
153
  const draggable$ = new Val(draggable);
136
- const ratio$ = new Val(ratio);
154
+ const boxRatio$ = new Val(boxRatio);
137
155
  const zIndex$ = new Val(zIndex);
138
156
  const focus$ = new Val(focus);
139
- const $userContent$ = new Val(content);
140
- const $userFooter$ = new Val(footer);
141
- const $userStyles$ = new Val(styles);
157
+
158
+ const boxMaximized$ = new Val<boolean | null>(null);
159
+ const boxMinimized$ = new Val<boolean | null>(null);
160
+ const boxReadonly$ = new Val<boolean | null>(null);
161
+
162
+ const maximized$ = combine(
163
+ [boxMaximized$, managerMaximized$],
164
+ ([boxMaximized, managerMaximized]) =>
165
+ boxMaximized ?? managerMaximized
166
+ );
167
+ const minimized$ = combine(
168
+ [boxMinimized$, managerMinimized$],
169
+ ([boxMinimized, managerMinimized]) =>
170
+ boxMinimized ?? managerMinimized
171
+ );
172
+ const readonly$ = combine(
173
+ [boxReadonly$, managerReadonly$],
174
+ ([boxReadonly, managerReadonly]) => boxReadonly ?? managerReadonly
175
+ );
142
176
 
143
177
  const state$ = combine(
144
178
  [minimized$, maximized$],
@@ -199,60 +233,50 @@ export class TeleBox {
199
233
  const pxIntrinsicCoord$ = combine(
200
234
  [intrinsicCoord$, managerStageRect$],
201
235
  ([intrinsicCoord, managerStageRect]) => ({
202
- x:
203
- intrinsicCoord.x * managerStageRect.width +
204
- managerStageRect.x,
205
- y:
206
- intrinsicCoord.y * managerStageRect.height +
207
- managerStageRect.y,
236
+ x: intrinsicCoord.x * managerStageRect.width,
237
+ y: intrinsicCoord.y * managerStageRect.height,
208
238
  }),
209
239
  { compare: shallowequal }
210
240
  );
211
241
 
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
- );
242
+ const bodyStyle$ = new Val<string | null>(bodyStyle);
243
+ const stageStyle$ = new Val<string | null>(stageStyle);
223
244
 
224
245
  const contentRoot$ = new Val<HTMLElement | null>(null);
225
-
226
- const contentRect$ = new Val<TeleBoxRect>(rootRect$.value, {
246
+ const bodyRect$ = new Val<TeleBoxRect>(managerStageRect$.value, {
227
247
  compare: shallowequal,
228
248
  });
249
+ const stageRatio$ = new Val(stageRatio);
250
+ const finalStageRatio$ = combine(
251
+ [stageRatio$, managerStageRatio$],
252
+ ([stageRatio, managerStageRatio]) => stageRatio ?? managerStageRatio
253
+ );
254
+ const stageRect$ = combine(
255
+ [bodyRect$, finalStageRatio$],
256
+ calcStageRect,
257
+ { compare: shallowequal }
258
+ );
229
259
 
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 = {
260
+ const propsValConfig: PropsValConfig = {
240
261
  darkMode: darkMode$,
241
262
  fence: fence$,
242
- minimized: minimized$,
243
- maximized: maximized$,
244
- readonly: readonly$,
245
263
  rootRect: rootRect$,
264
+ managerMinimized: managerMinimized$,
265
+ managerMaximized: managerMaximized$,
266
+ managerReadonly: managerReadonly$,
246
267
  managerStageRect: managerStageRect$,
268
+ managerStageRatio: managerStageRatio$,
269
+ defaultBoxBodyStyle: defaultBoxBodyStyle$,
270
+ defaultBoxStageStyle: defaultBoxStageStyle$,
247
271
  collectorRect: collectorRect$,
272
+ };
248
273
 
274
+ withReadonlyValueEnhancer(this, propsValConfig);
275
+
276
+ const myReadonlyValConfig: MyReadonlyValConfig = {
249
277
  zIndex: zIndex$,
250
278
  focus: focus$,
251
279
 
252
- $userContent: $userContent$,
253
- $userFooter: $userFooter$,
254
- $userStyles: $userStyles$,
255
-
256
280
  state: state$,
257
281
  minSize: minSize$,
258
282
  pxMinSize: pxMinSize$,
@@ -260,44 +284,50 @@ export class TeleBox {
260
284
  intrinsicCoord: intrinsicCoord$,
261
285
  pxIntrinsicSize: pxIntrinsicSize$,
262
286
  pxIntrinsicCoord: pxIntrinsicCoord$,
263
- highlightStage: highlightStage$,
264
- boxHighlightStage: boxHighlightStage$,
265
- contentRect: contentRect$,
266
- contentStageRect: teleStage.stageRect$,
287
+ bodyRect: bodyRect$,
288
+ stageRect: stageRect$,
289
+ minimized: minimized$,
290
+ maximized: maximized$,
291
+ readonly: readonly$,
267
292
  };
268
293
 
269
- withReadonlyValueEnhancer(this, readonlyValConfig);
294
+ withReadonlyValueEnhancer(this, myReadonlyValConfig, valManager);
270
295
 
271
296
  const valConfig: ValConfig = {
272
297
  title: title$,
273
298
  visible: visible$,
274
299
  resizable: resizable$,
275
300
  draggable: draggable$,
276
- ratio: ratio$,
301
+ boxRatio: boxRatio$,
302
+ boxMinimized: boxMinimized$,
303
+ boxMaximized: boxMaximized$,
304
+ boxReadonly: boxReadonly$,
305
+ stageRatio: stageRatio$,
306
+ bodyStyle: bodyStyle$,
307
+ stageStyle: stageStyle$,
277
308
  };
278
309
 
279
- withValueEnhancer(this, valConfig);
310
+ withValueEnhancer(this, valConfig, valManager);
280
311
 
281
312
  this.titleBar =
282
313
  titleBar ||
283
314
  new DefaultTitleBar({
284
315
  readonly$: readonly$,
285
316
  state$: state$,
286
- title: title$.value,
317
+ title$: title$,
287
318
  namespace: this.namespace,
288
319
  onDragStart: (event) => this._handleTrackStart?.(event),
289
320
  onEvent: (event) => this._delegateEvents.emit(event.type),
290
321
  });
291
322
 
292
323
  this._sideEffect.addDisposer(
293
- ratio$.subscribe((ratio) => {
294
- if (ratio > 0) {
324
+ boxRatio$.subscribe((boxRatio) => {
325
+ if (boxRatio > 0) {
295
326
  this.transform(
296
327
  pxIntrinsicCoord$.value.x,
297
328
  pxIntrinsicCoord$.value.y,
298
329
  pxIntrinsicSize$.value.width,
299
- pxIntrinsicSize$.value.height,
300
- true
330
+ pxIntrinsicSize$.value.height
301
331
  );
302
332
  }
303
333
  })
@@ -308,15 +338,20 @@ export class TeleBox {
308
338
  if (fence) {
309
339
  this.move(
310
340
  pxIntrinsicCoord$.value.x,
311
- pxIntrinsicCoord$.value.y,
312
- true
341
+ pxIntrinsicCoord$.value.y
313
342
  );
314
343
  }
315
344
  })
316
345
  );
317
346
 
318
- this.$box = this.render();
347
+ this.$box = this._render();
319
348
  contentRoot$.setValue(this.$content.parentElement);
349
+ content && this.mountContent(content);
350
+ stage && this.mountStage(stage);
351
+ footer && this.mountFooter(footer);
352
+ styles && this.mountStyles(styles);
353
+ userStyles && this.mountUserStyles(userStyles);
354
+ root.appendChild(this.$box);
320
355
 
321
356
  const watchValEvent = <E extends TeleBoxEvent>(
322
357
  val: ReadonlyVal<TeleBoxEventConfig[E], boolean>,
@@ -353,13 +388,6 @@ export class TeleBox {
353
388
  );
354
389
  }
355
390
  }),
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
391
  ]);
364
392
  }
365
393
 
@@ -368,6 +396,9 @@ export class TeleBox {
368
396
  /** ClassName Prefix. For CSS styling. Default "telebox" */
369
397
  public readonly namespace: string;
370
398
 
399
+ /** Enable shadow DOM for box content. Default true. */
400
+ public readonly enableShadowDOM: boolean;
401
+
371
402
  public readonly events = new Emittery<
372
403
  TeleBoxEventConfig,
373
404
  TeleBoxEventConfig
@@ -465,34 +496,25 @@ export class TeleBox {
465
496
  const pxIntrinsicSize = this.pxIntrinsicSize;
466
497
 
467
498
  if (this.fence) {
468
- safeX = clamp(
469
- x,
470
- managerStageRect.x,
471
- managerStageRect.x +
472
- managerStageRect.width -
473
- pxIntrinsicSize.width
474
- );
499
+ safeX = clamp(x, 0, managerStageRect.width - pxIntrinsicSize.width);
475
500
  safeY = clamp(
476
501
  y,
477
- managerStageRect.y,
478
- managerStageRect.y +
479
- managerStageRect.height -
480
- pxIntrinsicSize.height
502
+ 0,
503
+ managerStageRect.height - pxIntrinsicSize.height
481
504
  );
482
505
  } else {
483
- const rootRect = this.rootRect;
484
506
  safeX = clamp(
485
507
  x,
486
- rootRect.x - pxIntrinsicSize.width + 20,
487
- rootRect.x + rootRect.width - 20
508
+ -(pxIntrinsicSize.width - 120),
509
+ 0 + managerStageRect.width - 20
488
510
  );
489
- safeY = clamp(y, rootRect.y, rootRect.y + rootRect.height - 20);
511
+ safeY = clamp(y, 0, 0 + managerStageRect.height - 20);
490
512
  }
491
513
 
492
514
  this._intrinsicCoord$.setValue(
493
515
  {
494
- x: (safeX - managerStageRect.x) / managerStageRect.width,
495
- y: (safeY - managerStageRect.y) / managerStageRect.height,
516
+ x: safeX / managerStageRect.width,
517
+ y: safeY / managerStageRect.height,
496
518
  },
497
519
  skipUpdate
498
520
  );
@@ -515,21 +537,20 @@ export class TeleBox {
515
537
  skipUpdate = false
516
538
  ): void {
517
539
  const managerStageRect = this.managerStageRect;
518
- const rootRect = this.rootRect;
519
540
 
520
541
  width = Math.max(width, this.pxMinSize.width);
521
542
  height = Math.max(height, this.pxMinSize.height);
522
543
 
523
- if (this.ratio > 0) {
524
- const newHeight = this.ratio * width;
544
+ if (this.boxRatio > 0) {
545
+ const newHeight = this.boxRatio * width;
525
546
  if (y !== this.pxIntrinsicCoord.y) {
526
547
  y -= newHeight - height;
527
548
  }
528
549
  height = newHeight;
529
550
  }
530
551
 
531
- if (y < rootRect.y) {
532
- y = rootRect.y;
552
+ if (y < 0) {
553
+ y = 0;
533
554
  height = this.pxIntrinsicSize.height;
534
555
  }
535
556
 
@@ -543,104 +564,158 @@ export class TeleBox {
543
564
  );
544
565
  }
545
566
 
546
- /**
547
- * Mount dom to box content.
548
- */
567
+ private $authorContent?: HTMLElement;
568
+
569
+ /** Mount dom to box content. */
549
570
  public mountContent(content: HTMLElement): void {
550
- this._$userContent$.setValue(content);
571
+ this.$authorContent?.remove();
572
+ this.$authorContent = content;
573
+ this.$content.appendChild(content);
551
574
  }
552
575
 
553
- /**
554
- * Unmount content from the box.
555
- */
576
+ /** Unmount content from the box. */
556
577
  public unmountContent(): void {
557
- this._$userContent$.setValue(undefined);
578
+ if (this.$authorContent) {
579
+ this.$authorContent.remove();
580
+ this.$authorContent = undefined;
581
+ }
558
582
  }
559
583
 
560
- /**
561
- * Mount dom to box Footer.
562
- */
563
- public mountFooter(footer: HTMLElement): void {
564
- this._$userFooter$.setValue(footer);
584
+ private $authorStage?: HTMLElement;
585
+
586
+ /** Mount dom to box stage. */
587
+ public mountStage(stage: HTMLElement): void {
588
+ this.$authorStage?.remove();
589
+ this.$authorStage = stage;
590
+ if (!this.$stage) {
591
+ this.$stage = this._renderStage();
592
+ }
593
+ this.$stage.appendChild(stage);
594
+ if (!this.$stage.parentElement) {
595
+ this.$body.appendChild(this.$stage);
596
+ }
565
597
  }
566
598
 
567
- /**
568
- * Unmount Footer from the box.
569
- */
570
- public unmountFooter(): void {
571
- this._$userFooter$.setValue(undefined);
599
+ /** Unmount content from the box. */
600
+ public unmountStage(): void {
601
+ if (this.$authorStage) {
602
+ this.$authorStage.remove();
603
+ this.$authorStage = undefined;
604
+ }
605
+ this.$stage?.remove();
572
606
  }
573
607
 
574
- public getUserStyles(): HTMLStyleElement | undefined {
575
- return this.$userStyles;
608
+ private $authorFooter?: HTMLElement;
609
+
610
+ /** Mount dom to box Footer. */
611
+ public mountFooter(footer: HTMLElement): void {
612
+ this.$authorFooter?.remove();
613
+ this.$authorFooter = footer;
614
+ this.$footer.appendChild(footer);
576
615
  }
577
616
 
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;
617
+ /** Unmount Footer from the box. */
618
+ public unmountFooter(): void {
619
+ if (this.$authorFooter) {
620
+ this.$authorFooter.remove();
621
+ this.$authorFooter = undefined;
585
622
  }
586
- this._$userStyles$.setValue($styles);
587
623
  }
588
624
 
625
+ /** Mount styles for box content */
626
+ public mountStyles(styles: string): void {
627
+ this.$styles.textContent = styles;
628
+ }
629
+
630
+ /** Umount styles for box content */
589
631
  public unmountStyles(): void {
590
- this._$userStyles$.setValue(undefined);
632
+ this.$styles.textContent = "";
633
+ }
634
+
635
+ /** Mount user styles for box content */
636
+ public mountUserStyles(styles: string): void {
637
+ this.$userStyles.textContent = styles;
591
638
  }
592
639
 
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);
640
+ /** Umount user styles for box content */
641
+ public unmountUserStyles(): void {
642
+ this.$userStyles.textContent = "";
596
643
  }
597
644
 
598
645
  /** DOM of the box */
599
646
  public $box: HTMLElement;
600
647
 
601
- /** DOM of the box content */
648
+ /** DOM of main area of the box. Including $body and $footer. */
649
+ public $main!: HTMLElement;
650
+
651
+ /** DOM of the box body */
652
+ public $body!: HTMLElement;
653
+
654
+ /** DOM of the box content container inside box body */
602
655
  public $content!: HTMLElement;
603
656
 
604
- /** DOM of the box title bar */
657
+ /** DOM of the box stage area inside box body */
658
+ public $stage?: HTMLElement;
659
+
660
+ /** DOM of custom box content styles */
661
+ public $styles!: HTMLStyleElement;
662
+
663
+ /** DOM of end user custom box content styles */
664
+ public $userStyles!: HTMLStyleElement;
665
+
666
+ /** DOM of the box title bar container */
605
667
  public $titleBar!: HTMLElement;
606
668
 
607
- /** DOM of the box footer */
669
+ /** DOM of the box footer container */
608
670
  public $footer!: HTMLElement;
609
671
 
610
- protected render(): HTMLElement {
672
+ private _render(): HTMLElement {
611
673
  if (this.$box) {
612
674
  return this.$box;
613
675
  }
614
676
 
615
- this.$box = document.createElement("div");
616
-
617
- this.$box.classList.add(this.wrapClassName("box"));
618
-
619
- const bindClassName = <TValue>(
620
- el: Element,
621
- val: ReadonlyVal<TValue, boolean>,
622
- className: string,
623
- predicate: (value: TValue) => boolean = isTruthy
624
- ): string => {
625
- return this._sideEffect.add(() => {
626
- const wrappedClassName = this.wrapClassName(className);
627
- return val.subscribe((value) => {
628
- el.classList.toggle(wrappedClassName, predicate(value));
629
- });
630
- });
677
+ const bindBoxStates = (el: Element, disposerID?: string): string => {
678
+ return this._sideEffect.addDisposer(
679
+ [
680
+ this._readonly$.subscribe((readonly) =>
681
+ el.classList.toggle(
682
+ this.wrapClassName("readonly"),
683
+ readonly
684
+ )
685
+ ),
686
+ this._draggable$.subscribe((draggable) =>
687
+ el.classList.toggle(
688
+ this.wrapClassName("no-drag"),
689
+ !draggable
690
+ )
691
+ ),
692
+ this._resizable$.subscribe((resizable) =>
693
+ el.classList.toggle(
694
+ this.wrapClassName("no-resize"),
695
+ !resizable
696
+ )
697
+ ),
698
+ this._focus$.subscribe((focus) =>
699
+ el.classList.toggle(this.wrapClassName("blur"), !focus)
700
+ ),
701
+ this._darkMode$.subscribe((darkMode) => {
702
+ el.classList.toggle(
703
+ this.wrapClassName("color-scheme-dark"),
704
+ darkMode
705
+ );
706
+ el.classList.toggle(
707
+ this.wrapClassName("color-scheme-light"),
708
+ !darkMode
709
+ );
710
+ }),
711
+ ],
712
+ disposerID
713
+ );
631
714
  };
632
715
 
633
- bindClassName(this.$box, this._readonly$, "readonly");
634
- bindClassName(this.$box, this._draggable$, "no-drag", isFalsy);
635
- bindClassName(this.$box, this._resizable$, "no-resize", isFalsy);
636
- bindClassName(this.$box, this._focus$, "blur", isFalsy);
637
- bindClassName(this.$box, this._darkMode$, "color-scheme-dark");
638
- bindClassName(
639
- this.$box,
640
- this._darkMode$,
641
- "color-scheme-light",
642
- isFalsy
643
- );
716
+ this.$box = document.createElement("div");
717
+ this.$box.classList.add(this.wrapClassName("box"));
718
+ bindBoxStates(this.$box, "bind-box-state");
644
719
 
645
720
  this._sideEffect.add(() => {
646
721
  const minimizedClassName = this.wrapClassName("minimized");
@@ -695,6 +770,8 @@ export class TeleBox {
695
770
  this._pxIntrinsicSize$,
696
771
  this._pxIntrinsicCoord$,
697
772
  this._collectorRect$,
773
+ this._rootRect$,
774
+ this._managerStageRect$,
698
775
  ],
699
776
  ([
700
777
  maximized,
@@ -702,42 +779,58 @@ export class TeleBox {
702
779
  pxIntrinsicSize,
703
780
  pxIntrinsicCoord,
704
781
  collectorRect,
782
+ rootRect,
783
+ managerStageRect,
705
784
  ]) => {
785
+ const styles: {
786
+ x: number;
787
+ y: number;
788
+ width: number;
789
+ height: number;
790
+ scaleX: number;
791
+ scaleY: number;
792
+ } = maximized
793
+ ? {
794
+ x: -managerStageRect.x,
795
+ y: -managerStageRect.y,
796
+ width: rootRect.width,
797
+ height: rootRect.height,
798
+ scaleX: 1,
799
+ scaleY: 1,
800
+ }
801
+ : {
802
+ x: pxIntrinsicCoord.x,
803
+ y: pxIntrinsicCoord.y,
804
+ width: pxIntrinsicSize.width,
805
+ height: pxIntrinsicSize.height,
806
+ scaleX: 1,
807
+ scaleY: 1,
808
+ };
706
809
  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
- };
715
- }
716
- if (maximized) {
717
- return {
718
- x: 0,
719
- y: 0,
720
- width: "100%",
721
- height: "100%",
722
- scaleX: 1,
723
- scaleY: 1,
724
- };
810
+ const { width: boxWidth, height: boxHeight } = maximized
811
+ ? this.rootRect
812
+ : pxIntrinsicSize;
813
+ styles.x =
814
+ collectorRect.x -
815
+ boxWidth / 2 +
816
+ collectorRect.width / 2 -
817
+ managerStageRect.x;
818
+ styles.y =
819
+ collectorRect.y -
820
+ boxHeight / 2 +
821
+ collectorRect.height / 2 -
822
+ managerStageRect.y;
823
+ styles.scaleX = collectorRect.width / boxWidth;
824
+ styles.scaleY = collectorRect.height / boxHeight;
725
825
  }
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
- };
826
+ return styles;
734
827
  },
735
828
  { compare: shallowequal }
736
829
  );
737
830
 
738
831
  const boxStyles = boxStyles$.value;
739
- this.$box.style.width = boxStyles.width;
740
- this.$box.style.height = boxStyles.height;
832
+ this.$box.style.width = boxStyles.width + "px";
833
+ this.$box.style.height = boxStyles.height + "px";
741
834
  // Add 10px offset on first frame
742
835
  // which creates a subtle moving effect
743
836
  this.$box.style.transform = `translate(${boxStyles.x - 10}px,${
@@ -759,91 +852,133 @@ export class TeleBox {
759
852
  $titleBar.appendChild(this.titleBar.render());
760
853
  this.$titleBar = $titleBar;
761
854
 
762
- const $contentWrap = document.createElement("div");
763
- $contentWrap.className = this.wrapClassName("content-wrap");
855
+ const $body = document.createElement("div");
856
+ $body.className = this.wrapClassName("body-wrap");
857
+ this.$body = $body;
858
+
859
+ const $styles = document.createElement("style");
860
+ this.$styles = $styles;
861
+ $body.appendChild($styles);
862
+
863
+ const $userStyles = document.createElement("style");
864
+ this.$userStyles = $userStyles;
865
+ $body.appendChild($userStyles);
764
866
 
765
867
  const $content = document.createElement("div");
766
868
  $content.className =
767
869
  this.wrapClassName("content") + " tele-fancy-scrollbar";
768
870
  this.$content = $content;
871
+ this._sideEffect.addDisposer(
872
+ combine(
873
+ [this._bodyStyle$, this._defaultBoxBodyStyle$],
874
+ ([bodyStyle, defaultBoxBodyStyle]) =>
875
+ bodyStyle ?? defaultBoxBodyStyle
876
+ ).subscribe((style) => ($content.style.cssText = style || ""))
877
+ );
769
878
 
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);
879
+ $body.appendChild($content);
813
880
 
814
881
  const $footer = document.createElement("div");
815
882
  $footer.className = this.wrapClassName("footer-wrap");
816
883
  this.$footer = $footer;
817
884
 
885
+ $boxMain.appendChild($titleBar);
886
+
887
+ const $main = document.createElement("div");
888
+ $main.className = this.wrapClassName("main");
889
+ this.$main = $main;
890
+ $boxMain.appendChild($main);
891
+
892
+ const $quarantineOuter = document.createElement("div");
893
+ $quarantineOuter.className = this.wrapClassName("quarantine-outer");
894
+ $main.appendChild($quarantineOuter);
895
+
896
+ const $quarantine = document.createElement("div");
897
+ $quarantine.className = this.wrapClassName("quarantine");
898
+ $quarantine.appendChild($body);
899
+ $quarantine.appendChild($footer);
900
+
901
+ if (this.enableShadowDOM) {
902
+ bindBoxStates($quarantine, "bind-quarantine-state");
903
+ const $shadowStyle = document.createElement("style");
904
+ $shadowStyle.textContent = shadowStyles;
905
+ $quarantine.insertBefore($shadowStyle, $quarantine.firstChild);
906
+ const shadow = $quarantineOuter.attachShadow({ mode: "open" });
907
+ shadow.appendChild($quarantine);
908
+ } else {
909
+ $quarantineOuter.appendChild($quarantine);
910
+ }
911
+
912
+ this._renderResizeHandlers();
913
+
914
+ const updateBodyRect = (): void => {
915
+ const rect = $body.getBoundingClientRect();
916
+ this._bodyRect$.setValue({
917
+ x: 0,
918
+ y: 0,
919
+ width: rect.width,
920
+ height: rect.height,
921
+ });
922
+ };
818
923
  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);
924
+ const observer = new ResizeObserver(() => {
925
+ if (!this.minimized) {
926
+ updateBodyRect();
827
927
  }
828
928
  });
929
+ observer.observe($body);
930
+ return () => observer.disconnect();
829
931
  });
932
+ this._sideEffect.addDisposer(
933
+ this._minimized$.reaction((minimized) => {
934
+ // correct content size when restoring from minimized
935
+ if (!minimized) {
936
+ this._sideEffect.setTimeout(
937
+ updateBodyRect,
938
+ 400,
939
+ "minimized-content-rect-fix"
940
+ );
941
+ }
942
+ })
943
+ );
830
944
 
831
- $boxMain.appendChild($titleBar);
832
- $boxMain.appendChild($contentWrap);
833
- $boxMain.appendChild($footer);
945
+ return this.$box;
946
+ }
834
947
 
835
- this._renderResizeHandlers();
948
+ private _renderStage(): HTMLDivElement {
949
+ const $stage = document.createElement("div");
836
950
 
837
- return this.$box;
951
+ $stage.className = this.wrapClassName("box-stage");
952
+ const updateStageRect = (stageRect: TeleBoxRect): void => {
953
+ $stage.style.top = stageRect.y + "px";
954
+ $stage.style.left = stageRect.x + "px";
955
+ $stage.style.width = stageRect.width + "px";
956
+ $stage.style.height = stageRect.height + "px";
957
+ };
958
+ this._sideEffect.addDisposer(
959
+ [
960
+ combine(
961
+ [this._stageStyle$, this._defaultBoxStageStyle$],
962
+ ([stageStyle, defaultBoxStageStyle]) =>
963
+ stageStyle ?? defaultBoxStageStyle
964
+ ).subscribe((styles) => {
965
+ $stage.style.cssText = styles || "";
966
+ updateStageRect(this._stageRect$.value);
967
+ }),
968
+ this._stageRect$.subscribe(updateStageRect),
969
+ ],
970
+ "box-stage-styles"
971
+ );
972
+ return $stage;
838
973
  }
839
974
 
840
- protected _handleTrackStart?: (ev: MouseEvent | TouchEvent) => void;
975
+ private _handleTrackStart?: (ev: PointerEvent) => void;
841
976
 
842
- public handleTrackStart: (ev: MouseEvent | TouchEvent) => void = (ev) => {
977
+ public handleTrackStart: (ev: PointerEvent) => void = (ev) => {
843
978
  return this._handleTrackStart?.(ev);
844
979
  };
845
980
 
846
- protected _renderResizeHandlers(): void {
981
+ private _renderResizeHandlers(): void {
847
982
  const $resizeHandles = document.createElement("div");
848
983
  $resizeHandles.className = this.wrapClassName("resize-handles");
849
984
 
@@ -876,16 +1011,16 @@ export class TeleBox {
876
1011
 
877
1012
  let trackingHandle: TeleBoxHandleType | undefined;
878
1013
 
879
- const handleTracking = (ev: MouseEvent | TouchEvent): void => {
880
- if (this.state !== TELE_BOX_STATE.Normal) {
1014
+ const handleTracking = (ev: PointerEvent): void => {
1015
+ if (!ev.isPrimary || this.state !== TELE_BOX_STATE.Normal) {
881
1016
  return;
882
1017
  }
883
1018
 
884
1019
  preventEvent(ev);
885
1020
 
886
- let { pageX, pageY } = flattenEvent(ev);
887
- if (pageY < this.rootRect.y) {
888
- pageY = this.rootRect.y;
1021
+ let { pageX, pageY } = ev;
1022
+ if (pageY < 0) {
1023
+ pageY = 0;
889
1024
  }
890
1025
 
891
1026
  const offsetX = pageX - trackStartPageX;
@@ -947,7 +1082,11 @@ export class TeleBox {
947
1082
  this.transform(newX, newY, newWidth, newHeight);
948
1083
  };
949
1084
 
950
- const handleTrackEnd = (ev: MouseEvent | TouchEvent): void => {
1085
+ const handleTrackEnd = (ev: PointerEvent): void => {
1086
+ if (!ev.isPrimary) {
1087
+ return;
1088
+ }
1089
+
951
1090
  trackingHandle = void 0;
952
1091
 
953
1092
  if (!$trackMask) {
@@ -963,8 +1102,8 @@ export class TeleBox {
963
1102
  $trackMask.remove();
964
1103
  };
965
1104
 
966
- const handleTrackStart = (ev: MouseEvent | TouchEvent): void => {
967
- if (this.readonly) {
1105
+ const handleTrackStart = (ev: PointerEvent): void => {
1106
+ if (!ev.isPrimary || this.readonly) {
968
1107
  return;
969
1108
  }
970
1109
 
@@ -992,8 +1131,7 @@ export class TeleBox {
992
1131
  ({ width: trackStartWidth, height: trackStartHeight } =
993
1132
  this.pxIntrinsicSize);
994
1133
 
995
- ({ pageX: trackStartPageX, pageY: trackStartPageY } =
996
- flattenEvent(ev));
1134
+ ({ pageX: trackStartPageX, pageY: trackStartPageY } = ev);
997
1135
 
998
1136
  trackingHandle = target.dataset
999
1137
  .teleBoxHandle as TELE_BOX_RESIZE_HANDLE;
@@ -1015,25 +1153,24 @@ export class TeleBox {
1015
1153
  this.$box.classList.add(transformingClassName);
1016
1154
 
1017
1155
  this._sideEffect.add(() => {
1018
- window.addEventListener("mousemove", handleTracking);
1019
- window.addEventListener("touchmove", handleTracking, {
1156
+ window.addEventListener("pointermove", handleTracking, {
1020
1157
  passive: false,
1021
1158
  });
1022
- window.addEventListener("mouseup", handleTrackEnd);
1023
- window.addEventListener("touchend", handleTrackEnd, {
1159
+ window.addEventListener("pointerup", handleTrackEnd, {
1024
1160
  passive: false,
1025
1161
  });
1026
- window.addEventListener("touchcancel", handleTrackEnd, {
1162
+ window.addEventListener("pointercancel", handleTrackEnd, {
1027
1163
  passive: false,
1028
1164
  });
1029
1165
 
1030
1166
  return () => {
1031
- window.removeEventListener("mousemove", handleTracking);
1032
- window.removeEventListener("touchmove", handleTracking);
1033
- window.removeEventListener("mouseup", handleTrackEnd);
1034
- window.removeEventListener("touchend", handleTrackEnd);
1035
1167
  window.removeEventListener(
1036
- "touchcancel",
1168
+ "pointermove",
1169
+ handleTracking
1170
+ );
1171
+ window.removeEventListener("pointerup", handleTrackEnd);
1172
+ window.removeEventListener(
1173
+ "pointercancel",
1037
1174
  handleTrackEnd
1038
1175
  );
1039
1176
  };
@@ -1045,18 +1182,10 @@ export class TeleBox {
1045
1182
 
1046
1183
  this._sideEffect.addEventListener(
1047
1184
  $resizeHandles,
1048
- "mousedown",
1185
+ "pointerdown",
1049
1186
  handleTrackStart,
1050
1187
  {},
1051
- "box-resizeHandles-mousedown"
1052
- );
1053
-
1054
- this._sideEffect.addEventListener(
1055
- $resizeHandles,
1056
- "touchstart",
1057
- handleTrackStart,
1058
- { passive: false },
1059
- "box-resizeHandles-touchstart"
1188
+ "box-resizeHandles-pointerdown"
1060
1189
  );
1061
1190
  }
1062
1191
 
@@ -1090,7 +1219,21 @@ export type ReadonlyTeleBox = Pick<
1090
1219
  | PropKeys
1091
1220
  | "wrapClassName"
1092
1221
  | "mountContent"
1222
+ | "unmountContent"
1093
1223
  | "mountFooter"
1224
+ | "unmountFooter"
1225
+ | "mountStage"
1226
+ | "unmountStage"
1094
1227
  | "mountStyles"
1228
+ | "unmountStyles"
1229
+ | "setTitle"
1230
+ | "setDraggable"
1231
+ | "setResizable"
1232
+ | "setVisible"
1233
+ | "setBoxRatio"
1234
+ | "setStageRatio"
1235
+ | "setStageStyle"
1236
+ | "setBodyStyle"
1095
1237
  | "handleTrackStart"
1238
+ | "onValChanged"
1096
1239
  >;