chnobli 0.1.9 → 0.1.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 (197) hide show
  1. package/dist/animation/Animation.d.ts +37 -0
  2. package/dist/animation/Animation.d.ts.map +1 -0
  3. package/dist/animation/Animation.js +232 -0
  4. package/dist/animation/Animation.js.map +1 -0
  5. package/dist/animation/public.d.ts +68 -0
  6. package/dist/animation/public.d.ts.map +1 -0
  7. package/dist/animation/public.js +115 -0
  8. package/dist/animation/public.js.map +1 -0
  9. package/dist/animator/Animator.d.ts +30 -0
  10. package/dist/animator/Animator.d.ts.map +1 -0
  11. package/dist/animator/Animator.js +97 -0
  12. package/dist/animator/Animator.js.map +1 -0
  13. package/dist/animator/index.d.ts +5 -0
  14. package/dist/animator/index.d.ts.map +1 -0
  15. package/dist/animator/index.js +53 -0
  16. package/dist/animator/index.js.map +1 -0
  17. package/dist/animator/public.d.ts +16 -0
  18. package/dist/animator/public.d.ts.map +1 -0
  19. package/dist/animator/public.js +50 -0
  20. package/dist/animator/public.js.map +1 -0
  21. package/dist/chnobli.d.ts +15 -0
  22. package/dist/chnobli.d.ts.map +1 -0
  23. package/dist/chnobli.js +59 -0
  24. package/dist/chnobli.js.map +1 -0
  25. package/dist/property/BasicProperty.d.ts +38 -0
  26. package/dist/property/BasicProperty.d.ts.map +1 -0
  27. package/dist/property/BasicProperty.js +72 -0
  28. package/dist/property/BasicProperty.js.map +1 -0
  29. package/dist/property/ClassProperty.d.ts +32 -0
  30. package/dist/property/ClassProperty.d.ts.map +1 -0
  31. package/dist/property/ClassProperty.js +108 -0
  32. package/dist/property/ClassProperty.js.map +1 -0
  33. package/dist/property/Property.d.ts +13 -0
  34. package/dist/property/Property.d.ts.map +1 -0
  35. package/dist/property/Property.js +22 -0
  36. package/dist/property/Property.js.map +1 -0
  37. package/dist/property/StyleProperty.d.ts +25 -0
  38. package/dist/property/StyleProperty.d.ts.map +1 -0
  39. package/dist/property/StyleProperty.js +221 -0
  40. package/dist/property/StyleProperty.js.map +1 -0
  41. package/dist/property/TransformProperty.d.ts +15 -0
  42. package/dist/property/TransformProperty.d.ts.map +1 -0
  43. package/dist/property/TransformProperty.js +43 -0
  44. package/dist/property/TransformProperty.js.map +1 -0
  45. package/dist/property/TransformXYProperty.d.ts +28 -0
  46. package/dist/property/TransformXYProperty.d.ts.map +1 -0
  47. package/dist/property/TransformXYProperty.js +65 -0
  48. package/dist/property/TransformXYProperty.js.map +1 -0
  49. package/dist/responsive/ResponsiveEvent.d.ts +17 -0
  50. package/dist/responsive/ResponsiveEvent.d.ts.map +1 -0
  51. package/dist/responsive/ResponsiveEvent.js +45 -0
  52. package/dist/responsive/ResponsiveEvent.js.map +1 -0
  53. package/dist/responsive/TestEvent.d.ts +11 -0
  54. package/dist/responsive/TestEvent.d.ts.map +1 -0
  55. package/dist/responsive/TestEvent.js +26 -0
  56. package/dist/responsive/TestEvent.js.map +1 -0
  57. package/dist/scroll/Scroll.d.ts +61 -0
  58. package/dist/scroll/Scroll.d.ts.map +1 -0
  59. package/dist/scroll/Scroll.js +280 -0
  60. package/dist/scroll/Scroll.js.map +1 -0
  61. package/dist/scroll/ScrollEvent.d.ts +17 -0
  62. package/dist/scroll/ScrollEvent.d.ts.map +1 -0
  63. package/dist/scroll/ScrollEvent.js +40 -0
  64. package/dist/scroll/ScrollEvent.js.map +1 -0
  65. package/dist/scroll/index.d.ts +8 -0
  66. package/dist/scroll/index.d.ts.map +1 -0
  67. package/dist/scroll/index.js +9 -0
  68. package/dist/scroll/index.js.map +1 -0
  69. package/dist/scroll/public.d.ts +35 -0
  70. package/dist/scroll/public.d.ts.map +1 -0
  71. package/dist/scroll/public.js +50 -0
  72. package/dist/scroll/public.js.map +1 -0
  73. package/dist/stagger/stagger.d.ts +20 -0
  74. package/dist/stagger/stagger.d.ts.map +1 -0
  75. package/dist/stagger/stagger.js +43 -0
  76. package/dist/stagger/stagger.js.map +1 -0
  77. package/dist/target/BaseTarget.old.d.ts +33 -0
  78. package/dist/target/BaseTarget.old.d.ts.map +1 -0
  79. package/dist/target/BaseTarget.old.js +73 -0
  80. package/dist/target/BaseTarget.old.js.map +1 -0
  81. package/dist/target/DomTarget.d.ts +41 -0
  82. package/dist/target/DomTarget.d.ts.map +1 -0
  83. package/dist/target/DomTarget.js +230 -0
  84. package/dist/target/DomTarget.js.map +1 -0
  85. package/dist/target/ObjectTarget.d.ts +31 -0
  86. package/dist/target/ObjectTarget.d.ts.map +1 -0
  87. package/dist/target/ObjectTarget.js +108 -0
  88. package/dist/target/ObjectTarget.js.map +1 -0
  89. package/dist/target/Target.d.ts +25 -0
  90. package/dist/target/Target.d.ts.map +1 -0
  91. package/dist/target/Target.js +25 -0
  92. package/dist/target/Target.js.map +1 -0
  93. package/dist/target/TestDomNode.d.ts +14 -0
  94. package/dist/target/TestDomNode.d.ts.map +1 -0
  95. package/dist/target/TestDomNode.js +55 -0
  96. package/dist/target/TestDomNode.js.map +1 -0
  97. package/dist/timeline/Nested.d.ts +30 -0
  98. package/dist/timeline/Nested.d.ts.map +1 -0
  99. package/dist/timeline/Nested.js +51 -0
  100. package/dist/timeline/Nested.js.map +1 -0
  101. package/dist/timeline/Timeline.d.ts +42 -0
  102. package/dist/timeline/Timeline.d.ts.map +1 -0
  103. package/dist/timeline/Timeline.js +306 -0
  104. package/dist/timeline/Timeline.js.map +1 -0
  105. package/dist/timeline/public.d.ts +167 -0
  106. package/dist/timeline/public.d.ts.map +1 -0
  107. package/dist/timeline/public.js +396 -0
  108. package/dist/timeline/public.js.map +1 -0
  109. package/dist/timing/AnimationFrameTicker.d.ts +32 -0
  110. package/dist/timing/AnimationFrameTicker.d.ts.map +1 -0
  111. package/dist/timing/AnimationFrameTicker.js +138 -0
  112. package/dist/timing/AnimationFrameTicker.js.map +1 -0
  113. package/dist/timing/Ease.d.ts +6 -0
  114. package/dist/timing/Ease.d.ts.map +1 -0
  115. package/dist/timing/Ease.js +15 -0
  116. package/dist/timing/Ease.js.map +1 -0
  117. package/dist/timing/TestTicker.d.ts +19 -0
  118. package/dist/timing/TestTicker.d.ts.map +1 -0
  119. package/dist/timing/TestTicker.js +85 -0
  120. package/dist/timing/TestTicker.js.map +1 -0
  121. package/dist/timing/Ticker.d.ts +16 -0
  122. package/dist/timing/Ticker.d.ts.map +1 -0
  123. package/dist/timing/Ticker.js +2 -0
  124. package/dist/timing/Ticker.js.map +1 -0
  125. package/dist/timing/Timing.d.ts +116 -0
  126. package/dist/timing/Timing.d.ts.map +1 -0
  127. package/dist/timing/Timing.js +310 -0
  128. package/dist/timing/Timing.js.map +1 -0
  129. package/dist/timing/easing.d.ts +158 -0
  130. package/dist/timing/easing.d.ts.map +1 -0
  131. package/dist/timing/easing.js +273 -0
  132. package/dist/timing/easing.js.map +1 -0
  133. package/dist/utils/Events.d.ts +9 -0
  134. package/dist/utils/Events.d.ts.map +1 -0
  135. package/dist/utils/Events.js +35 -0
  136. package/dist/utils/Events.js.map +1 -0
  137. package/dist/utils/internal.d.ts +5 -0
  138. package/dist/utils/internal.d.ts.map +1 -0
  139. package/dist/utils/internal.js +9 -0
  140. package/dist/utils/internal.js.map +1 -0
  141. package/dist/utils/motionpath.d.ts +16 -0
  142. package/dist/utils/motionpath.d.ts.map +1 -0
  143. package/dist/utils/motionpath.js +41 -0
  144. package/dist/utils/motionpath.js.map +1 -0
  145. package/dist/utils/utils.d.ts +44 -0
  146. package/dist/utils/utils.d.ts.map +1 -0
  147. package/dist/utils/utils.js +88 -0
  148. package/dist/utils/utils.js.map +1 -0
  149. package/dist/values/ColorValue.d.ts +12 -0
  150. package/dist/values/ColorValue.d.ts.map +1 -0
  151. package/dist/values/ColorValue.js +134 -0
  152. package/dist/values/ColorValue.js.map +1 -0
  153. package/dist/values/StyleValue.d.ts +41 -0
  154. package/dist/values/StyleValue.d.ts.map +1 -0
  155. package/dist/values/StyleValue.js +159 -0
  156. package/dist/values/StyleValue.js.map +1 -0
  157. package/dist/values/Value.d.ts +13 -0
  158. package/dist/values/Value.d.ts.map +1 -0
  159. package/dist/values/Value.js +38 -0
  160. package/dist/values/Value.js.map +1 -0
  161. package/dist/values/defaultcolors.d.ts +2 -0
  162. package/dist/values/defaultcolors.d.ts.map +1 -0
  163. package/dist/values/defaultcolors.js +149 -0
  164. package/dist/values/defaultcolors.js.map +1 -0
  165. package/eslint.config.js +23 -0
  166. package/package.json +10 -3
  167. package/src/animation/Animation.ts +6 -3
  168. package/src/animator/Animator.ts +130 -0
  169. package/src/animator/index.ts +56 -0
  170. package/src/animator/public.ts +66 -0
  171. package/src/chnobli.ts +3 -2
  172. package/src/property/ClassProperty.ts +1 -1
  173. package/src/property/TransformXYProperty.ts +1 -1
  174. package/src/scroll/Scroll.ts +202 -51
  175. package/src/scroll/ScrollEvent.ts +1 -0
  176. package/src/scroll/index.ts +3 -0
  177. package/src/scroll/public.ts +35 -2
  178. package/src/target/DomTarget.ts +1 -1
  179. package/src/target/ObjectTarget.ts +19 -13
  180. package/src/tests/properties.test.ts +44 -3
  181. package/src/tests/timeline.test.ts +1 -1
  182. package/src/tests/timing.test.ts +32 -0
  183. package/src/tests/usecases.test.ts +40 -2
  184. package/src/tests/values.test.ts +9 -9
  185. package/src/timeline/Timeline.ts +5 -4
  186. package/src/timeline/public.ts +34 -12
  187. package/src/timing/AnimationFrameTicker.ts +6 -1
  188. package/src/timing/TestTicker.ts +7 -1
  189. package/src/timing/Ticker.ts +5 -1
  190. package/src/timing/Timing.ts +127 -91
  191. package/src/utils/Events.ts +1 -1
  192. package/src/utils/motionpath.ts +5 -5
  193. package/src/utils/utils.ts +0 -10
  194. package/src/values/ColorValue.ts +1 -0
  195. package/src/values/Value.ts +1 -1
  196. package/.eslintrc.cjs +0 -39
  197. package/src/animator.js +0 -187
