@netless/telebox-insider 0.2.25 → 1.0.0-alpha.10

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 (53) hide show
  1. package/dist/TeleBox/constants.d.ts +0 -3
  2. package/dist/TeleBox/index.d.ts +120 -97
  3. package/dist/TeleBox/typings.d.ts +42 -55
  4. package/dist/TeleBoxCollector/index.d.ts +27 -29
  5. package/dist/TeleBoxManager/MaxTitleBar/index.d.ts +14 -18
  6. package/dist/TeleBoxManager/constants.d.ts +0 -3
  7. package/dist/TeleBoxManager/index.d.ts +64 -19
  8. package/dist/TeleBoxManager/typings.d.ts +35 -28
  9. package/dist/TeleStage/index.d.ts +21 -0
  10. package/dist/TeleTitleBar/DefaultTitleBar/index.d.ts +5 -9
  11. package/dist/TeleTitleBar/typings.d.ts +4 -6
  12. package/dist/index.d.ts +0 -1
  13. package/dist/style.css +1 -1
  14. package/dist/telebox-insider.cjs.js +1 -15
  15. package/dist/telebox-insider.cjs.js.map +1 -1
  16. package/dist/telebox-insider.es.js +1 -15
  17. package/dist/telebox-insider.es.js.map +1 -1
  18. package/dist/utils.d.ts +0 -1
  19. package/package.json +7 -19
  20. package/src/TeleBox/constants.ts +0 -3
  21. package/src/TeleBox/index.ts +518 -689
  22. package/src/TeleBox/style.scss +6 -0
  23. package/src/TeleBox/typings.ts +42 -75
  24. package/src/TeleBoxCollector/index.ts +151 -159
  25. package/src/TeleBoxCollector/style.scss +4 -1
  26. package/src/TeleBoxManager/MaxTitleBar/index.ts +88 -108
  27. package/src/TeleBoxManager/MaxTitleBar/style.scss +8 -3
  28. package/src/TeleBoxManager/constants.ts +0 -3
  29. package/src/TeleBoxManager/index.ts +330 -336
  30. package/src/TeleBoxManager/typings.ts +42 -52
  31. package/src/TeleStage/index.ts +174 -0
  32. package/src/TeleStage/style.scss +49 -0
  33. package/src/TeleTitleBar/DefaultTitleBar/index.ts +44 -65
  34. package/src/TeleTitleBar/DefaultTitleBar/style.scss +7 -0
  35. package/src/TeleTitleBar/typings.ts +4 -10
  36. package/src/index.ts +0 -1
  37. package/src/scss/mixins.scss +7 -0
  38. package/src/scss/variables.scss +3 -0
  39. package/src/utils.ts +0 -6
  40. package/dist/TeleBoxCollector/TeleBoxCollector.stories.d.ts +0 -5
  41. package/dist/TeleBoxManager/MaxTitleBar/MaxTitleBar.stories.d.ts +0 -7
  42. package/dist/TeleBoxManager/MaxTitleBar/MaxTitleBarReact.d.ts +0 -4
  43. package/dist/TeleBoxReact/TeleBox.stories.d.ts +0 -9
  44. package/dist/TeleBoxReact/index.d.ts +0 -17
  45. package/dist/TeleBoxReact/utils.d.ts +0 -2
  46. package/dist/TeleTitleBar/DefaultTitleBar/DefaultTitleBar.stories.d.ts +0 -4
  47. package/src/TeleBoxCollector/TeleBoxCollector.stories.tsx +0 -23
  48. package/src/TeleBoxManager/MaxTitleBar/MaxTitleBar.stories.tsx +0 -66
  49. package/src/TeleBoxManager/MaxTitleBar/MaxTitleBarReact.tsx +0 -34
  50. package/src/TeleBoxReact/TeleBox.stories.tsx +0 -74
  51. package/src/TeleBoxReact/index.tsx +0 -175
  52. package/src/TeleBoxReact/utils.ts +0 -14
  53. package/src/TeleTitleBar/DefaultTitleBar/DefaultTitleBar.stories.tsx +0 -15
@@ -1,141 +1,181 @@
1
- import EventEmitter from "eventemitter3";
2
1
  import shallowequal from "shallowequal";
2
+ import { ResizeObserver as ResizeObserverPolyfill } from "@juggle/resize-observer";
3
+ import { SideEffectManager } from "side-effect-manager";
3
4
  import type {
4
- TeleBoxConfig,
5
+ ReadonlyVal,
6
+ ValEnhancedResult,
7
+ ReadonlyValEnhancedResult,
8
+ } from "value-enhancer";
9
+ import { derive } from "value-enhancer";
10
+ import {
11
+ combine,
12
+ Val,
13
+ withValueEnhancer,
14
+ withReadonlyValueEnhancer,
15
+ ValManager,
16
+ } from "value-enhancer";
17
+ import Emittery from "emittery";
18
+ import type {
19
+ ReadonlyTeleBox,
20
+ TeleBoxColorScheme,
5
21
  TeleBoxRect,
6
22
  TeleBoxState,
7
- } from "../TeleBox/typings";
23
+ } from "../TeleBox";
24
+ import {
25
+ TeleBox,
26
+ TELE_BOX_EVENT,
27
+ TELE_BOX_STATE,
28
+ TELE_BOX_COLOR_SCHEME,
29
+ TELE_BOX_DELEGATE_EVENT,
30
+ } from "../TeleBox";
8
31
  import { TeleBoxCollector } from "../TeleBoxCollector";
