@netless/telebox-insider 0.2.24 → 1.0.0-alpha.1

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