@@ -1,8 +1,8 @@
1
1
  import { describe, expect, it } from 'vitest';
2
2
  import TestTicker from '../timing/TestTicker.js';
3
3
  import TestResponsiveEvent from '../responsive/TestEvent.js';
4
- import { animate, timeline } from '../chnobli.js';
5
- import { responsive } from '../utils/utils.js';
4
+ import { timeline } from '../chnobli.js';
5
+ import { fromTo, responsive } from '../utils/utils.js';
6
6
  import { el } from '../target/TestDomNode.js';
7
7
 
8
8
  describe('usecases', () => {
@@ -64,4 +64,42 @@ describe('usecases', () => {
64
64
  expect(ctn.style.maxHeight).toBe(undefined);
65
65
  expect(itm.classList.contains('open')).toBe(false);
66
66
  });
67
+
68
+ it('accordion2', () => {
69
+ const ticker = new TestTicker();
70
+ const _respEv = new TestResponsiveEvent();
71
+
72
+ const ctn = el();
73
+ ctn.computedStyle.maxHeight = 'none';
74
+ // @ts-ignore
75
+ ctn.scrollHeight = '100px';
76
+
77
+ const tl = timeline({ reversed: true }).add(ctn, {
78
+ height: fromTo(
79
+ 0,
80
+ responsive(el => el.scrollHeight),
81
+ ),
82
+ duration: 100,
83
+ });
84
+
85
+ const toggle = () => {
86
+ tl.reverse();
87
+ tl.play();
88
+ };
89
+
90
+ // on click reverse or not
91
+ toggle();
92
+ ticker.run(1);
93
+ expect(ctn.style.height).toBe('1.000px');
94
+ ticker.run(49);
95
+ expect(ctn.style.height).toBe('50.000px');
96
+ toggle();
97
+ ticker.run(1);
98
+ expect(ctn.style.height).toBe('49.000px');
99
+ ticker.run(29);
100
+ expect(ctn.style.height).toBe('20.000px');
101
+ toggle();
102
+ ticker.run(1);
103
+ expect(ctn.style.height).toBe('21.000px');
104
+ });
67
105
  });