9
- import { ReadonlyTeleBox, TeleBox } from "../TeleBox";
10
- import { TELE_BOX_EVENT, TELE_BOX_STATE } from "../TeleBox/constants";
11
32
  import { TELE_BOX_MANAGER_EVENT } from "./constants";
12
33
  import type {
13
34
  TeleBoxManagerConfig,
14
35
  TeleBoxManagerCreateConfig,
15
- TeleBoxManagerEvents,
36
+ TeleBoxManagerEventConfig,
16
37
  TeleBoxManagerQueryConfig,
17
38
  TeleBoxManagerUpdateConfig,
18
39
  } from "./typings";
19
40
  import { MaxTitleBar } from "./MaxTitleBar";
20
- import {
21
- TeleBoxColorScheme,
22
- TELE_BOX_COLOR_SCHEME,
23
- TELE_BOX_DELEGATE_EVENT,
24
- } from "..";
25
- import { SideEffectManager } from "side-effect-manager";
26
- import {
27
- createSideEffectBinder,
28
- Val,
29
- ValEnhancedResult,
30
- withValueEnhancer,
31
- } from "value-enhancer";
41
+ import { TeleStage } from "../TeleStage";
32
42
 
33
43
  export * from "./typings";
34
44
  export * from "./constants";
35
45
 
46
+ const ResizeObserver = window.ResizeObserver || ResizeObserverPolyfill;
47
+
48
+ type ReadonlyValConfig = {
49
+ darkMode: ReadonlyVal<boolean, boolean>;
50
+ state: ReadonlyVal<TeleBoxState, boolean>;
51
+ root: Val<HTMLElement | null>;
52
+ rootRect: Val<TeleBoxRect>;
53
+ stageRect: ReadonlyVal<TeleBoxRect>;
54
+ };
55
+
36
56
  type ValConfig = {
37
57
  prefersColorScheme: Val<TeleBoxColorScheme, boolean>;
38
- containerRect: Val<TeleBoxRect, boolean>;
39
- collector: Val<TeleBoxCollector | null>;
40
- collectorRect: Val<TeleBoxRect | undefined>;
41
58
  readonly: Val<boolean, boolean>;
42
59
  minimized: Val<boolean, boolean>;
43
60
  maximized: Val<boolean, boolean>;
44
61
  fence: Val<boolean, boolean>;
62
+ stageRatio: Val<number, boolean>;
63
+ highlightStage: Val<boolean, boolean>;
45
64
  };
46
- export interface TeleBoxManager extends ValEnhancedResult<ValConfig> {}
65
+
66
+ type CombinedValEnhancedResult = ValEnhancedResult<ValConfig> &
67
+ ReadonlyValEnhancedResult<ReadonlyValConfig>;
68
+
69
+ export interface TeleBoxManager extends CombinedValEnhancedResult {}
47
70
 
