@netless/telebox-insider 0.2.26 → 1.0.0-alpha.11

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