@@ -1,7 +1,7 @@
1
1
  import { describe, expect, it } from 'vitest';
2
2
  import TestTicker from '../timing/TestTicker.js';
3
- import { animate, timeline } from '../chnobli.js';
4
- import { responsive, from, fromTo } from '../utils/utils.js';
3
+ import { timeline } from '../chnobli.js';
4
+ import { from, fromTo } from '../utils/utils.js';
5
5
  import { el, getRootElement } from '../target/TestDomNode.js';
6
6
 
7
7
  describe('values', () => {
@@ -12,7 +12,7 @@ describe('values', () => {
12
12
  root.computedStyle.fontSize = '13px';
13
13
 
14
14
  const div = el();
15
- const tl = timeline()
15
+ const _tl = timeline()
16
16
  .add(div, {
17
17
  width: '10rem',
18
18
  duration: 5,
@@ -35,7 +35,7 @@ describe('values', () => {
35
35
 
36
36
  const div = el();
37
37
  div.computedStyle.width = '10px';
38
- const tl = timeline()
38
+ const _tl = timeline()
39
39
  .add(div, {
40
40
  x: '10%',
41
41
  width: '50%',
@@ -62,7 +62,7 @@ describe('values', () => {
62
62
 
63
63
  const div = el();
64
64
  div.computedStyle.padding = '5px';
65
- const tl = timeline()
65
+ const _tl = timeline()
66
66
  .add(div, {
67
67
  padding: '10px 20rem',
68
68
  duration: 10,
@@ -81,7 +81,7 @@ describe('values', () => {
81
81
 
82
82
  const div = el();
83
83
  div.computedStyle.display = 'block';
84
- const tl = timeline()
84
+ const _tl = timeline()
85
85
  .add(div, {
86
86
  display: 'none',
87
87
  position: from('absolute'),
@@ -100,7 +100,7 @@ describe('values', () => {
100
100
  expect(div.style.position).toBe(undefined);
101
101
  expect(div.style.visibility).toBe('visible');
102
102
 
103
- tl.seek(-1);
103
+ _tl.seek(-1);
104
104
  ticker.run();
105
105
  expect(div.style.display).toBe(undefined);
106
106
  expect(div.style.position).toBe(undefined);
@@ -112,7 +112,7 @@ describe('values', () => {
112
112
  const div = el();
113
113
  div.computedStyle.color = 'rgb(120, 130, 20)';
114
114
 
115
- const tl = timeline()
115
+ const _tl = timeline()
116
116
  .add(div, {
117
117
  color: 'black',
118
118
  backgroundColor: 'hsl(10, 80%, 40%)',
@@ -139,7 +139,7 @@ describe('values', () => {
139
139
  div.computedStyle['--color'] = 'rgb(120, 130, 20)';
140
140
  div.computedStyle['--border'] = '20px';
141
141
 
142
- const tl = timeline()
142
+ const _tl = timeline()
143
143
  .add(div, {
144
144
  '--color': 'black',
145
145
  '--border': '1px 20px',
@@ -10,6 +10,7 @@ import Timing, {
10
10
  import Ticker from '../timing/Ticker.js';
11
11
  import Animation from '../animation/Animation.js';
12
12
  import AnimationFrameTicker from '../timing/AnimationFrameTicker.js';
13
+ import { DestroyOptions } from './public.js';
13
14
 
14
15
  type Entry = {
15
16
  type: 'label' | 'animation' | 'timeline';
@@ -185,7 +186,7 @@ export default class Timeline {
185
186
 
186
187
  const pos = this.entries[i - 1 - entry.relativeOffset]?.end ?? 0;
187
188
 
188
- let start = offset.calculate(pos);
189
+ const start = offset.calculate(pos);
189
190
  if (start < 0) throw new Error('cannot go in the past start < 0');
190
191
 
191
192
  let end = start;
@@ -325,17 +326,17 @@ export default class Timeline {
325
326
  this.ticker.applyTargets();
326
327
  }
327
328
 
328
- destroy() {
329
+ destroy(opts: DestroyOptions) {
329
330
  for (const entry of this.entries) {
330
331
  if (entry.type === 'timeline') {
331
- entry.value.destroy();
332
+ entry.value.destroy(opts);
332
333
  continue;
333
334
  }
334
335
 
335
336
  if (entry.type !== 'animation') continue;
336
337
 
337
338
  const animation = entry.value;
338
- animation.destroy();
339
+ animation.destroy(opts);
339
340
  }
340
341
 
341
342
  this.entries = [];
@@ -38,12 +38,21 @@ export type TimelineProps = {
38
38
  // alternate
39
39
  // reversed
40
40
 
41
+ /**
42
+ * When set will keep all values when destroy is called
43
+ */
44
+ keepValues?: boolean;
45
+
41
46
  // other properties
42
47
  [key: string]: any;
43
48
  };
44
49
 
45
50
  export type Offset = number | string | Stagger<number | string>;
46
51
 
52
+ export type DestroyOptions = {
53
+ keepValues?: boolean;
54
+ };
55
+
47
56
  export default class PublicTimeline {
48
57
  /**
49
58
  * @ignore
@@ -60,13 +69,14 @@ export default class PublicTimeline {
60
69
  private _triggeredStart: boolean;
61
70
 
62
71
  private _state: number;
63
- private _renderedOnce: boolean;
64
72
  private _runningTicker: any;
65
73
  private _responsiveBlocks: { responsive: () => void }[];
66
74
  private _responsiveEvent: any;
67
75
  private _smoothSeek: SmoothSeek | null;
68
76
  private _seekTo: number;
69
77
 
78
+ private _destroyOpts: DestroyOptions;
79
+
70
80
  constructor(props: TimelineProps = {}) {
71
81
  this._defaults = takeProp(props, 'defaults', {});
72
82
  this._responsive = takeProp(props, 'responsive', true);
@@ -81,6 +91,12 @@ export default class PublicTimeline {
81
91
  );
82
92
  this._seekTo = 0;
83
93
 
94
+ this._destroyOpts = {
95
+ // we set this to undefined so we can have other default values
96
+ // for example in chnobli-svelte
97
+ keepValues: takeProp(props, 'keepValues', undefined),
98
+ };
99
+
84
100
  this._inner = new Timeline(props);
85
101
 
86
102
  // 'start', 'end'
@@ -88,7 +104,6 @@ export default class PublicTimeline {
88
104
  this._triggeredStart = false;
89
105
 
90
106
  this._state = STATE_PAUSED;
91
- this._renderedOnce = false;
92
107
  this._runningTicker = null;
93
108
  this._responsiveBlocks = [];
94
109
  if (this._responsive) {
@@ -227,7 +242,7 @@ export default class PublicTimeline {
227
242
  this._inner.init();
228
243
 
229
244
  if (this._smoothSeek) {
230
- this._smoothSeek.update(this._inner.timing.positionLinear(), pos);
245
+ this._smoothSeek.update(this._inner.timing.positionAbsolute(), pos);
231
246
 
232
247
  if (this._state !== STATE_PLAYING) this._state = STATE_SEEK;
233
248
  } else {
@@ -331,9 +346,11 @@ export default class PublicTimeline {
331
346
  /**
332
347
  * Destroys this timeline and resets all props
333
348
  */
334
- destroy() {
349
+ destroy(opts: DestroyOptions = {}) {
350
+ opts.keepValues = opts.keepValues ?? this._destroyOpts.keepValues;
351
+
335
352
  this._stopTicker();
336
- this._inner.destroy();
353
+ this._inner.destroy(opts);
337
354
  this._events.destroy();
338
355
  this._responsiveEvent?.remove();
339
356
  this._responsiveBlocks = [];
@@ -360,7 +377,7 @@ export default class PublicTimeline {
360
377
  const smoothSeekEnded = () =>
361
378
  !this._smoothSeek || this._smoothSeek.state >= STATE_ENDED;
362
379
 
363
- this._runningTicker = this._inner.ticker.add(change => {
380
+ this._runningTicker = this._inner.ticker.add((change, api) => {
364
381
  if (!this._triggeredStart) {
365
382
  // todo check that we are at the start
366
383
  if (this._inner.timing.state <= STATE_BEFORE) {
@@ -385,11 +402,19 @@ export default class PublicTimeline {
385
402
  }
386
403
 
387
404
  this._inner.render();
405
+ const pos = this._inner.timing.position;
406
+ api.onApplied(() => {
407
+ this._events.trigger('update', pos);
408
+ });
388
409
 
389
410
  // we rendered once let's stop
390
411
  const renderOnce = this._state === STATE_RENDER_ONCE;
391
412
 
392
- if (renderOnce || (timingEnded() && smoothSeekEnded())) {
413
+ if (
414
+ renderOnce ||
415
+ (smoothSeekEnded() &&
416
+ (this._state === STATE_SEEK || timingEnded()))
417
+ ) {
393
418
  this._maybeTriggerEndEvent();
394
419
 
395
420
  this._state = STATE_PAUSED;
@@ -413,12 +438,9 @@ export default class PublicTimeline {
413
438
  * @ignore
414
439
  */
415
440
  _onResponsive(
416
- a: { width: number; height: number },
417
- b: { remove: () => void },
441
+ _a: { width: number; height: number },
442
+ _b: { remove: () => void },
418
443
  ) {
419
- // // make sure we don't render something if we never did
420
- // if (!this._renderedOnce)
421
- // return;
422
444
  this._inner.update();
423
445
  }
424
446
  }
@@ -91,16 +91,21 @@ export default class AnimationFrameTicker implements Ticker {
91
91
  this._previousTick = elapsed;
92
92
 
93
93
  // const changes = new PropertyChanges;
94
+ const onApplied: (() => void)[] = [];
94
95
 
95
96
  for (const fn of this._listeners) {
96
97
  fn(change, {
97
- // changes,
98
98
  remove: () => this.remove(fn),
99
+ onApplied: fnOnApplied => onApplied.push(fnOnApplied),
99
100
  });
100
101
  }
101
102
 
102
103
  this._targets.apply();
103
104
 
105
+ for (const fn of onApplied) {
106
+ fn();
107
+ }
108
+
104
109
  requestAnimationFrame(a => this._tick(a));
105
110
  }
106
111
  }
@@ -81,15 +81,21 @@ export default class TestTicker implements Ticker {
81
81
  }
82
82
  this._previousTick = elapsed;
83
83
 
84
+ const onApplied: (() => void)[] = [];
85
+
84
86
  for (const fn of this._listeners) {
85
87
  fn(change, {
86
- // changes,
87
88
  remove: () => this.remove(fn),
89
+ onApplied: fn => onApplied.push(fn),
88
90
  });
89
91
  }
90
92
 
91
93
  this.targets.apply();
92
94
 
95
+ for (const fn of onApplied) {
96
+ fn();
97
+ }
98
+
93
99
  if (this._listeners.size === 0) {
94
100
  this.running = false;
95
101
  this._previousTick = null;
@@ -1,6 +1,10 @@
1
1
  import { Target } from '../target/Target.js';
2
2
 
3
- export type Callback = (change: number, api: { remove: () => void }) => void;
3
+ export type CallbackApi = {
4
+ remove: () => void;
5
+ onApplied: (fn: () => void) => void;
6
+ };
7
+ export type Callback = (change: number, api: CallbackApi) => void;
4
8
 
5
9
  export default interface Ticker {
6
10
  registerTarget(target: any): Target;
@@ -36,67 +36,84 @@ export type TimingProps = {
36
36
  * because it is like one frame, so it's an image
37
37
  */
38
38
  export default class Timing {
39
- // removes the relevant properties from the props
40
-
39
+ /**
40
+ * The duration of a single iteration
41
+ */
41
42
  iterDuration: number;
43
+
44
+ /**
45
+ * The total duration of the timing
46
+ */
42
47
  duration: number;
43
48
 
44
49
  ease: (t: number) => number;
50
+ /**
51
+ * The number of repeats
52
+ *
53
+ * -1 is infinite
54
+ */
45
55
  repeat: number;
56
+
57
+ /**
58
+ * If the iteration should alternate
59
+ */
46
60
  alternate: boolean;
61
+
62
+ /**
63
+ * If the iteration should be reversed
64
+ */
47
65
  reversed: boolean;
48
66
 
67
+ /**
68
+ * The position of the current iteration
69
+ *
70
+ * will never be outside of the range 0-1 (inclusive)
71
+ */
49
72
  position: number;
73
+ /**
74
+ * The state of the timing
75
+ */
50
76
  state: number;
51
77
 
52
- private _progress: number;
53
-
54
- /*
55
- seeking
56
- if repeat is infinite
57
- seek will only control the current iteration
58
- if repeat is finite
59
- seek will control the entire time
60
-
78
+ /**
79
+ * Progress is a value which always counts up
80
+ * does not take alternate or easing into account
81
+ */
82
+ private progress: number;
61
83
 
62
- {
63
- duration: in ms
64
- ease: easeFunction
65
- repeat: -1 - x,
66
- alternate
67
- }
68
- */
69
84
  constructor(props: TimingProps) {
70
85
  // these vars are only readonly
71
86
  // use functions to update them
72
87
 
73
- this.iterDuration = props.duration;
74
- this.duration = props.duration;
75
-
76
88
  this.ease = props.ease ?? (t => t);
77
89
  this.repeat = props.repeat ?? 0;
78
90
  this.alternate = props.alternate ?? true;
79
91
  this.reversed = props.reversed ?? false;
80
92
 
81
- this.position = this.duration > 0 ? 0 : 1;
82
- this.state = STATE_BEFORE;
83
-
84
- // progress does not take alternation into account and has no easing
85
- // this always increments up
86
- this._progress = 0;
93
+ this.iterDuration = 0;
94
+ this.duration = 0;
95
+ this.setDuration(props.duration);
87
96
 
88
- // scrub
97
+ this.position = 0;
98
+ this.state = STATE_BEFORE;
99
+ this.progress = 0;
100
+ this.seek(-1);
89
101
  }
90
102
 
91
103
  setDuration(iterDuration: number) {
92
104
  this.iterDuration = iterDuration;
93
105
 
94
106
  this.duration = this.iterDuration;
95
- if (this.repeat > -1) {
107
+ if (this.isFinite()) {
96
108
  this.duration = (this.repeat + 1) * this.iterDuration;
97
109
  }
98
110
  }
99
111
 
112
+ /**
113
+ * Returns the current position in milliseconds
114
+ *
115
+ * This is equivalent to position * iteration duration
116
+ */
100
117
  positionMs() {
101
118
  // todo should this not return pos * duration?
102
119
  return this.position * this.iterDuration;
@@ -110,13 +127,19 @@ export default class Timing {
110
127
  * required
111
128
  */
112
129
  positionMsUnbounded() {
113
- const outOfBounds =
114
- this.state <= STATE_BEFORE || this.state >= STATE_AFTER;
130
+ let reversed = this.reversed;
131
+
132
+ if (this._shouldInvert()) reversed = !reversed;
115
133
 
116
- if (!outOfBounds) return this.position * this.iterDuration;
134
+ let pos = this.position;
135
+
136
+ if (this.state <= STATE_BEFORE) {
137
+ pos = reversed ? 2 : -1;
138
+ } else if (this.state >= STATE_AFTER) {
139
+ pos = reversed ? -1 : 2;
140
+ }
117
141
 
118
- if (this.position === 0) return -1;
119
- return this.position * this.iterDuration + 1;
142
+ return pos * this.iterDuration;
120
143
  }
121
144
 
122
145
  isFinite() {
@@ -131,56 +154,60 @@ export default class Timing {
131
154
  return;
132
155
  }
133
156
 
134
- this._updateProgress(this._progress + change / this.iterDuration);
157
+ if (this.isFinite()) {
158
+ this._updateProgress(
159
+ this.positionAbsolute() + change / this.iterDuration,
160
+ );
161
+ } else {
162
+ // to make sure we don't mess up the alternate
163
+ this._updateProgress(
164
+ Math.max(0, this.progress) + change / this.iterDuration,
165
+ );
166
+ }
135
167
  }
136
168
 
137
169
  seekMs(ms: number) {
138
- if (this.iterDuration <= 0) {
139
- this._updateProgress(Math.sign(ms));
140
- return;
141
- }
142
-
143
- this._updateProgress(ms / this.iterDuration);
144
-
145
- // return this.seek(this.normalizeMs(ms));
170
+ return this.seek(this.normalizeMs(ms));
146
171
  }
147
172
 
173
+ /**
174
+ * Returns the position of time (ms) position
175
+ */
148
176
  normalizeMs(ms: number) {
149
177
  if (this.iterDuration <= 0) {
150
178
  return Math.sign(ms);
151
179
  }
152
180
 
153
- const pos = ms / this.iterDuration;
154
-
155
- if (this.isFinite()) {
156
- return pos / (this.repeat + 1);
157
- }
158
-
159
- return pos;
181
+ return ms / this.duration;
160
182
  }
161
183
 
162
- // todo how to call this
163
- positionLinear(): number {
184
+ // Returns the position without easing or reversing
185
+ //
186
+ // Returns 0..=(repeat + 1)
187
+ positionAbsolute(): number {
164
188
  if (this.isFinite()) {
165
- return this._progress / (this.repeat + 1);
189
+ return Math.min(this.repeat + 1, Math.max(0, this.progress));
166
190
  }
167
191
 
168
- return this._progress;
192
+ // the iterations should be inclusive
193
+ const prog = Math.max(0, this.progress) % 1;
194
+ if (prog === 0 && this.progress > 0) return 1;
195
+ return prog;
169
196
  }
170
197
 
171
198
  // should be between 0-1 if outside might change the state
172
199
  seek(pos: number) {
173
- if (this.repeat <= 0) {
174
- this._updateProgress(pos);
175
- } else {
176
- // finite
200
+ if (this.isFinite()) {
177
201
  this._updateProgress(pos * (this.repeat + 1));
202
+ } else {
203
+ // to make sure we don't mess up the alternate
204
+ this._updateProgress(Math.floor(this.progress) + pos);
178
205
  }
179
206
  }
180
207
 
181
208
  savePosition(): Position {
182
209
  return {
183
- progress: this._progress,
210
+ progress: this.progress,
184
211
  };
185
212
  }
186
213
 
@@ -188,48 +215,46 @@ export default class Timing {
188
215
  this._updateProgress(pos.progress);
189
216
  }
190
217
 
218
+ /**
219
+ * Sets the alternate
220
+ */
191
221
  setAlternate(alternate: boolean) {
192
222
  if (this.alternate == alternate) return;
193
223
 
194
- // make sure the reversed is updated according to the current inversion
195
- this.reversed = alternate == this._shouldInvert();
224
+ this.reversed = !this.reversed;
196
225
  this.alternate = alternate;
197
226
  }
198
227
 
199
228
  reverse() {
200
229
  this.reversed = !this.reversed;
201
230
 
202
- const wrapAround = (p: number) => {
203
- if (this.repeat > -1) return p % (this.repeat + 1);
204
- return p;
205
- };
206
-
207
- let p;
208
- if (this.state <= STATE_BEFORE) {
209
- p = 2;
210
- } else if (this.state >= STATE_AFTER) {
211
- p = -1;
212
- // check if the values should be reversed
213
- } else if (this.reversed != this._shouldInvert()) {
214
- let decimal = 1 - (this._progress % 1);
215
- p = wrapAround(Math.floor(this._progress) + decimal);
231
+ if (this.isFinite()) {
232
+ this._updateProgress(this.repeat + 1 - this.progress);
216
233
  } else {
217
- p = wrapAround(this._progress);
234
+ const fract = this.progress % 1;
235
+ this._updateProgress(Math.floor(this.progress) + 1 - fract);
218
236
  }
219
-
220
- this._updateProgress(p);
221
237
  }
222
238
 
223
239
  _shouldInvert() {
224
- return this.alternate && Math.floor(this._progress) % 2 === 1;
240
+ return (
241
+ this.alternate &&
242
+ Math.floor(this.progress) % 2 === 1 &&
243
+ this.progress % 1 !== 0
244
+ );
225
245
  }
226
246
 
247
+ /**
248
+ * Updates the progress and the state
249
+ *
250
+ * newProgress should follow the same rules as _progress
251
+ */
227
252
  _updateProgress(newProgress: number) {
228
253
  // if duration is zero the position is always 1
229
254
  // and the state is either BEFORE or AFTER
230
255
  if (this.iterDuration <= 0) {
231
256
  newProgress = Math.sign(newProgress);
232
- this._progress = newProgress;
257
+ this.progress = newProgress;
233
258
  this.position = 1;
234
259
 
235
260
  if (newProgress < 0) this.state = STATE_BEFORE;
@@ -238,15 +263,19 @@ export default class Timing {
238
263
  return;
239
264
  }
240
265
 
241
- this._progress = newProgress;
266
+ this.progress = newProgress;
242
267
 
268
+ // update state
269
+ //
270
+ // is this not wrong if we are in reversed?
271
+ //
243
272
  // since infinite repeat can never end let's ignore it
244
- if (this.repeat > -1) {
273
+ if (this.isFinite()) {
245
274
  const end = this.repeat + 1;
246
- if (this._progress > end) {
247
- this._progress = end;
275
+ if (this.progress > end) {
276
+ this.progress = end + 1;
248
277
  this.state = STATE_AFTER;
249
- } else if (this._progress === end) {
278
+ } else if (this.progress === end) {
250
279
  this.state = STATE_ENDED;
251
280
  } else {
252
281
  this.state = STATE_RUNNING;
@@ -256,20 +285,27 @@ export default class Timing {
256
285
  }
257
286
 
258
287
  // override state if not running
259
- if (this._progress < 0) {
260
- this._progress = 0;
288
+ if (this.progress < 0) {
289
+ this.progress = -1;
261
290
  this.state = STATE_BEFORE;
262
- } else if (this._progress === 0) {
291
+ } else if (this.progress === 0) {
263
292
  this.state = STATE_START;
264
293
  }
265
294
 
266
295
  // now calculate the position
267
- this.position = this._progress % 1;
296
+ this.position = this.positionAbsolute() % 1;
297
+
298
+ // the iterations should be inclusive
299
+ if (this.position === 0 && this.progress > 0) {
300
+ this.position = 1;
301
+ }
302
+
303
+ // alternate
304
+ if (this._shouldInvert()) this.position = 1 - this.position;
268
305
 
269
306
  // calc if we are in a reversed iteration or not
270
307
  // and we are we should invert the position
271
- if (this.reversed != this._shouldInvert())
272
- this.position = 1 - this.position;
308
+ if (this.reversed) this.position = 1 - this.position;
273
309
 
274
310
  this.position = this.ease(this.position);
275
311
  }