48
71
  export class TeleBoxManager {
49
72
  public constructor({
50
- root = document.body,
73
+ root = null,
51
74
  prefersColorScheme = TELE_BOX_COLOR_SCHEME.Light,
52
75
  minimized = false,
53
76
  maximized = false,
54
- fence = true,
55
- containerRect = {
56
- x: 0,
57
- y: 0,
58
- width: window.innerWidth,
59
- height: window.innerHeight,
60
- },
77
+ fence = false,
61
78
  collector,
62
79
  namespace = "telebox",
63
80
  readonly = false,
81
+ stageRatio = -1,
82
+ highlightStage = true,
64
83
  }: TeleBoxManagerConfig = {}) {
65
84
  this._sideEffect = new SideEffectManager();
66
- const { combine, createVal } = createSideEffectBinder(this._sideEffect);
67
85
 
68
- this.root = root;
69
86
  this.namespace = namespace;
70
87
 
71
- this.boxes$ = createVal<TeleBox[]>([]);
72
- this.topBox$ = this.boxes$.derive((boxes) => {
73
- if (boxes.length > 0) {
74
- const topBox = boxes.reduce((topBox, box) =>
75
- topBox.zIndex > box.zIndex ? topBox : box
76
- );
77
- return topBox;
78
- }
79
- return;
80
- });
88
+ const valManager = new ValManager();
89
+ this._sideEffect.addDisposer(() => valManager.destroy());
90
+
91
+ const root$ = new Val(root);
92
+ const readonly$ = new Val(readonly);
93
+ const minimized$ = new Val(minimized);
94
+ const maximized$ = new Val(maximized);
95
+ const fence$ = new Val(fence);
96
+ const stageRatio$ = new Val(stageRatio);
97
+ const highlightStage$ = new Val(highlightStage);
98
+
99
+ const rootRect$ = new Val<TeleBoxRect>(
100
+ {
101
+ x: 0,
102
+ y: 0,
103
+ width: window.innerWidth,
104
+ height: window.innerHeight,
105
+ },
106
+ { compare: shallowequal }
107
+ );
108
+ this._sideEffect.addDisposer(
109
+ root$.subscribe((root) => {
110
+ this._sideEffect.add(() => {
111
+ if (!root) {
112
+ return () => void 0;
113
+ }
114
+ const observer = new ResizeObserver(() => {
115
+ const rect = root.getBoundingClientRect();
116
+ rootRect$.setValue({
117
+ x: rect.x,
118
+ y: rect.y,
119
+ width: rect.width,
120
+ height: rect.height,
121
+ });
122
+ });
123
+ observer.observe(root);
124
+ return () => observer.disconnect();
125
+ }, "calc-root-rect");
126
+ })
127
+ );
81
128
 
82
- const prefersDark = window.matchMedia("(prefers-color-scheme: dark)");
83
- const prefersDark$ = createVal(false);
129
+ this.boxes$ = new Val<TeleBox[]>([]);
130
+ this.topBox$ = new Val<TeleBox | undefined>(undefined);
131
+ this._sideEffect.addDisposer(
132
+ this.boxes$.subscribe((boxes) => {
133
+ if (boxes.length > 0) {
134
+ const topBox = boxes.reduce((topBox, box) =>
135
+ topBox.zIndex > box.zIndex ? topBox : box
136
+ );
137
+ this.topBox$.setValue(topBox);
138
+ } else {
139
+ this.topBox$.setValue(undefined);
140
+ }
141
+ })
142
+ );
84
143
 
85
- if (prefersDark) {
86
- prefersDark$.setValue(prefersDark.matches);
144
+ const prefersDarkMatch = window.matchMedia(
145
+ "(prefers-color-scheme: dark)"
146
+ );
147
+ const prefersDark$ = new Val(false);
148
+ if (prefersDarkMatch) {
149
+ prefersDark$.setValue(prefersDarkMatch.matches);
87
150
  this._sideEffect.add(() => {
88
151
  const handler = (evt: MediaQueryListEvent): void => {
89
152
  prefersDark$.setValue(evt.matches);
90
153
  };
91
- prefersDark.addListener(handler);
92
- return () => prefersDark.removeListener(handler);
154
+ prefersDarkMatch.addEventListener("change", handler);
155
+ return () =>
156
+ prefersDarkMatch.removeEventListener("change", handler);
93
157
  });
94
158
  }
95
159
 
96
- const prefersColorScheme$ = createVal(prefersColorScheme);
97
- prefersColorScheme$.reaction((prefersColorScheme, _, skipUpdate) => {
98
- this.boxes.forEach((box) =>
99
- box.setPrefersColorScheme(prefersColorScheme, skipUpdate)
100
- );
101
- if (!skipUpdate) {
102
- this.events.emit(
103
- TELE_BOX_MANAGER_EVENT.PrefersColorScheme,
104
- prefersColorScheme
105
- );
106
- }
107
- });
160
+ const prefersColorScheme$ = new Val(prefersColorScheme);
161
+ this._sideEffect.addDisposer(
162
+ prefersColorScheme$.reaction((prefersColorScheme, skipUpdate) => {
163
+ if (!skipUpdate) {
164
+ this.events.emit(
165
+ TELE_BOX_MANAGER_EVENT.PrefersColorScheme,
166
+ prefersColorScheme
167
+ );
168
+ }
169
+ })
170
+ );
108
171
 
109
- this._darkMode$ = combine(
172
+ const darkMode$ = combine(
110
173
  [prefersDark$, prefersColorScheme$],
111
174
  ([prefersDark, prefersColorScheme]) =>
112
175
  prefersColorScheme === "auto"
113
176
  ? prefersDark
114
177
  : prefersColorScheme === "dark"
115
178
  );
116
- this._darkMode$.reaction((darkMode, _, skipUpdate) => {
117
- this.boxes.forEach((box) => box.setDarkMode(darkMode, skipUpdate));
118
- if (!skipUpdate) {
119
- this.events.emit(TELE_BOX_MANAGER_EVENT.DarkMode, darkMode);
120
- }
121
- });
122
-
123
- const readonly$ = createVal(readonly);
124
- readonly$.reaction((readonly, _, skipUpdate) => {
125
- this.boxes.forEach((box) => box.setReadonly(readonly, skipUpdate));
126
- });
127
-
128
- const minimized$ = createVal(minimized);
129
-
130
- const maximized$ = createVal(maximized);
131
- maximized$.reaction((maximized, _, skipUpdate) => {
132
- this.boxes.forEach((box) =>
133
- box.setMaximized(maximized, skipUpdate)
134
- );
135
- if (!skipUpdate) {
136
- this.events.emit(TELE_BOX_MANAGER_EVENT.Maximized, maximized);
137
- }
138
- });
139
179
 
140
180
  const state$ = combine(
141
181
  [minimized$, maximized$],
@@ -146,101 +186,52 @@ export class TeleBoxManager {
146
186
  ? TELE_BOX_STATE.Maximized
147
187
  : TELE_BOX_STATE.Normal
148
188
  );
149
- state$.reaction((state, _, skipUpdate) => {
150
- this.maxTitleBar.setState(state);
151
- if (!skipUpdate) {
152
- this.events.emit(TELE_BOX_MANAGER_EVENT.State, state);
153
- }
154
- });
155
189
 
156
- const fence$ = createVal(fence);
157
- fence$.subscribe((fence, _, skipUpdate) => {
158
- this.boxes.forEach((box) => box.setFence(fence, skipUpdate));
159
- });
190
+ this.collector =
191
+ collector ??
192
+ new TeleBoxCollector({
193
+ minimized$: minimized$,
194
+ readonly$: readonly$,
195
+ darkMode$: darkMode$,
196
+ namespace,
197
+ root$,
198
+ rootRect$,
199
+ });
160
200
 
161
- const containerRect$ = createVal(containerRect, shallowequal);
162
- containerRect$.reaction((containerRect, _, skipUpdate) => {
163
- this.boxes.forEach((box) =>
164
- box.setContainerRect(containerRect, skipUpdate)
165
- );
166
- this.maxTitleBar.setContainerRect(containerRect);
201
+ const teleStage = new TeleStage({
202
+ namespace,
203
+ rootRect$,
204
+ ratio$: stageRatio$,
205
+ root$,
206
+ highlightStage$: combine(
207
+ [highlightStage$, maximized$, minimized$],
208
+ ([highlightStage, maximized, minimized]) =>
209
+ highlightStage && (minimized || !maximized)
210
+ ),
167
211
  });
168
-
169
- const collector$ = createVal(
170
- collector === null
171
- ? null
172
- : collector ||
173
- new TeleBoxCollector({
174
- visible: minimized,
175
- readonly: readonly,
176
- namespace,
177
- }).mount(root)
178
- );
179
- collector$.subscribe((collector) => {
180
- if (collector) {
181
- collector.setVisible(minimized$.value);
182
- collector.setReadonly(readonly$.value);
183
- collector.setDarkMode(this._darkMode$.value);
184
- this._sideEffect.add(() => {
185
- collector.onClick = () => {
186
- if (!readonly$.value) {
187
- minimized$.setValue(false);
188
- }
189
- };
190
- return () => collector.destroy();
191
- }, "collect-onClick");
192
- }
193
- });
194
- readonly$.subscribe((readonly) =>
195
- collector$.value?.setReadonly(readonly)
196
- );
197
- this._darkMode$.subscribe((darkMode) => {
198
- collector$.value?.setDarkMode(darkMode);
199
- });
200
-
201
- const calcCollectorRect = (): TeleBoxRect | undefined => {
202
- if (collector$.value?.$collector) {
203
- const { x, y, width, height } =
204
- collector$.value.$collector.getBoundingClientRect();
205
- const rootRect = this.root.getBoundingClientRect();
206
- return {
207
- x: x - rootRect.x,
208
- y: y - rootRect.y,
209
- width,
210
- height,
211
- };
212
- }
213
- return;
212
+ this._sideEffect.addDisposer(() => teleStage.destroy());
213
+
214
+ const readonlyValConfig: ReadonlyValConfig = {
215
+ darkMode: darkMode$,
216
+ state: state$,
217
+ root: root$,
218
+ rootRect: rootRect$,
219
+ stageRect: teleStage.stageRect$,
214
220
  };
215
221
 
216
- const collectorRect$ = createVal(
217
- minimized$.value ? calcCollectorRect() : void 0
218
- );
219
- collectorRect$.subscribe((collectorRect, _, skipUpdate) => {
220
- this.boxes.forEach((box) => {
221
- box.setCollectorRect(collectorRect, skipUpdate);
222
- });
223
- });
224
-
225
- minimized$.subscribe((minimized, _, skipUpdate) => {
226
- collector$.value?.setVisible(minimized);
227
-
228
- if (minimized) {
229
- if (collector$.value?.$collector) {
230
- collectorRect$.setValue(calcCollectorRect());
231
- } else if (import.meta.env.DEV) {
232
- console.warn("No collector for minimized boxes.");
233
- }
234
- }
222
+ withReadonlyValueEnhancer(this, readonlyValConfig, valManager);
235
223
 
236
- this.boxes.forEach((box) =>
237
- box.setMinimized(minimized, skipUpdate)
238
- );
224
+ const valConfig: ValConfig = {
225
+ prefersColorScheme: prefersColorScheme$,
226
+ readonly: readonly$,
227
+ fence: fence$,
228
+ minimized: minimized$,
229
+ maximized: maximized$,
230
+ stageRatio: stageRatio$,
231
+ highlightStage: highlightStage$,
232
+ };
239
233
 
240
- if (!skipUpdate) {
241
- this.events.emit(TELE_BOX_MANAGER_EVENT.Minimized, minimized);
242
- }
243
- });
234
+ withValueEnhancer(this, valConfig, valManager);
244
235
 
245
236
  const closeBtnClassName = this.wrapClassName("titlebar-icon-close");
246
237
 
@@ -287,13 +278,15 @@ export class TeleBoxManager {
287
278
  true
288
279
  );
289
280
 
290
- this.maxTitleBar = new MaxTitleBar({
291
- darkMode: this.darkMode,
292
- readonly: readonly$.value,
281
+ this.titleBar = new MaxTitleBar({
293
282
  namespace: this.namespace,
294
- state: state$.value,
295
- boxes: this.boxes$.value,
296
- containerRect: containerRect$.value,
283
+ title$: derive(this.topBox$, (topBox) => topBox?.title || ""),
284
+ boxes$: this.boxes$,
285
+ darkMode$: darkMode$,
286
+ readonly$: readonly$,
287
+ state$: state$,
288
+ root$,
289
+ rootRect$: rootRect$,
297
290
  onEvent: (event): void => {
298
291
  switch (event.type) {
299
292
  case TELE_BOX_DELEGATE_EVENT.Maximize: {
@@ -315,32 +308,35 @@ export class TeleBoxManager {
315
308
  }
316
309
  },
317
310
  });
318
- readonly$.subscribe((readonly) =>
319
- this.maxTitleBar.setReadonly(readonly)
320
- );
321
- this._darkMode$.subscribe((darkMode) => {
322
- this.maxTitleBar.setDarkMode(darkMode);
323
- });
324
- this.boxes$.reaction((boxes) => {
325
- this.maxTitleBar.setBoxes(boxes);
326
- });
327
311
 
328
- const valConfig: ValConfig = {
329
- prefersColorScheme: prefersColorScheme$,
330
- containerRect: containerRect$,
331
- collector: collector$,
332
- collectorRect: collectorRect$,
333
- readonly: readonly$,
334
- fence: fence$,
335
- minimized: minimized$,
336
- maximized: maximized$,
337
- };
338
-
339
- withValueEnhancer(this, valConfig);
340
-
341
- this._state$ = state$;
342
-
343
- this.root.appendChild(this.maxTitleBar.render());
312
+ this._sideEffect.addDisposer([
313
+ state$.reaction((state, skipUpdate) => {
314
+ if (!skipUpdate) {
315
+ this.events.emit(TELE_BOX_MANAGER_EVENT.State, state);
316
+ }
317
+ }),
318
+ maximized$.reaction((maximized, skipUpdate) => {
319
+ if (!skipUpdate) {
320
+ this.events.emit(
321
+ TELE_BOX_MANAGER_EVENT.Maximized,
322
+ maximized
323
+ );
324
+ }
325
+ }),
326
+ minimized$.reaction((minimized, skipUpdate) => {
327
+ if (!skipUpdate) {
328
+ this.events.emit(
329
+ TELE_BOX_MANAGER_EVENT.Minimized,
330
+ minimized
331
+ );
332
+ }
333
+ }),
334
+ darkMode$.reaction((darkMode, skipUpdate) => {
335
+ if (!skipUpdate) {
336
+ this.events.emit(TELE_BOX_MANAGER_EVENT.DarkMode, darkMode);
337
+ }
338
+ }),
339
+ ]);
344
340
  }
345
341
 
346
342
  public get boxes(): ReadonlyArray<TeleBox> {
@@ -351,26 +347,15 @@ export class TeleBoxManager {
351
347
  return this.topBox$.value;
352
348
  }
353
349
 
354
- public readonly events = new EventEmitter() as TeleBoxManagerEvents;
350
+ public readonly events = new Emittery<
351
+ TeleBoxManagerEventConfig,
352
+ TeleBoxManagerEventConfig
353
+ >();
355
354
 
356
355
  protected _sideEffect: SideEffectManager;
357
356
 
358
- protected root: HTMLElement;
359
-
360
357
  public readonly namespace: string;
361
358
 
362
- public _darkMode$: Val<boolean, boolean>;
363
-
364
- public get darkMode(): boolean {
365
- return this._darkMode$.value;
366
- }
367
-
368
- public _state$: Val<TeleBoxState, boolean>;
369
-
370
- public get state(): TeleBoxState {
371
- return this._state$.value;
372
- }
373
-
374
359
  /** @deprecated use setMaximized and setMinimized instead */
375
360
  public setState(state: TeleBoxState, skipUpdate = false): this {
376
361
  switch (state) {
@@ -399,20 +384,22 @@ export class TeleBoxManager {
399
384
  ): ReadonlyTeleBox {
400
385
  const box = new TeleBox({
401
386
  zIndex: this.topBox ? this.topBox.zIndex + 1 : 100,
402
- ...(smartPosition ? this.smartPosition(config) : config),
403
- darkMode: this.darkMode,
404
- prefersColorScheme: this.prefersColorScheme,
405
- maximized: this.maximized,
406
- minimized: this.minimized,
407
- fence: this.fence,
387
+ ...config,
388
+ ...(smartPosition ? this.smartPosition(config) : {}),
408
389
  namespace: this.namespace,
409
- containerRect: this.containerRect,
410
- readonly: this.readonly,
411
- collectorRect: this.collectorRect,
390
+ root$: this._root$,
391
+ darkMode$: this._darkMode$,
392
+ maximized$: this._maximized$,
393
+ minimized$: this._minimized$,
394
+ fence$: this._fence$,
395
+ rootRect$: this._rootRect$,
396
+ managerStageRect$: this._stageRect$,
397
+ stageRatio$: this._stageRatio$,
398
+ readonly$: this._readonly$,
399
+ collectorRect$: this.collector._rect$,
400
+ managerHighlightStage$: this._highlightStage$,
412
401
  });
413
402
 
414
- box.mount(this.root);
415
-
416
403
  if (box.focus) {
417
404
  this.focusBox(box);
418
405
  if (smartPosition) {
@@ -422,52 +409,43 @@ export class TeleBoxManager {
422
409
 
423
410
  this.boxes$.setValue([...this.boxes, box]);
424
411
 
425
- box._delegateEvents.on(TELE_BOX_DELEGATE_EVENT.Maximize, () => {
426
- this.setMaximized(!this.maximized);
427
- });
428
- box._delegateEvents.on(TELE_BOX_DELEGATE_EVENT.Minimize, () => {
429
- this.setMinimized(true);
430
- });
431
- box._delegateEvents.on(TELE_BOX_DELEGATE_EVENT.Close, () => {
432
- this.remove(box);
433
- this.focusTopBox();
434
- });
435
- box._coord$.reaction((_, __, skipUpdate) => {
436
- if (!skipUpdate) {
437
- this.events.emit(TELE_BOX_MANAGER_EVENT.Move, box);
438
- }
439
- });
440
- box._size$.reaction((_, __, skipUpdate) => {
441
- if (!skipUpdate) {
442
- this.events.emit(TELE_BOX_MANAGER_EVENT.Resize, box);
443
- }
444
- });
445
- box._intrinsicCoord$.reaction((_, __, skipUpdate) => {
446
- if (!skipUpdate) {
447
- this.events.emit(TELE_BOX_MANAGER_EVENT.IntrinsicMove, box);
448
- }
449
- });
450
- box._intrinsicSize$.reaction((_, __, skipUpdate) => {
451
- if (!skipUpdate) {
452
- this.events.emit(TELE_BOX_MANAGER_EVENT.IntrinsicResize, box);
453
- }
454
- });
455
- box._visualSize$.reaction((_, __, skipUpdate) => {
456
- if (!skipUpdate) {
457
- this.events.emit(TELE_BOX_MANAGER_EVENT.VisualResize, box);
458
- }
459
- });
460
- box._zIndex$.reaction((_, __, skipUpdate) => {
461
- if (this.boxes.length > 0) {
462
- const topBox = this.boxes.reduce((topBox, box) =>
463
- topBox.zIndex > box.zIndex ? topBox : box
464
- );
465
- this.topBox$.setValue(topBox);
466
- }
467
- if (!skipUpdate) {
468
- this.events.emit(TELE_BOX_MANAGER_EVENT.ZIndex, box);
469
- }
470
- });
412
+ this._sideEffect.addDisposer([
413
+ box._delegateEvents.on(TELE_BOX_DELEGATE_EVENT.Maximize, () => {
414
+ this.setMaximized(!this.maximized);
415
+ }),
416
+ box._delegateEvents.on(TELE_BOX_DELEGATE_EVENT.Minimize, () => {
417
+ this.setMinimized(true);
418
+ }),
419
+ box._delegateEvents.on(TELE_BOX_DELEGATE_EVENT.Close, () => {
420
+ this.remove(box);
421
+ this.focusTopBox();
422
+ }),
423
+ box._intrinsicCoord$.reaction((_, skipUpdate) => {
424
+ if (!skipUpdate) {
425
+ this.events.emit(TELE_BOX_MANAGER_EVENT.IntrinsicMove, box);
426
+ }
427
+ }),
428
+ box._intrinsicSize$.reaction((_, skipUpdate) => {
429
+ if (!skipUpdate) {
430
+ this.events.emit(
431
+ TELE_BOX_MANAGER_EVENT.IntrinsicResize,
432
+ box
433
+ );
434
+ }
435
+ }),
436
+ box._zIndex$.reaction((_, skipUpdate) => {
437
+ if (this.boxes.length > 0) {
438
+ const topBox = this.boxes.reduce((topBox, box) =>
439
+ topBox.zIndex > box.zIndex ? topBox : box
440
+ );
441
+ this.topBox$.setValue(topBox);
442
+ }
443
+ if (!skipUpdate) {
444
+ this.events.emit(TELE_BOX_MANAGER_EVENT.ZIndex, box);
445
+ }
446
+ }),
447
+ ]);
448
+
471
449
  this.events.emit(TELE_BOX_MANAGER_EVENT.Created, box);
472
450
 
473
451
  return box;
@@ -550,17 +528,26 @@ export class TeleBoxManager {
550
528
  return deletedBoxes;
551
529
  }
552
530
 
531
+ /**
532
+ * Mount manager to a container element.
533
+ */
534
+ public mount(root: HTMLElement): void {
535
+ this._root$.setValue(root);
536
+ }
537
+
538
+ /**
539
+ * Unmount manager from the container element.
540
+ */
541
+ public unmount(): void {
542
+ this._root$.setValue(null);
543
+ }
544
+
553
545
  public destroy(skipUpdate = false): void {
554
- this.events.removeAllListeners();
546
+ this.events.clearListeners();
555
547
  this._sideEffect.flushAll();
556
548
  this.removeAll(skipUpdate);
557
-
558
- Object.keys(this).forEach((key) => {
559
- const value = this[key as keyof this];
560
- if (value instanceof Val) {
561
- value.destroy();
562
- }
563
- });
549
+ this.collector.destroy();
550
+ this.titleBar.destroy();
564
551
  }
565
552
 
566
553
  public wrapClassName(className: string): string {
@@ -575,7 +562,7 @@ export class TeleBoxManager {
575
562
  let focusChanged = false;
576
563
  if (!targetBox.focus) {
577
564
  focusChanged = true;
578
- targetBox.setFocus(true, skipUpdate);
565
+ targetBox._focus$.setValue(true, skipUpdate);
579
566
  }
580
567
  if (focusChanged && !skipUpdate) {
581
568
  this.events.emit(
@@ -587,7 +574,7 @@ export class TeleBoxManager {
587
574
  this.blurBox(box, skipUpdate);
588
575
  }
589
576
  });
590
- this.maxTitleBar.focusBox(targetBox);
577
+ this.titleBar.focusBox(targetBox);
591
578
  }
592
579
  }
593
580
 
@@ -601,13 +588,13 @@ export class TeleBoxManager {
601
588
  const targetBox = this.getBox(boxOrID);
602
589
  if (targetBox) {
603
590
  if (targetBox.focus) {
604
- targetBox.setFocus(false, skipUpdate);
591
+ targetBox._focus$.setValue(false, skipUpdate);
605
592
  if (!skipUpdate) {
606
593
  this.events.emit(TELE_BOX_MANAGER_EVENT.Blurred, targetBox);
607
594
  }
608
595
  }
609
- if (this.maxTitleBar.focusedBox === targetBox) {
610
- this.maxTitleBar.focusBox();
596
+ if (this.titleBar.focusedBox === targetBox) {
597
+ this.titleBar.focusBox();
611
598
  }
612
599
  }
613
600
  }
@@ -615,18 +602,19 @@ export class TeleBoxManager {
615
602
  public blurAll(skipUpdate = false): void {
616
603
  this.boxes.forEach((box) => {
617
604
  if (box.focus) {
618
- box.setFocus(false, skipUpdate);
605
+ box._focus$.setValue(false, skipUpdate);
619
606
  if (!skipUpdate) {
620
607
  this.events.emit(TELE_BOX_MANAGER_EVENT.Blurred, box);
621
608
  }
622
609
  }
623
610
  });
624
- if (this.maxTitleBar.focusedBox) {
625
- this.maxTitleBar.focusBox();
611
+ if (this.titleBar.focusedBox) {
612
+ this.titleBar.focusBox();
626
613
  }
627
614
  }
628
615
 
629
- protected maxTitleBar: MaxTitleBar;
616
+ public collector: TeleBoxCollector;
617
+ public titleBar: MaxTitleBar;
630
618
 
631
619
  protected boxes$: Val<TeleBox[]>;
632
620
  protected topBox$: Val<TeleBox | undefined>;
@@ -647,43 +635,40 @@ export class TeleBoxManager {
647
635
  skipUpdate = false
648
636
  ): void {
649
637
  if (config.x != null || config.y != null) {
650
- box.move(
651
- config.x == null ? box.intrinsicX : config.x,
652
- config.y == null ? box.intrinsicY : config.y,
638
+ box._intrinsicCoord$.setValue(
639
+ {
640
+ x: config.x ?? box.intrinsicX,
641
+ y: config.y ?? box.intrinsicY,
642
+ },
653
643
  skipUpdate
654
644
  );
655
645
  }
656
646
  if (config.width != null || config.height != null) {
657
- box.resize(
658
- config.width == null ? box.intrinsicWidth : config.width,
659
- config.height == null ? box.intrinsicHeight : config.height,
647
+ box._intrinsicSize$.setValue(
648
+ {
649
+ width: config.width ?? box.intrinsicWidth,
650
+ height: config.height ?? box.intrinsicHeight,
651
+ },
660
652
  skipUpdate
661
653
  );
662
654
  }
663
655
  if (config.title != null) {
664
- box.setTitle(config.title);
665
- this.maxTitleBar.updateTitles();
656
+ box._title$.setValue(config.title);
666
657
  }
667
658
  if (config.visible != null) {
668
- box.setVisible(config.visible, skipUpdate);
669
- }
670
- if (config.minHeight != null) {
671
- box.setMinHeight(config.minHeight, skipUpdate);
672
- }
673
- if (config.minWidth != null) {
674
- box.setMinWidth(config.minWidth, skipUpdate);
659
+ box._visible$.setValue(config.visible, skipUpdate);
675
660
  }
676
661
  if (config.resizable != null) {
677
- box.setResizable(config.resizable, skipUpdate);
662
+ box._resizable$.setValue(config.resizable, skipUpdate);
678
663
  }
679
664
  if (config.draggable != null) {
680
- box.setDraggable(config.draggable, skipUpdate);
665
+ box._draggable$.setValue(config.draggable, skipUpdate);
681
666
  }
682
- if (config.fixRatio != null) {
683
- box.setFixRatio(config.fixRatio, skipUpdate);
667
+ if (config.ratio != null) {
668
+ box._ratio$.setValue(config.ratio, skipUpdate);
684
669
  }
685
670
  if (config.zIndex != null) {
686
- box.setZIndex(config.zIndex, skipUpdate);
671
+ box._zIndex$.setValue(config.zIndex, skipUpdate);
687
672
  }
688
673
  if (config.content != null) {
689
674
  box.mountContent(config.content);
@@ -691,52 +676,61 @@ export class TeleBoxManager {
691
676
  if (config.footer != null) {
692
677
  box.mountFooter(config.footer);
693
678
  }
679
+ if (config.minHeight != null || config.minWidth != null) {
680
+ box._minSize$.setValue(
681
+ {
682
+ width: config.minWidth ?? box.minWidth,
683
+ height: config.minHeight ?? box.minHeight,
684
+ },
685
+ skipUpdate
686
+ );
687
+ }
694
688
  }
695
689
 
696
- protected smartPosition(config: TeleBoxConfig = {}): TeleBoxConfig {
697
- let { x, y } = config;
698
- const { width = 0.5, height = 0.5 } = config;
690
+ /** Keep new boxes staggered inside stage area */
691
+ protected smartPosition(rect: Partial<TeleBoxRect>): TeleBoxRect {
692
+ let { x, y } = rect;
693
+ const { width = 0.5, height = 0.5 } = rect;
694
+ const stageRect = this.stageRect;
695
+ const topBox = this.topBox;
699
696
 
700
697
  if (x == null) {
701
- let vx = 20;
702
- if (this.topBox) {
703
- vx = this.topBox.intrinsicX * this.containerRect.width + 20;
704
-
698
+ let pxX = stageRect.x + 20;
699
+ if (topBox) {
700
+ const pxPreferredX = topBox.pxIntrinsicCoord.x + 20;
701
+ const pxIntrinsicWidth = width * stageRect.width;
705
702
  if (
706
- vx >
707
- this.containerRect.width - width * this.containerRect.width
703
+ pxPreferredX + pxIntrinsicWidth <=
704
+ stageRect.x + stageRect.width
708
705
  ) {
709
- vx = 20;
706
+ pxX = pxPreferredX;
710
707
  }
711
708
  }
712
- x = vx / this.containerRect.width;
709
+ x = (pxX - stageRect.x) / stageRect.width;
713
710
  }
714
711
 
715
712
  if (y == null) {
716
- let vy = 20;
717
-
718
- if (this.topBox) {
719
- vy = this.topBox.intrinsicY * this.containerRect.height + 20;
720
-
713
+ let pxY = stageRect.y + 20;
714
+ if (topBox) {
715
+ const pxPreferredY = topBox.pxIntrinsicCoord.y + 20;
716
+ const pxIntrinsicHeight = height * stageRect.height;
721
717
  if (
722
- vy >
723
- this.containerRect.height -
724
- height * this.containerRect.height
718
+ pxPreferredY + pxIntrinsicHeight <=
719
+ stageRect.y + stageRect.height
725
720
  ) {
726
- vy = 20;
721
+ pxY = pxPreferredY;
727
722
  }
728
723
  }
729
-
730
- y = vy / this.containerRect.height;
724
+ y = (pxY - stageRect.y) / stageRect.height;
731
725
  }
732
726
 
733
- return { ...config, x, y, width, height };
727
+ return { x, y, width, height };
734
728
  }
735
729
 
736
730
  protected makeBoxTop(box: TeleBox, skipUpdate = false): void {
737
731
  if (this.topBox) {
738
732
  if (box !== this.topBox) {
739
- box.setZIndex(this.topBox.zIndex + 1, skipUpdate);
733
+ box._zIndex$.setValue(this.topBox.zIndex + 1, skipUpdate);
740
734
  }
741
735
  }
742
736
  }