@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,21 +1,27 @@
1
1
  import "./style.scss";
2
2
 
3
- import EventEmitter from "eventemitter3";
3
+ import Emittery from "emittery";
4
4
  import styler from "stylefire";
5
5
  import shallowequal from "shallowequal";
6
- import { SideEffectManager } from "side-effect-manager";
6
+ import { genUID, SideEffectManager } from "side-effect-manager";
7
+ import type {
8
+ ReadonlyVal,
9
+ ReadonlyValEnhancedResult,
10
+ ValEnhancedResult,
11
+ } from "value-enhancer";
7
12
  import {
8
- createSideEffectBinder,
13
+ combine,
9
14
  Val,
10
- ValEnhancedResult,
11
- ValSideEffectBinder,
15
+ withReadonlyValueEnhancer,
12
16
  withValueEnhancer,
17
+ ValManager,
13
18
  } from "value-enhancer";
14
- import { DefaultTitleBar, TeleTitleBar } from "../TeleTitleBar";
19
+ import type { TeleTitleBar } from "../TeleTitleBar";
20
+ import { DefaultTitleBar } from "../TeleTitleBar";
21
+ import { ResizeObserver as ResizeObserverPolyfill } from "@juggle/resize-observer";
15
22
  import {
16
23
  clamp,
17
24
  flattenEvent,
18
- genUniqueKey,
19
25
  getBoxDefaultName,
20
26
  isFalsy,
21
27
  isTruthy,
@@ -25,61 +31,79 @@ import {
25
31
  TELE_BOX_EVENT,
26
32
  TELE_BOX_STATE,
27
33
  TELE_BOX_RESIZE_HANDLE,
28
- TELE_BOX_DELEGATE_EVENT,
29
- TELE_BOX_COLOR_SCHEME,
30
34
  } from "./constants";
31
35
  import type {
32
36
  TeleBoxConfig,
33
- TeleBoxRect,
34
- TeleBoxEvents,
35
37
  TeleBoxHandleType,
36
38
  TeleBoxState,
37
- TeleBoxDelegateEvents,
38
39
  TeleBoxCoord,
39
40
  TeleBoxSize,
40
- TeleBoxColorScheme,
41
+ TeleBoxEventConfig,
42
+ TeleBoxEvent,
43
+ TeleBoxDelegateEventConfig,
44
+ TeleBoxRect,
41
45
  } from "./typings";
46
+ import { TeleStage } from "../TeleStage";
42
47
 
43
48
  export * from "./constants";
44
49
  export * from "./typings";
45
50
 
51
+ const ResizeObserver = window.ResizeObserver || ResizeObserverPolyfill;
52
+
53
+ type RequiredTeleBoxConfig = Required<TeleBoxConfig>;
54
+
46
55
  type ValConfig = {
47
- prefersColorScheme: Val<TeleBoxColorScheme, boolean>;
48
- darkMode: Val<boolean, boolean>;
49
- containerRect: Val<TeleBoxRect, boolean>;
50
- collectorRect: Val<TeleBoxRect | undefined, boolean>;
51
- /** Box title. Default empty. */
52
- title: Val<string, boolean>;
53
- /** Is box visible */
54
- visible: Val<boolean, boolean>;
55
- /** Is box readonly */
56
- readonly: Val<boolean, boolean>;
57
- /** Able to resize box window */
58
- resizable: Val<boolean, boolean>;
59
- /** Able to drag box window */
60
- draggable: Val<boolean, boolean>;
61
- /** Restrict box to always be within the containing area. */
62
- fence: Val<boolean, boolean>;
63
- /** Fixed width/height ratio for box window. */
64
- fixRatio: Val<boolean, boolean>;
65
- focus: Val<boolean, boolean>;
66
- zIndex: Val<number, boolean>;
67
- /** Is box minimized. Default false. */
68
- minimized: Val<boolean, boolean>;
69
- /** Is box maximized. Default false. */
70
- maximized: Val<boolean, boolean>;
71
- $userContent: Val<HTMLElement | undefined>;
72
- $userFooter: Val<HTMLElement | undefined>;
73
- $userStyles: Val<HTMLStyleElement | undefined>;
56
+ title: Val<RequiredTeleBoxConfig["title"], boolean>;
57
+ visible: Val<RequiredTeleBoxConfig["visible"], boolean>;
58
+ resizable: Val<RequiredTeleBoxConfig["resizable"], boolean>;
59
+ draggable: Val<RequiredTeleBoxConfig["draggable"], boolean>;
60
+ ratio: Val<RequiredTeleBoxConfig["ratio"], boolean>;
61
+ };
62
+
63
+ type PropsValConfig = {
64
+ darkMode: RequiredTeleBoxConfig["darkMode$"];
65
+ fence: RequiredTeleBoxConfig["fence$"];
66
+ minimized: RequiredTeleBoxConfig["minimized$"];
67
+ maximized: RequiredTeleBoxConfig["maximized$"];
68
+ readonly: RequiredTeleBoxConfig["readonly$"];
69
+ rootRect: RequiredTeleBoxConfig["rootRect$"];
70
+ managerStageRect: RequiredTeleBoxConfig["managerStageRect$"];
71
+ collectorRect: RequiredTeleBoxConfig["collectorRect$"];
74
72
  };
75
- export interface TeleBox extends ValEnhancedResult<ValConfig> {}
73
+
74
+ type MyReadonlyValConfig = {
75
+ zIndex: Val<RequiredTeleBoxConfig["zIndex"], boolean>;
76
+ focus: Val<RequiredTeleBoxConfig["focus"], boolean>;
77
+
78
+ $userContent: Val<TeleBoxConfig["content"], boolean>;
79
+ $userFooter: Val<TeleBoxConfig["footer"], boolean>;
80
+ $userStyles: Val<TeleBoxConfig["styles"], boolean>;
81
+
82
+ minSize: Val<TeleBoxSize, boolean>;
83
+ intrinsicSize: Val<TeleBoxSize, boolean>;
84
+ intrinsicCoord: Val<TeleBoxCoord, boolean>;
85
+ pxMinSize: ReadonlyVal<TeleBoxSize, boolean>;
86
+ pxIntrinsicSize: ReadonlyVal<TeleBoxSize, boolean>;
87
+ pxIntrinsicCoord: ReadonlyVal<TeleBoxCoord, boolean>;
88
+ state: ReadonlyVal<TeleBoxState, boolean>;
89
+ highlightStage: ReadonlyVal<boolean, boolean>;
90
+ boxHighlightStage: Val<boolean | null, boolean>;
91
+ contentRect: Val<TeleBoxRect>;
92
+ contentStageRect: ReadonlyVal<TeleBoxRect | null>;
93
+ };
94
+
95
+ type CombinedValEnhancedResult = ReadonlyValEnhancedResult<
96
+ PropsValConfig & MyReadonlyValConfig
97
+ > &
98
+ ValEnhancedResult<ValConfig>;
99
+
100
+ export interface TeleBox extends CombinedValEnhancedResult {}
76
101
 
77
102
  export class TeleBox {
78
103
  public constructor({
79
- id = genUniqueKey(),
104
+ id = genUID(),
80
105
  title = getBoxDefaultName(),
81
- prefersColorScheme = TELE_BOX_COLOR_SCHEME.Light,
82
- darkMode,
106
+ namespace = "telebox",
83
107
  visible = true,
84
108
  width = 0.5,
85
109
  height = 0.5,
@@ -87,146 +111,46 @@ export class TeleBox {
87
111
  minHeight = 0,
88
112
  x = 0.1,
89
113
  y = 0.1,
90
- minimized = false,
91
- maximized = false,
92
- readonly = false,
93
114
  resizable = true,
94
115
  draggable = true,
95
- fence = true,
96
- fixRatio = false,
116
+ ratio = -1,
97
117
  focus = false,
98
118
  zIndex = 100,
99
- namespace = "telebox",
100
119
  titleBar,
101
120
  content,
102
121
  footer,
103
122
  styles,
104
- containerRect = {
105
- x: 0,
106
- y: 0,
107
- width: window.innerWidth,
108
- height: window.innerHeight,
109
- },
110
- collectorRect,
111
- }: TeleBoxConfig = {}) {
123
+ highlightStage = null,
124
+ darkMode$,
125
+ fence$,
126
+ minimized$,
127
+ maximized$,
128
+ readonly$,
129
+ root$,
130
+ rootRect$,
131
+ managerStageRect$,
132
+ stageRatio$,
133
+ collectorRect$,
134
+ managerHighlightStage$,
135
+ }: TeleBoxConfig) {
112
136
  this._sideEffect = new SideEffectManager();
113
- this._valSideEffectBinder = createSideEffectBinder(this._sideEffect);
114
- const { combine, createVal } = this._valSideEffectBinder;
115
137
 
116
138
  this.id = id;
117
139
  this.namespace = namespace;
118
- this.events = new EventEmitter();
119
- this._delegateEvents = new EventEmitter();
120
-
121
- const prefersColorScheme$ = createVal<TeleBoxColorScheme, boolean>(
122
- prefersColorScheme
123
- );
124
- prefersColorScheme$.reaction((prefersColorScheme, _, skipUpdate) => {
125
- if (!skipUpdate) {
126
- this.events.emit(
127
- TELE_BOX_EVENT.PrefersColorScheme,
128
- prefersColorScheme
129
- );
130
- }
131
- });
132
-
133
- const darkMode$ = createVal(Boolean(darkMode));
134
-
135
- if (darkMode == null) {
136
- prefersColorScheme$.subscribe(
137
- (prefersColorScheme, _, skipUpdate) => {
138
- this._sideEffect.add(() => {
139
- if (prefersColorScheme === "auto") {
140
- const prefersDark = window.matchMedia(
141
- "(prefers-color-scheme: dark)"
142
- );
143
- if (prefersDark) {
144
- darkMode$.setValue(
145
- prefersDark.matches,
146
- skipUpdate
147
- );
148
- const handler = (
149
- evt: MediaQueryListEvent
150
- ): void => {
151
- darkMode$.setValue(evt.matches, skipUpdate);
152
- };
153
- prefersDark.addListener(handler);
154
- return () =>
155
- prefersDark.removeListener(handler);
156
- } else {
157
- return noop;
158
- }
159
- } else {
160
- darkMode$.setValue(
161
- prefersColorScheme === "dark",
162
- skipUpdate
163
- );
164
- return noop;
165
- }
166
- }, "prefers-color-scheme");
167
- }
168
- );
169
- }
170
-
171
- darkMode$.reaction((darkMode, _, skipUpdate) => {
172
- if (!skipUpdate) {
173
- this.events.emit(TELE_BOX_EVENT.DarkMode, darkMode);
174
- }
175
- });
176
-
177
- const containerRect$ = createVal(containerRect, shallowequal);
178
- const collectorRect$ = createVal(collectorRect, shallowequal);
179
-
180
- const title$ = createVal(title);
181
-
182
- const visible$ = createVal(visible);
183
- visible$.reaction((visible, _, skipUpdate) => {
184
- if (!skipUpdate && !visible) {
185
- this.events.emit(TELE_BOX_EVENT.Close);
186
- }
187
- });
188
-
189
- const readonly$ = createVal(readonly);
190
- readonly$.reaction((readonly, _, skipUpdate) => {
191
- if (!skipUpdate) {
192
- this.events.emit(TELE_BOX_EVENT.Readonly, readonly);
193
- }
194
- });
195
-
196
- const resizable$ = createVal(resizable);
197
- const draggable$ = createVal(draggable);
198
- const fence$ = createVal(fence);
199
- const fixRatio$ = createVal(fixRatio);
200
140
 
201
- const zIndex$ = createVal(zIndex);
202
- zIndex$.reaction((zIndex, _, skipUpdate) => {
203
- if (!skipUpdate) {
204
- this.events.emit(TELE_BOX_EVENT.ZIndex, zIndex);
205
- }
206
- });
141
+ const valManager = new ValManager();
142
+ this._sideEffect.addDisposer(() => valManager.destroy());
207
143
 
208
- const focus$ = createVal(focus);
209
- focus$.reaction((focus, _, skipUpdate) => {
210
- if (!skipUpdate) {
211
- this.events.emit(
212
- focus ? TELE_BOX_EVENT.Focus : TELE_BOX_EVENT.Blur
213
- );
214
- }
215
- });
216
-
217
- const minimized$ = createVal(minimized);
218
- minimized$.reaction((minimized, _, skipUpdate) => {
219
- if (!skipUpdate) {
220
- this.events.emit(TELE_BOX_EVENT.Minimized, minimized);
221
- }
222
- });
223
-
224
- const maximized$ = createVal(maximized);
225
- maximized$.reaction((maximized, _, skipUpdate) => {
226
- if (!skipUpdate) {
227
- this.events.emit(TELE_BOX_EVENT.Maximized, maximized);
228
- }
229
- });
144
+ const title$ = new Val(title);
145
+ const visible$ = new Val(visible);
146
+ const resizable$ = new Val(resizable);
147
+ const draggable$ = new Val(draggable);
148
+ const ratio$ = new Val(ratio);
149
+ const zIndex$ = new Val(zIndex);
150
+ const focus$ = new Val(focus);
151
+ const $userContent$ = new Val(content);
152
+ const $userFooter$ = new Val(footer);
153
+ const $userStyles$ = new Val(styles);
230
154
 
231
155
  const state$ = combine(
232
156
  [minimized$, maximized$],
@@ -237,232 +161,222 @@ export class TeleBox {
237
161
  ? TELE_BOX_STATE.Maximized
238
162
  : TELE_BOX_STATE.Normal
239
163
  );
240
- state$.reaction((state, _, skipUpdate) => {
241
- if (!skipUpdate) {
242
- this.events.emit(TELE_BOX_EVENT.State, state);
243
- }
244
- });
245
164
 
246
- const minSize$ = createVal(
165
+ const minSize$ = new Val(
247
166
  {
248
167
  width: clamp(minWidth, 0, 1),
249
168
  height: clamp(minHeight, 0, 1),
250
169
  },
251
- shallowequal
170
+ { compare: shallowequal }
252
171
  );
253
172
 
254
- const intrinsicSize$ = createVal(
255
- {
256
- width: clamp(width, minSize$.value.width, 1),
257
- height: clamp(height, minSize$.value.height, 1),
258
- },
259
- shallowequal
173
+ const pxMinSize$ = combine(
174
+ [minSize$, managerStageRect$],
175
+ ([minSize, managerStageRect]) => ({
176
+ width: minSize.width * managerStageRect.width,
177
+ height: minSize.height * managerStageRect.height,
178
+ }),
179
+ { compare: shallowequal }
260
180
  );
261
- minSize$.reaction((minSize, _, skipUpdate) => {
262
- intrinsicSize$.setValue(
263
- {
264
- width: clamp(width, minSize.width, 1),
265
- height: clamp(height, minSize.height, 1),
266
- },
267
- skipUpdate
268
- );
269
- });
270
- intrinsicSize$.reaction((size, _, skipUpdate) => {
271
- if (!skipUpdate) {
272
- this.events.emit(TELE_BOX_EVENT.IntrinsicResize, size);
273
- }
274
- });
275
181
 
276
- const size$ = combine(
277
- [intrinsicSize$, maximized$],
278
- ([intrinsicSize, maximized]) => {
279
- if (maximized) {
280
- return { width: 1, height: 1 };
281
- }
282
- return intrinsicSize;
283
- },
284
- shallowequal
182
+ const intrinsicSize$ = new Val(
183
+ { width, height },
184
+ { compare: shallowequal }
285
185
  );
286
- size$.reaction((size, _, skipUpdate) => {
287
- if (!skipUpdate) {
288
- this.events.emit(TELE_BOX_EVENT.Resize, size);
289
- }
290
- });
291
186
 
292
- const visualSize$ = combine(
293
- [size$, minimized$, containerRect$, collectorRect$],
294
- ([size, minimized, containerRect, collectorRect]) => {
295
- if (minimized && collectorRect) {
296
- return {
297
- width:
298
- collectorRect.width /
299
- size.width /
300
- containerRect.width,
301
- height:
302
- collectorRect.height /
303
- size.height /
304
- containerRect.height,
305
- };
306
- }
307
- return size;
308
- },
309
- shallowequal
187
+ this._sideEffect.addDisposer(
188
+ // check intrinsicSize overflow
189
+ minSize$.reaction((minSize, skipUpdate) => {
190
+ intrinsicSize$.setValue(
191
+ {
192
+ width: Math.max(width, minSize.width),
193
+ height: Math.max(height, minSize.height),
194
+ },
195
+ skipUpdate
196
+ );
197
+ })
310
198
  );
311
- visualSize$.reaction((size, _, skipUpdate) => {
312
- if (!skipUpdate) {
313
- this.events.emit(TELE_BOX_EVENT.VisualResize, size);
314
- }
315
- });
316
199
 
317
- const intrinsicCoord$ = createVal(
318
- { x: clamp(x, 0, 1), y: clamp(y, 0, 1) },
319
- shallowequal
200
+ const intrinsicCoord$ = new Val({ x, y }, { compare: shallowequal });
201
+
202
+ const pxIntrinsicSize$ = combine(
203
+ [intrinsicSize$, managerStageRect$],
204
+ ([size, managerStageRect]) => ({
205
+ width: managerStageRect.width * size.width,
206
+ height: managerStageRect.height * size.height,
207
+ }),
208
+ { compare: shallowequal }
320
209
  );
321
- intrinsicCoord$.reaction((coord, _, skipUpdate) => {
322
- if (!skipUpdate) {
323
- this.events.emit(TELE_BOX_EVENT.IntrinsicMove, coord);
324
- }
325
- });
326
210
 
327
- const coord$ = combine(
328
- [
329
- intrinsicCoord$,
330
- intrinsicSize$,
331
- containerRect$,
332
- collectorRect$,
333
- minimized$,
334
- maximized$,
335
- ],
336
- ([
337
- intrinsicCoord,
338
- intrinsicSize,
339
- containerRect,
340
- collectorRect,
341
- minimized,
342
- maximized,
343
- ]) => {
344
- if (minimized && collectorRect) {
345
- if (maximized) {
346
- return {
347
- x:
348
- (collectorRect.x + collectorRect.width / 2) /
349
- containerRect.width -
350
- 1 / 2,
351
- y:
352
- (collectorRect.y + collectorRect.height / 2) /
353
- containerRect.height -
354
- 1 / 2,
355
- };
356
- }
357
- return {
358
- x:
359
- (collectorRect.x + collectorRect.width / 2) /
360
- containerRect.width -
361
- intrinsicSize.width / 2,
362
- y:
363
- (collectorRect.y + collectorRect.height / 2) /
364
- containerRect.height -
365
- intrinsicSize.height / 2,
366
- };
367
- }
368
- if (maximized) {
369
- return { x: 0, y: 0 };
370
- }
371
- return intrinsicCoord;
372
- },
373
- shallowequal
211
+ const pxIntrinsicCoord$ = combine(
212
+ [intrinsicCoord$, managerStageRect$],
213
+ ([intrinsicCoord, managerStageRect]) => ({
214
+ x:
215
+ intrinsicCoord.x * managerStageRect.width +
216
+ managerStageRect.x,
217
+ y:
218
+ intrinsicCoord.y * managerStageRect.height +
219
+ managerStageRect.y,
220
+ }),
221
+ { compare: shallowequal }
374
222
  );
375
- coord$.reaction((coord, _, skipUpdate) => {
376
- if (!skipUpdate) {
377
- this.events.emit(TELE_BOX_EVENT.Move, coord);
378
- }
379
- });
380
223
 
381
- this.titleBar =
382
- titleBar ||
383
- new DefaultTitleBar({
384
- readonly: readonly$.value,
385
- title: title$.value,
386
- namespace: this.namespace,
387
- onDragStart: (event) => this._handleTrackStart?.(event),
388
- onEvent: (event): void => {
389
- if (this._delegateEvents.listeners.length > 0) {
390
- this._delegateEvents.emit(event.type);
391
- } else {
392
- switch (event.type) {
393
- case TELE_BOX_DELEGATE_EVENT.Maximize: {
394
- maximized$.setValue(!maximized$.value);
395
- break;
396
- }
397
- case TELE_BOX_DELEGATE_EVENT.Minimize: {
398
- minimized$.setValue(true);
399
- break;
400
- }
401
- case TELE_BOX_DELEGATE_EVENT.Close: {
402
- visible$.setValue(false);
403
- break;
404
- }
405
- default: {
406
- console.error(
407
- "Unsupported titleBar event:",
408
- event
409
- );
410
- break;
411
- }
412
- }
413
- }
414
- },
415
- });
416
- readonly$.reaction((readonly) => {
417
- this.titleBar.setReadonly(readonly);
224
+ const boxHighlightStage$ = new Val<boolean | null, boolean>(
225
+ highlightStage
226
+ );
227
+
228
+ const highlightStage$ = combine(
229
+ [maximized$, boxHighlightStage$, managerHighlightStage$],
230
+ ([maximized, boxHighlightStage, managerHighlightStage]) =>
231
+ boxHighlightStage === null
232
+ ? managerHighlightStage && maximized
233
+ : boxHighlightStage
234
+ );
235
+
236
+ const contentRoot$ = new Val<HTMLElement | null>(null);
237
+
238
+ const contentRect$ = new Val<TeleBoxRect>(rootRect$.value, {
239
+ compare: shallowequal,
418
240
  });
419
241
 
420
- const $userContent$ = createVal(content);
421
- const $userFooter$ = createVal(footer);
422
- const $userStyles$ = createVal(styles);
242
+ const teleStage = new TeleStage({
243
+ namespace,
244
+ root$: contentRoot$,
245
+ rootRect$: contentRect$,
246
+ ratio$: stageRatio$,
247
+ highlightStage$,
248
+ });
249
+ this._sideEffect.addDisposer(() => teleStage.destroy());
423
250
 
424
- const valConfig: ValConfig = {
425
- prefersColorScheme: prefersColorScheme$,
251
+ const propsValConfig: PropsValConfig = {
426
252
  darkMode: darkMode$,
427
- containerRect: containerRect$,
428
- collectorRect: collectorRect$,
429
- title: title$,
430
- visible: visible$,
431
- readonly: readonly$,
432
- resizable: resizable$,
433
- draggable: draggable$,
434
253
  fence: fence$,
435
- fixRatio: fixRatio$,
436
- focus: focus$,
437
- zIndex: zIndex$,
438
254
  minimized: minimized$,
439
255
  maximized: maximized$,
256
+ readonly: readonly$,
257
+ rootRect: rootRect$,
258
+ managerStageRect: managerStageRect$,
259
+ collectorRect: collectorRect$,
260
+ };
261
+
262
+ withReadonlyValueEnhancer(this, propsValConfig);
263
+
264
+ const myReadonlyValConfig: MyReadonlyValConfig = {
265
+ zIndex: zIndex$,
266
+ focus: focus$,
267
+
440
268
  $userContent: $userContent$,
441
269
  $userFooter: $userFooter$,
442
270
  $userStyles: $userStyles$,
271
+
272
+ state: state$,
273
+ minSize: minSize$,
274
+ pxMinSize: pxMinSize$,
275
+ intrinsicSize: intrinsicSize$,
276
+ intrinsicCoord: intrinsicCoord$,
277
+ pxIntrinsicSize: pxIntrinsicSize$,
278
+ pxIntrinsicCoord: pxIntrinsicCoord$,
279
+ highlightStage: highlightStage$,
280
+ boxHighlightStage: boxHighlightStage$,
281
+ contentRect: contentRect$,
282
+ contentStageRect: teleStage.stageRect$,
443
283
  };
444
284
 
445
- withValueEnhancer(this, valConfig);
446
-
447
- this._state$ = state$;
448
- this._minSize$ = minSize$;
449
- this._size$ = size$;
450
- this._intrinsicSize$ = intrinsicSize$;
451
- this._visualSize$ = visualSize$;
452
- this._coord$ = coord$;
453
- this._intrinsicCoord$ = intrinsicCoord$;
454
-
455
- if (this.fixRatio) {
456
- this.transform(
457
- coord$.value.x,
458
- coord$.value.y,
459
- size$.value.width,
460
- size$.value.height,
461
- true
462
- );
463
- }
285
+ withReadonlyValueEnhancer(this, myReadonlyValConfig, valManager);
286
+
287
+ const valConfig: ValConfig = {
288
+ title: title$,
289
+ visible: visible$,
290
+ resizable: resizable$,
291
+ draggable: draggable$,
292
+ ratio: ratio$,
293
+ };
294
+
295
+ withValueEnhancer(this, valConfig, valManager);
296
+
297
+ this.titleBar =
298
+ titleBar ||
299
+ new DefaultTitleBar({
300
+ readonly$: readonly$,
301
+ state$: state$,
302
+ title$: title$,
303
+ namespace: this.namespace,
304
+ onDragStart: (event) => this._handleTrackStart?.(event),
305
+ onEvent: (event) => this._delegateEvents.emit(event.type),
306
+ });
307
+
308
+ this._sideEffect.addDisposer(
309
+ ratio$.subscribe((ratio) => {
310
+ if (ratio > 0) {
311
+ this.transform(
312
+ pxIntrinsicCoord$.value.x,
313
+ pxIntrinsicCoord$.value.y,
314
+ pxIntrinsicSize$.value.width,
315
+ pxIntrinsicSize$.value.height,
316
+ true
317
+ );
318
+ }
319
+ })
320
+ );
321
+
322
+ this._sideEffect.addDisposer(
323
+ fence$.subscribe((fence) => {
324
+ if (fence) {
325
+ this.move(
326
+ pxIntrinsicCoord$.value.x,
327
+ pxIntrinsicCoord$.value.y,
328
+ true
329
+ );
330
+ }
331
+ })
332
+ );
464
333
 
465
334
  this.$box = this.render();
335
+ contentRoot$.setValue(this.$content.parentElement);
336
+
337
+ const watchValEvent = <E extends TeleBoxEvent>(
338
+ val: ReadonlyVal<TeleBoxEventConfig[E], boolean>,
339
+ event: E
340
+ ) => {
341
+ this._sideEffect.addDisposer(
342
+ val.reaction((v, skipUpdate) => {
343
+ if (!skipUpdate) {
344
+ this.events.emit<any>(event, v);
345
+ }
346
+ })
347
+ );
348
+ };
349
+
350
+ watchValEvent(darkMode$, TELE_BOX_EVENT.DarkMode);
351
+ watchValEvent(readonly$, TELE_BOX_EVENT.Readonly);
352
+ watchValEvent(zIndex$, TELE_BOX_EVENT.ZIndex);
353
+ watchValEvent(minimized$, TELE_BOX_EVENT.Minimized);
354
+ watchValEvent(maximized$, TELE_BOX_EVENT.Maximized);
355
+ watchValEvent(state$, TELE_BOX_EVENT.State);
356
+ watchValEvent(intrinsicSize$, TELE_BOX_EVENT.IntrinsicResize);
357
+ watchValEvent(intrinsicCoord$, TELE_BOX_EVENT.IntrinsicMove);
358
+
359
+ this._sideEffect.addDisposer([
360
+ visible$.reaction((visible, skipUpdate) => {
361
+ if (!skipUpdate && !visible) {
362
+ this.events.emit(TELE_BOX_EVENT.Close);
363
+ }
364
+ }),
365
+ focus$.reaction((focus, skipUpdate) => {
366
+ if (!skipUpdate) {
367
+ this.events.emit(
368
+ focus ? TELE_BOX_EVENT.Focus : TELE_BOX_EVENT.Blur
369
+ );
370
+ }
371
+ }),
372
+ root$.subscribe((root) => {
373
+ if (root) {
374
+ root.appendChild(this.$box);
375
+ } else if (this.$box.parentNode) {
376
+ this.$box.remove();
377
+ }
378
+ }),
379
+ ]);
466
380
  }
467
381
 
468
382
  public readonly id: string;
@@ -470,97 +384,50 @@ export class TeleBox {
470
384
  /** ClassName Prefix. For CSS styling. Default "telebox" */
471
385
  public readonly namespace: string;
472
386
 
473
- public readonly events: TeleBoxEvents;
387
+ public readonly events = new Emittery<
388
+ TeleBoxEventConfig,
389
+ TeleBoxEventConfig
390
+ >();
474
391
 
475
- public readonly _delegateEvents: TeleBoxDelegateEvents;
392
+ public readonly _delegateEvents = new Emittery<
393
+ TeleBoxDelegateEventConfig,
394
+ TeleBoxDelegateEventConfig
395
+ >();
476
396
 
477
397
  protected _sideEffect: SideEffectManager;
478
398
 
479
- protected _valSideEffectBinder: ValSideEffectBinder;
480
-
481
399
  public titleBar: TeleTitleBar;
482
400
 
483
- public _minSize$: Val<TeleBoxSize, boolean>;
484
- public _size$: Val<TeleBoxSize, boolean>;
485
- public _intrinsicSize$: Val<TeleBoxSize, boolean>;
486
- public _visualSize$: Val<TeleBoxSize, boolean>;
487
- public _coord$: Val<TeleBoxCoord, boolean>;
488
- public _intrinsicCoord$: Val<TeleBoxCoord, boolean>;
489
-
490
- public get darkMode(): boolean {
491
- return this._darkMode$.value;
492
- }
493
-
494
- public _state$: Val<TeleBoxState, boolean>;
495
-
496
- public get state(): TeleBoxState {
497
- return this._state$.value;
498
- }
499
-
500
- /** @deprecated use setMaximized and setMinimized instead */
501
- public setState(state: TeleBoxState, skipUpdate = false): this {
502
- switch (state) {
503
- case TELE_BOX_STATE.Maximized: {
504
- this.setMinimized(false, skipUpdate);
505
- this.setMaximized(true, skipUpdate);
506
- break;
507
- }
508
- case TELE_BOX_STATE.Minimized: {
509
- this.setMinimized(true, skipUpdate);
510
- this.setMaximized(false, skipUpdate);
511
- break;
512
- }
513
- default: {
514
- this.setMinimized(false, skipUpdate);
515
- this.setMaximized(false, skipUpdate);
516
- break;
517
- }
518
- }
519
- return this;
520
- }
521
-
522
- /** Minimum box width relative to container element. 0~1. Default 0. */
401
+ /** Minimum box width relative to stage area. 0~1. Default 0. */
523
402
  public get minWidth(): number {
524
403
  return this._minSize$.value.width;
525
404
  }
526
405
 
527
- /** Minimum box height relative to container element. 0~1. Default 0. */
406
+ /** Minimum box height relative to stage area. 0~1. Default 0. */
528
407
  public get minHeight(): number {
529
408
  return this._minSize$.value.height;
530
409
  }
531
410
 
532
411
  /**
533
- * @param minWidth Minimum box width relative to container element. 0~1.
412
+ * @param minWidth Minimum box width relative to stage area. 0~1.
534
413
  * @returns this
535
414
  */
536
- public setMinWidth(minWidth: number, skipUpdate = false): this {
415
+ public setMinWidth(minWidth: number, skipUpdate = false): void {
537
416
  this._minSize$.setValue(
538
417
  { width: minWidth, height: this.minHeight },
539
418
  skipUpdate
540
419
  );
541
- return this;
542
420
  }
543
421
 
544
422
  /**
545
423
  * @param minHeight Minimum box height relative to container element. 0~1.
546
424
  * @returns this
547
425
  */
548
- public setMinHeight(minHeight: number, skipUpdate = false): this {
426
+ public setMinHeight(minHeight: number, skipUpdate = false): void {
549
427
  this._minSize$.setValue(
550
428
  { width: this.minWidth, height: minHeight },
551
429
  skipUpdate
552
430
  );
553
- return this;
554
- }
555
-
556
- /** Intrinsic box width relative to container element(without counting the effect of maximization or minimization). 0~1. Default 0.5. */
557
- public get intrinsicWidth(): number {
558
- return this._intrinsicSize$.value.width;
559
- }
560
-
561
- /** Intrinsic box height relative to container element(without counting the effect of maximization or minimization). 0~1. Default 0.5. */
562
- public get intrinsicHeight(): number {
563
- return this._intrinsicSize$.value.height;
564
431
  }
565
432
 
566
433
  /**
@@ -570,39 +437,14 @@ export class TeleBox {
570
437
  * @param skipUpdate Skip emitting event.
571
438
  * @returns this
572
439
  */
573
- public resize(width: number, height: number, skipUpdate = false): this {
574
- this._intrinsicSize$.setValue({ width, height }, skipUpdate);
575
- return this;
576
- }
577
-
578
- /** Box width relative to container element. 0~1. Default 0.5. */
579
- public get width(): number {
580
- return this._size$.value.width;
581
- }
582
-
583
- /** Box height relative to container element. 0~1. Default 0.5. */
584
- public get height(): number {
585
- return this._size$.value.height;
586
- }
587
-
588
- /** Box width in pixels. */
589
- public get absoluteWidth(): number {
590
- return this.width * this.containerRect.width;
591
- }
592
-
593
- /** Box height in pixels. */
594
- public get absoluteHeight(): number {
595
- return this.height * this.containerRect.height;
596
- }
597
-
598
- /** Actual rendered box width relative to container element. 0~1. Default 0.5. */
599
- public get visualWidth(): number {
600
- return this._visualSize$.value.width;
601
- }
602
-
603
- /** Actual rendered box height relative to container element. 0~1. Default 0.5. */
604
- public get visualHeight(): number {
605
- return this._visualSize$.value.height;
440
+ public resize(width: number, height: number, skipUpdate = false): void {
441
+ this._intrinsicSize$.setValue(
442
+ {
443
+ width: Math.max(width, this.minWidth),
444
+ height: Math.max(height, this.minHeight),
445
+ },
446
+ skipUpdate
447
+ );
606
448
  }
607
449
 
608
450
  /** Intrinsic box x position relative to container element(without counting the effect of maximization or minimization). 0~1. Default 0.1. */
@@ -615,133 +457,141 @@ export class TeleBox {
615
457
  return this._intrinsicCoord$.value.y;
616
458
  }
617
459
 
460
+ /** Intrinsic box width relative to container element(without counting the effect of maximization or minimization). 0~1. Default 0.1. */
461
+ public get intrinsicWidth(): number {
462
+ return this._intrinsicSize$.value.width;
463
+ }
464
+
465
+ /** Intrinsic box height relative to container element(without counting the effect of maximization or minimization). 0~1. Default 0.1. */
466
+ public get intrinsicHeight(): number {
467
+ return this._intrinsicSize$.value.height;
468
+ }
469
+
618
470
  /**
619
471
  * Move box position.
620
- * @param x x position relative to container element. 0~1.
621
- * @param y y position relative to container element. 0~1.
472
+ * @param x x position in px.
473
+ * @param y y position in px.
622
474
  * @param skipUpdate Skip emitting event.
623
475
  * @returns this
624
476
  */
625
- public move(x: number, y: number, skipUpdate = false): this {
626
- this._intrinsicCoord$.setValue({ x, y }, skipUpdate);
627
- return this;
628
- }
629
-
630
- /** Box x position relative to container element. 0~1. Default 0.1. */
631
- public get x(): number {
632
- return this._coord$.value.x;
633
- }
477
+ protected move(x: number, y: number, skipUpdate = false): void {
478
+ let safeX: number;
479
+ let safeY: number;
480
+ const managerStageRect = this.managerStageRect;
481
+ const pxIntrinsicSize = this.pxIntrinsicSize;
482
+
483
+ if (this.fence) {
484
+ safeX = clamp(
485
+ x,
486
+ managerStageRect.x,
487
+ managerStageRect.x +
488
+ managerStageRect.width -
489
+ pxIntrinsicSize.width
490
+ );
491
+ safeY = clamp(
492
+ y,
493
+ managerStageRect.y,
494
+ managerStageRect.y +
495
+ managerStageRect.height -
496
+ pxIntrinsicSize.height
497
+ );
498
+ } else {
499
+ const rootRect = this.rootRect;
500
+ safeX = clamp(
501
+ x,
502
+ 0 - pxIntrinsicSize.width + 20,
503
+ 0 + rootRect.width - 20
504
+ );
505
+ safeY = clamp(y, 0, 0 + rootRect.height - 20);
506
+ }
634
507
 
635
- /** Box y position relative to container element. 0~1. Default 0.1. */
636
- public get y(): number {
637
- return this._coord$.value.y;
508
+ this._intrinsicCoord$.setValue(
509
+ {
510
+ x: (safeX - managerStageRect.x) / managerStageRect.width,
511
+ y: (safeY - managerStageRect.y) / managerStageRect.height,
512
+ },
513
+ skipUpdate
514
+ );
638
515
  }
639
516
 
640
517
  /**
641
518
  * Resize + Move, with respect to fixed ratio.
642
- * @param x x position relative to container element. 0~1.
643
- * @param y y position relative to container element. 0~1.
644
- * @param width Box width relative to container element. 0~1.
645
- * @param height Box height relative to container element. 0~1.
519
+ * @param x x position in px.
520
+ * @param y y position in px.
521
+ * @param width Box width in px.
522
+ * @param height Box height in px.
646
523
  * @param skipUpdate Skip emitting event.
647
524
  * @returns this
648
525
  */
649
- public transform(
526
+ protected transform(
650
527
  x: number,
651
528
  y: number,
652
529
  width: number,
653
530
  height: number,
654
531
  skipUpdate = false
655
- ): this {
656
- if (this.fixRatio) {
657
- const newHeight =
658
- (this.intrinsicHeight / this.intrinsicWidth) * width;
659
- if (y !== this.intrinsicY) {
532
+ ): void {
533
+ const managerStageRect = this.managerStageRect;
534
+ const rootRect = this.rootRect;
535
+
536
+ width = Math.max(width, this.pxMinSize.width);
537
+ height = Math.max(height, this.pxMinSize.height);
538
+
539
+ if (this.ratio > 0) {
540
+ const newHeight = this.ratio * width;
541
+ if (y !== this.pxIntrinsicCoord.y) {
660
542
  y -= newHeight - height;
661
543
  }
662
544
  height = newHeight;
663
545
  }
664
546
 
665
- if (y < 0) {
666
- y = 0;
667
- if (height > this.intrinsicHeight) {
668
- height = this.intrinsicHeight;
669
- }
547
+ if (y < rootRect.y) {
548
+ y = rootRect.y;
549
+ height = this.pxIntrinsicSize.height;
670
550
  }
671
551
 
672
- this._intrinsicCoord$.setValue(
673
- {
674
- x: width >= this.minWidth ? x : this.intrinsicX,
675
- y: height >= this.minHeight ? y : this.intrinsicY,
676
- },
677
- skipUpdate
678
- );
552
+ this.move(x, y, skipUpdate);
679
553
  this._intrinsicSize$.setValue(
680
554
  {
681
- width: clamp(width, this.minWidth, 1),
682
- height: clamp(height, this.minHeight, 1),
555
+ width: width / managerStageRect.width,
556
+ height: height / managerStageRect.height,
683
557
  },
684
558
  skipUpdate
685
559
  );
686
-
687
- return this;
688
- }
689
-
690
- /**
691
- * Mount box to a container element.
692
- */
693
- public mount(container: HTMLElement): this {
694
- container.appendChild(this.render());
695
- return this;
696
- }
697
-
698
- /**
699
- * Unmount box from the container element.
700
- */
701
- public unmount(): this {
702
- if (this.$box) {
703
- this.$box.remove();
704
- }
705
- return this;
706
560
  }
707
561
 
708
562
  /**
709
563
  * Mount dom to box content.
710
564
  */
711
- public mountContent(content: HTMLElement): this {
712
- this.set$userContent(content);
713
- return this;
565
+ public mountContent(content: HTMLElement): void {
566
+ this._$userContent$.setValue(content);
714
567
  }
715
568
 
716
569
  /**
717
570
  * Unmount content from the box.
718
571
  */
719
- public unmountContent(): this {
720
- this.set$userContent(undefined);
721
- return this;
572
+ public unmountContent(): void {
573
+ this._$userContent$.setValue(undefined);
722
574
  }
723
575
 
724
576
  /**
725
577
  * Mount dom to box Footer.
726
578
  */
727
- public mountFooter(footer: HTMLElement): this {
728
- this.set$userFooter(footer);
729
- return this;
579
+ public mountFooter(footer: HTMLElement): void {
580
+ this._$userFooter$.setValue(footer);
730
581
  }
731
582
 
732
583
  /**
733
584
  * Unmount Footer from the box.
734
585
  */
735
- public unmountFooter(): this {
736
- this.set$userFooter(undefined);
737
- return this;
586
+ public unmountFooter(): void {
587
+ this._$userFooter$.setValue(undefined);
738
588
  }
739
589
 
740
590
  public getUserStyles(): HTMLStyleElement | undefined {
741
591
  return this.$userStyles;
742
592
  }
743
593
 
744
- public mountStyles(styles: string | HTMLStyleElement): this {
594
+ public mountStyles(styles: string | HTMLStyleElement): void {
745
595
  let $styles: HTMLStyleElement;
746
596
  if (typeof styles === "string") {
747
597
  $styles = document.createElement("style");
@@ -749,13 +599,16 @@ export class TeleBox {
749
599
  } else {
750
600
  $styles = styles;
751
601
  }
752
- this.set$userStyles($styles);
753
- return this;
602
+ this._$userStyles$.setValue($styles);
603
+ }
604
+
605
+ public unmountStyles(): void {
606
+ this._$userStyles$.setValue(undefined);
754
607
  }
755
608
 
756
- public unmountStyles(): this {
757
- this.set$userStyles(undefined);
758
- return this;
609
+ /** Show stage frame and grey-out the non-stage area. Inherit setting from manager if null. */
610
+ setHighlightStage(highlightStage: boolean | null): void {
611
+ this._boxHighlightStage$.setValue(highlightStage);
759
612
  }
760
613
 
761
614
  /** DOM of the box */
@@ -770,34 +623,22 @@ export class TeleBox {
770
623
  /** DOM of the box footer */
771
624
  public $footer!: HTMLElement;
772
625
 
773
- protected _renderSideEffect = new SideEffectManager();
774
-
775
- public render(root?: HTMLElement): HTMLElement {
776
- if (root) {
777
- if (root === this.$box) {
778
- return this.$box;
779
- } else {
780
- this.$box = root;
781
- }
782
- } else {
783
- if (this.$box) {
784
- return this.$box;
785
- } else {
786
- this.$box = document.createElement("div");
787
- }
626
+ protected render(): HTMLElement {
627
+ if (this.$box) {
628
+ return this.$box;
788
629
  }
789
630
 
790
- this._renderSideEffect.flushAll();
631
+ this.$box = document.createElement("div");
791
632
 
792
633
  this.$box.classList.add(this.wrapClassName("box"));
793
634
 
794
635
  const bindClassName = <TValue>(
795
636
  el: Element,
796
- val: Val<TValue, boolean>,
637
+ val: ReadonlyVal<TValue, boolean>,
797
638
  className: string,
798
639
  predicate: (value: TValue) => boolean = isTruthy
799
640
  ): string => {
800
- return this._renderSideEffect.add(() => {
641
+ return this._sideEffect.add(() => {
801
642
  const wrappedClassName = this.wrapClassName(className);
802
643
  return val.subscribe((value) => {
803
644
  el.classList.toggle(wrappedClassName, predicate(value));
@@ -817,7 +658,7 @@ export class TeleBox {
817
658
  isFalsy
818
659
  );
819
660
 
820
- this._renderSideEffect.add(() => {
661
+ this._sideEffect.add(() => {
821
662
  const minimizedClassName = this.wrapClassName("minimized");
822
663
  const maximizedClassName = this.wrapClassName("maximized");
823
664
  const MAXIMIZED_TIMER_ID = "box-maximized-timer";
@@ -829,11 +670,11 @@ export class TeleBox {
829
670
  );
830
671
 
831
672
  if (state === TELE_BOX_STATE.Maximized) {
832
- this._renderSideEffect.flush(MAXIMIZED_TIMER_ID);
673
+ this._sideEffect.flush(MAXIMIZED_TIMER_ID);
833
674
  this.$box.classList.toggle(maximizedClassName, true);
834
675
  } else {
835
676
  // delay so that transition won't be triggered
836
- this._renderSideEffect.setTimeout(
677
+ this._sideEffect.setTimeout(
837
678
  () => {
838
679
  this.$box.classList.toggle(
839
680
  maximizedClassName,
@@ -847,68 +688,88 @@ export class TeleBox {
847
688
  });
848
689
  });
849
690
 
850
- this._renderSideEffect.add(() =>
691
+ this._sideEffect.addDisposer(
851
692
  this._visible$.subscribe((visible) => {
852
693
  this.$box.style.display = visible ? "block" : "none";
853
694
  })
854
695
  );
855
696
 
856
- this._renderSideEffect.add(() =>
697
+ this._sideEffect.addDisposer(
857
698
  this._zIndex$.subscribe((zIndex) => {
858
699
  this.$box.style.zIndex = String(zIndex);
859
700
  })
860
701
  );
861
702
 
703
+ this.$box.dataset.teleBoxID = this.id;
704
+
862
705
  const boxStyler = styler(this.$box);
863
706
 
864
- this.$box.dataset.teleBoxID = this.id;
707
+ const boxStyles$ = combine(
708
+ [
709
+ this._maximized$,
710
+ this._minimized$,
711
+ this._pxIntrinsicSize$,
712
+ this._pxIntrinsicCoord$,
713
+ this._collectorRect$,
714
+ ],
715
+ ([
716
+ maximized,
717
+ minimized,
718
+ pxIntrinsicSize,
719
+ pxIntrinsicCoord,
720
+ collectorRect,
721
+ ]) => {
722
+ const styles = maximized
723
+ ? {
724
+ x: 0,
725
+ y: 0,
726
+ width: "100%",
727
+ height: "100%",
728
+ scaleX: 1,
729
+ scaleY: 1,
730
+ }
731
+ : {
732
+ x: pxIntrinsicCoord.x,
733
+ y: pxIntrinsicCoord.y,
734
+ width: pxIntrinsicSize.width + "px",
735
+ height: pxIntrinsicSize.height + "px",
736
+ scaleX: 1,
737
+ scaleY: 1,
738
+ };
739
+ if (minimized && collectorRect) {
740
+ const { width: boxWidth, height: boxHeight } = maximized
741
+ ? this.rootRect
742
+ : pxIntrinsicSize;
743
+ styles.x =
744
+ collectorRect.x -
745
+ boxWidth / 2 +
746
+ collectorRect.width / 2;
747
+ styles.y =
748
+ collectorRect.y -
749
+ boxHeight / 2 +
750
+ collectorRect.height / 2;
751
+ styles.scaleX = collectorRect.width / boxWidth;
752
+ styles.scaleY = collectorRect.height / boxHeight;
753
+ }
754
+ return styles;
755
+ },
756
+ { compare: shallowequal }
757
+ );
865
758
 
866
- this.$box.style.width = this.absoluteWidth + "px";
867
- this.$box.style.height = this.absoluteHeight + "px";
759
+ const boxStyles = boxStyles$.value;
760
+ this.$box.style.width = boxStyles.width;
761
+ this.$box.style.height = boxStyles.height;
868
762
  // Add 10px offset on first frame
869
763
  // which creates a subtle moving effect
870
- const translateX =
871
- this.x * this.containerRect.width + this.containerRect.x;
872
- const translateY =
873
- this.y * this.containerRect.height + this.containerRect.y;
874
- this.$box.style.transform = `translate(${translateX - 10}px,${
875
- translateY - 10
764
+ this.$box.style.transform = `translate(${boxStyles.x - 10}px,${
765
+ boxStyles.y - 10
876
766
  }px)`;
877
767
 
878
- this._valSideEffectBinder
879
- .combine(
880
- [
881
- this._coord$,
882
- this._size$,
883
- this._minimized$,
884
- this._containerRect$,
885
- this._collectorRect$,
886
- ],
887
- ([coord, size, minimized, containerRect, collectorRect]) => {
888
- const absoluteWidth = size.width * containerRect.width;
889
- const absoluteHeight = size.height * containerRect.height;
890
- return {
891
- width: absoluteWidth,
892
- height: absoluteHeight,
893
- x: coord.x * containerRect.width,
894
- y: coord.y * containerRect.height,
895
- scaleX:
896
- minimized && collectorRect
897
- ? collectorRect.width / absoluteWidth
898
- : 1,
899
- scaleY:
900
- minimized && collectorRect
901
- ? collectorRect.height / absoluteHeight
902
- : 1,
903
- };
904
- },
905
- shallowequal
906
- )
907
- .subscribe((styles) => {
768
+ this._sideEffect.addDisposer(
769
+ boxStyles$.subscribe((styles) => {
908
770
  boxStyler.set(styles);
909
- });
910
-
911
- boxStyler.set({ x: translateX, y: translateY });
771
+ })
772
+ );
912
773
 
913
774
  const $boxMain = document.createElement("div");
914
775
  $boxMain.className = this.wrapClassName("box-main");
@@ -927,7 +788,21 @@ export class TeleBox {
927
788
  this.wrapClassName("content") + " tele-fancy-scrollbar";
928
789
  this.$content = $content;
929
790
 
930
- this._renderSideEffect.add(() => {
791
+ this._sideEffect.add(() => {
792
+ const observer = new ResizeObserver(() => {
793
+ const rect = $content.getBoundingClientRect();
794
+ this._contentRect$.setValue({
795
+ x: rect.x,
796
+ y: rect.y,
797
+ width: rect.width,
798
+ height: rect.height,
799
+ });
800
+ });
801
+ observer.observe($content);
802
+ return () => observer.disconnect();
803
+ });
804
+
805
+ this._sideEffect.add(() => {
931
806
  let last$userStyles: HTMLStyleElement | undefined;
932
807
  return this._$userStyles$.subscribe(($userStyles) => {
933
808
  if (last$userStyles) {
@@ -940,7 +815,7 @@ export class TeleBox {
940
815
  });
941
816
  });
942
817
 
943
- this._renderSideEffect.add(() => {
818
+ this._sideEffect.add(() => {
944
819
  let last$userContent: HTMLElement | undefined;
945
820
  return this._$userContent$.subscribe(($userContent) => {
946
821
  if (last$userContent) {
@@ -959,7 +834,7 @@ export class TeleBox {
959
834
  $footer.className = this.wrapClassName("footer-wrap");
960
835
  this.$footer = $footer;
961
836
 
962
- this._renderSideEffect.add(() => {
837
+ this._sideEffect.add(() => {
963
838
  let last$userFooter: HTMLElement | undefined;
964
839
  return this._$userFooter$.subscribe(($userFooter) => {
965
840
  if (last$userFooter) {
@@ -1028,109 +903,67 @@ export class TeleBox {
1028
903
  preventEvent(ev);
1029
904
 
1030
905
  let { pageX, pageY } = flattenEvent(ev);
1031
- if (pageY < 0) {
1032
- pageY = 0;
906
+ if (pageY < this.rootRect.y) {
907
+ pageY = this.rootRect.y;
1033
908
  }
1034
909
 
1035
- const offsetX =
1036
- (pageX - trackStartPageX) / this.containerRect.width;
1037
- const offsetY =
1038
- (pageY - trackStartPageY) / this.containerRect.height;
910
+ const offsetX = pageX - trackStartPageX;
911
+ const offsetY = pageY - trackStartPageY;
912
+
913
+ let { x: newX, y: newY } = this.pxIntrinsicCoord;
914
+ let { width: newWidth, height: newHeight } = this.pxIntrinsicSize;
1039
915
 
1040
916
  switch (trackingHandle) {
1041
917
  case TELE_BOX_RESIZE_HANDLE.North: {
1042
- this.transform(
1043
- this.x,
1044
- trackStartY + offsetY,
1045
- this.width,
1046
- trackStartHeight - offsetY
1047
- );
918
+ newY = trackStartY + offsetY;
919
+ newHeight = trackStartHeight - offsetY;
1048
920
  break;
1049
921
  }
922
+ // eslint-disable-next-line no-fallthrough
1050
923
  case TELE_BOX_RESIZE_HANDLE.South: {
1051
- this.transform(
1052
- this.x,
1053
- this.y,
1054
- this.width,
1055
- trackStartHeight + offsetY
1056
- );
924
+ newHeight = trackStartHeight + offsetY;
1057
925
  break;
1058
926
  }
1059
927
  case TELE_BOX_RESIZE_HANDLE.West: {
1060
- this.transform(
1061
- trackStartX + offsetX,
1062
- this.y,
1063
- trackStartWidth - offsetX,
1064
- this.height
1065
- );
928
+ newX = trackStartX + offsetX;
929
+ newWidth = trackStartWidth - offsetX;
1066
930
  break;
1067
931
  }
1068
932
  case TELE_BOX_RESIZE_HANDLE.East: {
1069
- this.transform(
1070
- this.x,
1071
- this.y,
1072
- trackStartWidth + offsetX,
1073
- this.height
1074
- );
933
+ newWidth = trackStartWidth + offsetX;
1075
934
  break;
1076
935
  }
1077
936
  case TELE_BOX_RESIZE_HANDLE.NorthWest: {
1078
- this.transform(
1079
- trackStartX + offsetX,
1080
- trackStartY + offsetY,
1081
- trackStartWidth - offsetX,
1082
- trackStartHeight - offsetY
1083
- );
937
+ newX = trackStartX + offsetX;
938
+ newY = trackStartY + offsetY;
939
+ newWidth = trackStartWidth - offsetX;
940
+ newHeight = trackStartHeight - offsetY;
1084
941
  break;
1085
942
  }
1086
943
  case TELE_BOX_RESIZE_HANDLE.NorthEast: {
1087
- this.transform(
1088
- this.x,
1089
- trackStartY + offsetY,
1090
- trackStartWidth + offsetX,
1091
- trackStartHeight - offsetY
1092
- );
944
+ newY = trackStartY + offsetY;
945
+ newWidth = trackStartWidth + offsetX;
946
+ newHeight = trackStartHeight - offsetY;
1093
947
  break;
1094
948
  }
1095
949
  case TELE_BOX_RESIZE_HANDLE.SouthEast: {
1096
- this.transform(
1097
- this.x,
1098
- this.y,
1099
- trackStartWidth + offsetX,
1100
- trackStartHeight + offsetY
1101
- );
950
+ newWidth = trackStartWidth + offsetX;
951
+ newHeight = trackStartHeight + offsetY;
1102
952
  break;
1103
953
  }
1104
954
  case TELE_BOX_RESIZE_HANDLE.SouthWest: {
1105
- this.transform(
1106
- trackStartX + offsetX,
1107
- this.y,
1108
- trackStartWidth - offsetX,
1109
- trackStartHeight + offsetY
1110
- );
955
+ newX = trackStartX + offsetX;
956
+ newWidth = trackStartWidth - offsetX;
957
+ newHeight = trackStartHeight + offsetY;
1111
958
  break;
1112
959
  }
1113
960
  default: {
1114
- if (this.fence) {
1115
- this.move(
1116
- clamp(trackStartX + offsetX, 0, 1 - this.width),
1117
- clamp(trackStartY + offsetY, 0, 1 - this.height)
1118
- );
1119
- } else {
1120
- const xOverflowOffset = 20 / this.containerRect.width;
1121
- const yOverflowOffset = 20 / this.containerRect.height;
1122
- this.move(
1123
- clamp(
1124
- trackStartX + offsetX,
1125
- xOverflowOffset - this.width,
1126
- 1 - xOverflowOffset
1127
- ),
1128
- clamp(trackStartY + offsetY, 0, 1 - yOverflowOffset)
1129
- );
1130
- }
1131
- break;
961
+ this.move(trackStartX + offsetX, trackStartY + offsetY);
962
+ return;
1132
963
  }
1133
964
  }
965
+
966
+ this.transform(newX, newY, newWidth, newHeight);
1134
967
  };
1135
968
 
1136
969
  const handleTrackEnd = (ev: MouseEvent | TouchEvent): void => {
@@ -1174,10 +1007,9 @@ export class TeleBox {
1174
1007
  if (target.dataset?.teleBoxHandle) {
1175
1008
  preventEvent(ev);
1176
1009
 
1177
- trackStartX = this.x;
1178
- trackStartY = this.y;
1179
- trackStartWidth = this.width;
1180
- trackStartHeight = this.height;
1010
+ ({ x: trackStartX, y: trackStartY } = this.pxIntrinsicCoord);
1011
+ ({ width: trackStartWidth, height: trackStartHeight } =
1012
+ this.pxIntrinsicSize);
1181
1013
 
1182
1014
  ({ pageX: trackStartPageX, pageY: trackStartPageY } =
1183
1015
  flattenEvent(ev));
@@ -1247,14 +1079,14 @@ export class TeleBox {
1247
1079
  );
1248
1080
  }
1249
1081
 
1250
- public destroy(): void {
1082
+ public async destroy(): Promise<void> {
1251
1083
  this.$box.remove();
1252
- this.events.emit(TELE_BOX_EVENT.Destroyed);
1253
-
1254
1084
  this._sideEffect.flushAll();
1255
- this._renderSideEffect.flushAll();
1256
- this.events.removeAllListeners();
1257
- this._delegateEvents.removeAllListeners();
1085
+ this._sideEffect.flushAll();
1086
+
1087
+ await this.events.emit(TELE_BOX_EVENT.Destroyed);
1088
+ this.events.clearListeners();
1089
+ this._delegateEvents.clearListeners();
1258
1090
  }
1259
1091
 
1260
1092
  /**
@@ -1265,12 +1097,9 @@ export class TeleBox {
1265
1097
  }
1266
1098
  }
1267
1099
 
1268
- function noop(): void {
1269
- return;
1270
- }
1271
-
1272
1100
  type PropKeys<K = keyof TeleBox> = K extends keyof TeleBox
1273
- ? TeleBox[K] extends Function
1101
+ ? // eslint-disable-next-line @typescript-eslint/ban-types
1102
+ TeleBox[K] extends Function
1274
1103
  ? never
1275
1104
  : K
1276
1105
  : never;