@freestylejs/ani-core 1.0.0 → 1.2.0

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.
package/dist/index.js CHANGED
@@ -1,4 +1,39 @@
1
- // src/ani/nodes/base.ts
1
+ // src/utils/time/is_end.ts
2
+ function isEndOfAnimation(currentT, duration, tolerance = 1e-3) {
3
+ return currentT === duration || currentT - duration >= tolerance;
4
+ }
5
+
6
+ // src/ani/core/engine.ts
7
+ function calculateSegmentState(localTime, segmentDef, dt = 0) {
8
+ const t = Math.max(0, Math.min(localTime, segmentDef.duration));
9
+ const animeValues = [];
10
+ let allComplete = true;
11
+ const isMultipleTiming = Array.isArray(segmentDef.timing);
12
+ if (isMultipleTiming && segmentDef.timing.length !== segmentDef.from.length) {
13
+ throw new TypeError(
14
+ `[calculateSegmentState] timing does not correctly set. It requires multiple timing for ${segmentDef.from}, but received ${segmentDef.timing}`
15
+ );
16
+ }
17
+ for (let i = 0; i < segmentDef.from.length; i++) {
18
+ const timingFunction = isMultipleTiming ? segmentDef.timing[i] : segmentDef.timing;
19
+ const animeResponse = timingFunction.step(t, {
20
+ dt,
21
+ from: segmentDef.from[i],
22
+ to: segmentDef.to[i],
23
+ duration: segmentDef.duration
24
+ });
25
+ animeValues.push(animeResponse.value);
26
+ if (!animeResponse.endOfAnimation) {
27
+ allComplete = false;
28
+ }
29
+ }
30
+ return {
31
+ values: animeValues,
32
+ isComplete: allComplete || isEndOfAnimation(t, segmentDef.duration)
33
+ };
34
+ }
35
+
36
+ // src/nodes/base.ts
2
37
  var AnimationNode = class {
3
38
  constructor(id) {
4
39
  if (id) {
@@ -28,6 +63,113 @@ var TimingFunction = class _TimingFunction {
28
63
  }
29
64
  };
30
65
 
66
+ // src/timing/bezier.ts
67
+ var NEWTON_ITERATIONS = 4;
68
+ var NEWTON_MIN_SLOPE = 1e-3;
69
+ var SUBDIVISION_PRECISION = 1e-7;
70
+ var SUBDIVISION_MAX_ITERATIONS = 10;
71
+ var SAMPLE_TABLE_SIZE = 11;
72
+ var SAMPLE_STEP_SIZE = 1 / (SAMPLE_TABLE_SIZE - 1);
73
+ var BezierTimingFunction = class extends TimingFunction {
74
+ constructor(opt) {
75
+ super();
76
+ this.opt = opt;
77
+ this.sampleValues = null;
78
+ if (this.opt.p2.x !== this.opt.p2.y || this.opt.p3.x !== this.opt.p3.y) {
79
+ this.sampleValues = new Float32Array(SAMPLE_TABLE_SIZE);
80
+ for (let i = 0; i < SAMPLE_TABLE_SIZE; ++i) {
81
+ this.sampleValues[i] = this.calcBezier(
82
+ i * SAMPLE_STEP_SIZE,
83
+ this.opt.p2.x,
84
+ this.opt.p3.x
85
+ );
86
+ }
87
+ }
88
+ }
89
+ calcBezier(t, a1, a2) {
90
+ return ((1 - 3 * a2 + 3 * a1) * t + (3 * a2 - 6 * a1)) * t * t + 3 * a1 * t;
91
+ }
92
+ getSlope(t, a1, a2) {
93
+ return 3 * (1 - 3 * a2 + 3 * a1) * t * t + 2 * (3 * a2 - 6 * a1) * t + 3 * a1;
94
+ }
95
+ getTForX(x) {
96
+ const mX1 = this.opt.p2.x;
97
+ const mX2 = this.opt.p3.x;
98
+ let intervalStart = 0;
99
+ let currentSample = 1;
100
+ const lastSample = SAMPLE_TABLE_SIZE - 1;
101
+ for (; currentSample !== lastSample && this.sampleValues[currentSample] <= x; ++currentSample) {
102
+ intervalStart += SAMPLE_STEP_SIZE;
103
+ }
104
+ --currentSample;
105
+ const dist = (x - this.sampleValues[currentSample]) / (this.sampleValues[currentSample + 1] - this.sampleValues[currentSample]);
106
+ const guessForT = intervalStart + dist * SAMPLE_STEP_SIZE;
107
+ const initialSlope = this.getSlope(guessForT, mX1, mX2);
108
+ if (initialSlope >= NEWTON_MIN_SLOPE) {
109
+ return this.newtonRaphsonIterate(x, guessForT, mX1, mX2);
110
+ }
111
+ if (initialSlope === 0) {
112
+ return guessForT;
113
+ }
114
+ return this.binarySubdivide(
115
+ x,
116
+ intervalStart,
117
+ intervalStart + SAMPLE_STEP_SIZE,
118
+ mX1,
119
+ mX2
120
+ );
121
+ }
122
+ binarySubdivide(aX, aA, aB, mX1, mX2) {
123
+ let currentX;
124
+ let currentT;
125
+ let i = 0;
126
+ let currentA = aA;
127
+ let currentB = aB;
128
+ do {
129
+ currentT = currentA + (currentB - currentA) / 2;
130
+ currentX = this.calcBezier(currentT, mX1, mX2) - aX;
131
+ if (currentX > 0) {
132
+ currentB = currentT;
133
+ } else {
134
+ currentA = currentT;
135
+ }
136
+ } while (Math.abs(currentX) > SUBDIVISION_PRECISION && ++i < SUBDIVISION_MAX_ITERATIONS);
137
+ return currentT;
138
+ }
139
+ newtonRaphsonIterate(aX, aGuessT, mX1, mX2) {
140
+ let guessT = aGuessT;
141
+ for (let i = 0; i < NEWTON_ITERATIONS; ++i) {
142
+ const currentSlope = this.getSlope(guessT, mX1, mX2);
143
+ if (currentSlope === 0) {
144
+ return guessT;
145
+ }
146
+ const currentX = this.calcBezier(guessT, mX1, mX2) - aX;
147
+ guessT -= currentX / currentSlope;
148
+ }
149
+ return guessT;
150
+ }
151
+ step(time, context) {
152
+ const { duration, from, to } = context;
153
+ if (duration === 0) {
154
+ return { value: to, endOfAnimation: true };
155
+ }
156
+ const x = Math.max(0, Math.min(time / duration, 1));
157
+ let easedT = x;
158
+ if (this.opt.p2.x !== this.opt.p2.y || this.opt.p3.x !== this.opt.p3.y) {
159
+ if (!this.sampleValues) {
160
+ }
161
+ const t = this.getTForX(x);
162
+ easedT = this.calcBezier(t, this.opt.p2.y, this.opt.p3.y);
163
+ }
164
+ const value = from + (to - from) * easedT;
165
+ const endOfAnimation = time >= duration;
166
+ return {
167
+ value,
168
+ endOfAnimation
169
+ };
170
+ }
171
+ };
172
+
31
173
  // src/timing/linear.ts
32
174
  var LinearTimingFunction = class extends TimingFunction {
33
175
  step(time, context) {
@@ -37,29 +179,72 @@ var LinearTimingFunction = class extends TimingFunction {
37
179
  }
38
180
  };
39
181
 
40
- // src/timing/bezier.ts
41
- var BezierTimingFunction = class extends TimingFunction {
182
+ // src/timing/dynamic_spring.ts
183
+ var DynamicSpringTimingFunction = class extends TimingFunction {
42
184
  constructor(opt) {
43
185
  super();
44
186
  this.opt = opt;
45
- this.p1 = {
46
- x: 0,
47
- y: 0
48
- };
49
- this.p4 = {
50
- x: 1,
51
- y: 1
52
- };
187
+ this.currentValue = 0;
188
+ this.currentVelocity = 0;
189
+ this.isInitialized = false;
53
190
  }
54
- _bezierFunction(t, duration) {
55
- const end = duration || this.p4.y;
56
- return (1 - t) ** 3 * this.p1.y + 3 * (1 - t) ** 2 * t * this.opt.p2.y + 3 * (1 - t) * t ** 2 * this.opt.p3.y + t ** 3 * end;
191
+ init(startValue) {
192
+ this.currentValue = startValue;
193
+ this.currentVelocity = 0;
194
+ this.isInitialized = true;
57
195
  }
58
- step(time, context) {
59
- const f = this._bezierFunction(time, context.duration);
196
+ getDerivatives(state, to) {
197
+ const { m, k, c } = this.opt;
198
+ const displacement = state.x - to;
199
+ const a2 = (-k * displacement - c * state.v) / m;
200
+ return { dx: state.v, dv: a2 };
201
+ }
202
+ step(_time, context) {
203
+ if (!this.isInitialized) {
204
+ this.init(context.from);
205
+ }
206
+ const { to, tolerance, dt } = context;
207
+ if (dt === 0) {
208
+ return {
209
+ value: this.currentValue,
210
+ endOfAnimation: false
211
+ // Or check for end state
212
+ };
213
+ }
214
+ const x = this.currentValue;
215
+ const v = this.currentVelocity;
216
+ const k1 = this.getDerivatives({ x, v }, to);
217
+ const k2State = {
218
+ x: x + k1.dx * (dt / 2),
219
+ v: v + k1.dv * (dt / 2)
220
+ };
221
+ const k2 = this.getDerivatives(k2State, to);
222
+ const k3State = {
223
+ x: x + k2.dx * (dt / 2),
224
+ v: v + k2.dv * (dt / 2)
225
+ };
226
+ const k3 = this.getDerivatives(k3State, to);
227
+ const k4State = {
228
+ x: x + k3.dx * dt,
229
+ v: v + k3.dv * dt
230
+ };
231
+ const k4 = this.getDerivatives(k4State, to);
232
+ const avgDx = 1 / 6 * (k1.dx + 2 * k2.dx + 2 * k3.dx + k4.dx);
233
+ const avgDv = 1 / 6 * (k1.dv + 2 * k2.dv + 2 * k3.dv + k4.dv);
234
+ this.currentValue = x + avgDx * dt;
235
+ this.currentVelocity = v + avgDv * dt;
236
+ const tol = tolerance ?? 1e-3;
237
+ const displacement = this.currentValue - to;
238
+ const isMoving = Math.abs(this.currentVelocity) > tol;
239
+ const isDisplaced = Math.abs(displacement) > tol;
240
+ const endOfAnimation = !isMoving && !isDisplaced;
241
+ if (endOfAnimation) {
242
+ this.currentValue = to;
243
+ this.currentVelocity = 0;
244
+ }
60
245
  return {
61
- value: f,
62
- endOfAnimation: (context.duration ? time >= context.duration : time >= this.p4.x) && f >= context.to
246
+ value: this.currentValue,
247
+ endOfAnimation
63
248
  };
64
249
  }
65
250
  };
@@ -134,30 +319,62 @@ var T = {
134
319
  * Creates a new Bezier timing function instance.
135
320
  *
136
321
  * @param {Bezier.BezierTimingFunctionOpt} opt - Options for configuring the Bezier curve.
137
- * A new instance of BezierTimingFunction.
138
322
  */
139
323
  bezier: (opt) => new BezierTimingFunction(opt),
140
324
  /**
141
325
  * Creates a new Spring timing function instance.
142
326
  *
143
- * @param {Spring.SpringTimingFunctionOpt} opt - Options for configuring the Spring timing function.
144
- * A new instance of SpringTimingFunction.
327
+ * @param {SpringTimingFunctionOpt} opt - Options for configuring the Spring timing function.
145
328
  */
146
329
  spring: (opt) => new SpringTimingFunction(opt),
330
+ /**
331
+ * Creates a new Dynamic Spring timing function instance.
332
+ *
333
+ * @param SpringTimingFunctionOpt} opt - Options for configuring the Spring timing function.
334
+ */
335
+ dynamicSpring: (opt) => new DynamicSpringTimingFunction(opt),
147
336
  /**
148
337
  * Creates linear timing function instance.
149
338
  */
150
- linear: () => new LinearTimingFunction()
339
+ linear: () => new LinearTimingFunction(),
340
+ /**
341
+ * Standard CSS 'ease' timing function (0.25, 0.1, 0.25, 1.0).
342
+ */
343
+ ease: () => new BezierTimingFunction({
344
+ p2: { x: 0.25, y: 0.1 },
345
+ p3: { x: 0.25, y: 1 }
346
+ }),
347
+ /**
348
+ * Standard CSS 'ease-in' timing function (0.42, 0, 1.0, 1.0).
349
+ */
350
+ easeIn: () => new BezierTimingFunction({
351
+ p2: { x: 0.42, y: 0 },
352
+ p3: { x: 1, y: 1 }
353
+ }),
354
+ /**
355
+ * Standard CSS 'ease-out' timing function (0, 0, 0.58, 1.0).
356
+ */
357
+ easeOut: () => new BezierTimingFunction({
358
+ p2: { x: 0, y: 0 },
359
+ p3: { x: 0.58, y: 1 }
360
+ }),
361
+ /**
362
+ * Standard CSS 'ease-in-out' timing function (0.42, 0, 0.58, 1.0).
363
+ */
364
+ easeInOut: () => new BezierTimingFunction({
365
+ p2: { x: 0.42, y: 0 },
366
+ p3: { x: 0.58, y: 1 }
367
+ })
151
368
  };
152
369
 
153
- // src/ani/nodes/segment.ts
370
+ // src/nodes/segment.ts
154
371
  var SegmentNode = class extends AnimationNode {
155
372
  constructor(props, id) {
156
373
  super(id);
157
374
  this.type = "SEGMENT";
158
375
  const nodeProps = {
159
376
  to: props.to,
160
- duration: props.duration ?? 0,
377
+ duration: props.duration,
161
378
  ...props.timing !== void 0 && { timing: props.timing }
162
379
  };
163
380
  this.props = nodeProps;
@@ -177,7 +394,7 @@ function ani(props, id) {
177
394
  return new SegmentNode(props, id);
178
395
  }
179
396
 
180
- // src/ani/nodes/composition.ts
397
+ // src/nodes/composition.ts
181
398
  var CompositionNode = class _CompositionNode extends AnimationNode {
182
399
  constructor(children, timing, id) {
183
400
  super(id);
@@ -206,12 +423,12 @@ var CompositionNode = class _CompositionNode extends AnimationNode {
206
423
  }
207
424
  };
208
425
 
209
- // src/ani/nodes/delay.ts
426
+ // src/nodes/delay.ts
210
427
  function delay(duration, id) {
211
428
  return new SegmentNode({ to: {}, duration }, id);
212
429
  }
213
430
 
214
- // src/ani/nodes/loop.ts
431
+ // src/nodes/loop.ts
215
432
  var LoopNode = class extends CompositionNode {
216
433
  constructor(child, loopCount, timing, id) {
217
434
  super([child], timing, id);
@@ -232,7 +449,7 @@ function loop(child, loopCount, timing, id) {
232
449
  return new LoopNode(child, loopCount, timing, id);
233
450
  }
234
451
 
235
- // src/ani/nodes/parallel.ts
452
+ // src/nodes/parallel.ts
236
453
  var ParallelNode = class extends CompositionNode {
237
454
  constructor(children, timing, id) {
238
455
  const seenProperty = /* @__PURE__ */ new Set();
@@ -282,7 +499,7 @@ function parallel(children, timing, id) {
282
499
  return new ParallelNode(children, timing, id);
283
500
  }
284
501
 
285
- // src/ani/nodes/sequence.ts
502
+ // src/nodes/sequence.ts
286
503
  var SequenceNode = class extends CompositionNode {
287
504
  constructor(children, timing, id) {
288
505
  super(children, timing, id);
@@ -301,12 +518,12 @@ function sequence(children, timing, id) {
301
518
  return new SequenceNode(children, timing, id);
302
519
  }
303
520
 
304
- // src/ani/nodes/stagger.ts
521
+ // src/nodes/stagger.ts
305
522
  var StaggerNode = class extends CompositionNode {
306
- constructor(children, props, id) {
307
- super(children, props?.timing, id);
523
+ constructor(children, offset, timing, id) {
524
+ super(children, timing, id);
308
525
  this.type = "STAGGER";
309
- this.offset = props.offset;
526
+ this.offset = offset;
310
527
  if (children.length === 0) {
311
528
  this.duration = 0;
312
529
  } else {
@@ -322,10 +539,81 @@ var StaggerNode = class extends CompositionNode {
322
539
  }
323
540
  }
324
541
  };
325
- function stagger(children, props, id) {
326
- return new StaggerNode(children, props, id);
542
+ function stagger(children, offset, timing, id) {
543
+ return new StaggerNode(children, offset, timing, id);
327
544
  }
328
545
 
546
+ // src/ani/core/interface/timeline_interface.ts
547
+ var TimelineBase = class {
548
+ constructor(rootNode) {
549
+ this.rootNode = rootNode;
550
+ this._currentExecutionPlan = null;
551
+ this.duration = rootNode.duration;
552
+ this._baseExecutionPlan = this._constructExecutionPlan(rootNode);
553
+ this.play = this.play.bind(this);
554
+ this.pause = this.pause.bind(this);
555
+ this.seek = this.seek.bind(this);
556
+ this.reset = this.reset.bind(this);
557
+ this.resume = this.resume.bind(this);
558
+ }
559
+ /**
560
+ * flatten the AST into a linear execution plan.
561
+ */
562
+ _constructExecutionPlan(rootNode) {
563
+ const plan = [];
564
+ rootNode.construct(plan, 0);
565
+ return plan;
566
+ }
567
+ /**
568
+ * Merges the base plan with runtime dynamic overrides.
569
+ */
570
+ _resolveExecutionPlan(keyframes, durations) {
571
+ if (!keyframes && !durations) {
572
+ return [...this._baseExecutionPlan];
573
+ }
574
+ const segmentNodes = this._baseExecutionPlan.filter(
575
+ (segment) => segment.node.type === "SEGMENT"
576
+ );
577
+ const segLength = segmentNodes.length;
578
+ if (keyframes && keyframes.length !== segLength) {
579
+ throw new Error(
580
+ `[Timeline] Keyframe mismatch: Expected ${segLength}, received ${keyframes.length}.`
581
+ );
582
+ }
583
+ if (durations && durations.length !== segLength) {
584
+ throw new Error(
585
+ `[Timeline] Duration mismatch: Expected ${segLength}, received ${durations.length}.`
586
+ );
587
+ }
588
+ const newPlan = [];
589
+ let keyframeIndex = 0;
590
+ for (const segment of this._baseExecutionPlan) {
591
+ if (segment.node.type === "SEGMENT") {
592
+ const dynamicTo = keyframes?.[keyframeIndex];
593
+ const dynamicDuration = durations?.[keyframeIndex];
594
+ const newSegmentProps = {
595
+ ...segment.node.props,
596
+ ...dynamicTo && dynamicTo !== "keep" && {
597
+ to: dynamicTo
598
+ },
599
+ ...dynamicDuration && dynamicDuration !== "keep" && {
600
+ duration: dynamicDuration
601
+ }
602
+ };
603
+ const newSegment = new SegmentNode(
604
+ newSegmentProps,
605
+ segment.node.id
606
+ );
607
+ newPlan.push({ ...segment, node: newSegment });
608
+ keyframeIndex++;
609
+ } else {
610
+ newPlan.push({ ...segment });
611
+ }
612
+ }
613
+ return newPlan;
614
+ }
615
+ };
616
+
329
617
  // src/loop/clock.ts
330
618
  var AnimationClock = class _AnimationClock {
331
619
  constructor(maxDeltaTime) {
@@ -381,234 +669,174 @@ var AnimationClock = class _AnimationClock {
381
669
  }
382
670
  };
383
671
 
384
- // src/utils/time/is_end.ts
385
- function isEndOfAnimation(currentT, duration, tolerance = 1e-3) {
386
- return currentT === duration || currentT - duration >= tolerance;
672
+ // src/ani/core/resolver.ts
673
+ function resolveGroup(group) {
674
+ if (Array.isArray(group)) {
675
+ return { keyMap: null, values: group };
676
+ }
677
+ const typedGroup = group;
678
+ const keys = Object.keys(typedGroup);
679
+ const keyMap = new Map(keys.map((key, i) => [key, i]));
680
+ const values = keys.map((key) => typedGroup[key]);
681
+ return { keyMap, values };
387
682
  }
388
-
389
- // src/ani/engine.ts
390
- function calculateSegmentState(localTime, segmentDef, dt = 0) {
391
- const t = Math.max(0, Math.min(localTime, segmentDef.duration));
392
- const animeValues = [];
393
- let allComplete = true;
394
- const isMultipleTiming = Array.isArray(segmentDef.timing);
395
- if (isMultipleTiming && segmentDef.timing.length !== segmentDef.from.length) {
396
- throw new TypeError(
397
- `[calculateSegmentState] timing does not correctly set. It requires multiple timing for ${segmentDef.from}, but received ${segmentDef.timing}`
398
- );
683
+ function resolveStateToGroup(state, keyMap) {
684
+ if (!keyMap) {
685
+ return state;
399
686
  }
400
- for (let i = 0; i < segmentDef.from.length; i++) {
401
- const timingFunction = isMultipleTiming ? segmentDef.timing[i] : segmentDef.timing;
402
- const animeResponse = timingFunction.step(t, {
403
- dt,
404
- from: segmentDef.from[i],
405
- to: segmentDef.to[i],
406
- duration: segmentDef.duration
407
- });
408
- animeValues.push(animeResponse.value);
409
- if (!animeResponse.endOfAnimation) {
410
- allComplete = false;
687
+ const group = {};
688
+ for (const [key, index] of keyMap.entries()) {
689
+ group[key] = state[index];
690
+ }
691
+ return group;
692
+ }
693
+ function resolvePlanState(plan, initialValues, keyMap, targetTime, dt = 0) {
694
+ const nextState = [...initialValues];
695
+ let stateAtLastStartTime = [...initialValues];
696
+ for (const segment of plan) {
697
+ if (targetTime < segment.startTime) {
698
+ continue;
699
+ }
700
+ stateAtLastStartTime = [...nextState];
701
+ const { keyMap: segKeyMap, values: toValues } = resolveGroup(
702
+ segment.node.props.to
703
+ );
704
+ const isRecordAni = keyMap !== null;
705
+ let fromValues = [];
706
+ const timings = [];
707
+ const t = segment.node.props.timing;
708
+ const isRecordTiming = t && !(t instanceof TimingFunction);
709
+ if (isRecordAni) {
710
+ for (const key of segKeyMap.keys()) {
711
+ const index = keyMap.get(key);
712
+ fromValues.push(stateAtLastStartTime[index]);
713
+ if (isRecordTiming) {
714
+ timings.push(t[key]);
715
+ }
716
+ }
717
+ } else {
718
+ fromValues = stateAtLastStartTime;
719
+ }
720
+ const localTime = targetTime - segment.startTime;
721
+ const segmentDef = {
722
+ from: fromValues,
723
+ to: toValues,
724
+ duration: segment.node.duration,
725
+ // default fallback = linear
726
+ timing: isRecordAni && isRecordTiming ? timings : t ?? T.linear()
727
+ };
728
+ const result = calculateSegmentState(localTime, segmentDef, dt);
729
+ const finalValues = result.isComplete ? toValues : result.values;
730
+ if (isRecordAni) {
731
+ let i = 0;
732
+ for (const key of segKeyMap.keys()) {
733
+ const stateIndex = keyMap.get(key);
734
+ if (stateIndex !== void 0 && stateIndex !== -1) {
735
+ nextState[stateIndex] = finalValues[i];
736
+ }
737
+ i++;
738
+ }
739
+ } else {
740
+ for (let i = 0; i < finalValues.length; i++) {
741
+ nextState[i] = finalValues[i];
742
+ }
411
743
  }
412
744
  }
413
- return {
414
- values: animeValues,
415
- isComplete: allComplete || isEndOfAnimation(t, segmentDef.duration)
416
- };
745
+ return nextState;
417
746
  }
418
747
 
419
- // src/ani/timeline.ts
420
- var Timeline = class {
748
+ // src/ani/raf/timeline.ts
749
+ var RafAniTimeline = class extends TimelineBase {
421
750
  constructor(rootNode, clock) {
422
- this.rootNode = rootNode;
423
- this._currentExecutionPlan = null;
751
+ super(rootNode);
424
752
  this._masterTime = 0;
753
+ this._delay = 0;
425
754
  this._status = "IDLE";
426
755
  this._currentConfig = null;
427
756
  this._state = [];
428
757
  this._initialState = [];
429
758
  this._repeatCount = 0;
430
759
  this._propertyKeyMap = null;
431
- this._segmentStartStates = /* @__PURE__ */ new Map();
432
760
  this._onUpdateCallbacks = /* @__PURE__ */ new Set();
433
- this.duration = rootNode.duration;
434
- this._baseExecutionPlan = this._constructExecutionPlan(rootNode);
435
761
  this._clock = clock ?? AnimationClock.create();
436
- this.play.bind(this);
437
- this.pause.bind(this);
438
- this.seek.bind(this);
439
- this.resume.bind(this);
440
- this.reset.bind(this);
762
+ this.play = this.play.bind(this);
763
+ this.pause = this.pause.bind(this);
764
+ this.seek = this.seek.bind(this);
765
+ this.resume = this.resume.bind(this);
766
+ this.reset = this.reset.bind(this);
441
767
  }
442
- /**
443
- * Current animation running config.
444
- */
445
768
  get currentConfig() {
446
769
  return this._currentConfig;
447
770
  }
448
- /**
449
- * Resolves a Group (like {x, y}) into keys and values.
450
- */
451
- _resolveGroup(group) {
452
- if (Array.isArray(group)) {
453
- return { keyMap: null, values: group };
454
- }
455
- const keyMap = new Map(Object.keys(group).map((key, i) => [key, i]));
456
- const values = Object.values(group);
457
- return { keyMap, values };
771
+ getCurrentValue() {
772
+ if (this._state.length === 0) return null;
773
+ return resolveStateToGroup(
774
+ this._state,
775
+ this._propertyKeyMap
776
+ );
458
777
  }
459
- /**
460
- * Resolves the internal state (a number array) back into Group.
461
- */
462
- _resolveStateToGroup(state) {
463
- if (!this._propertyKeyMap) {
464
- return state;
465
- }
466
- const group = {};
467
- let i = 0;
468
- for (const key of this._propertyKeyMap.keys()) {
469
- group[key] = state[i];
470
- i++;
778
+ _calculateStateAtTime(targetTime, dt = 0) {
779
+ if (this._initialState.length === 0 || !this._currentExecutionPlan) {
780
+ return [];
471
781
  }
472
- return group;
782
+ return resolvePlanState(
783
+ this._currentExecutionPlan,
784
+ this._initialState,
785
+ this._propertyKeyMap,
786
+ // Using the class property directly
787
+ targetTime,
788
+ dt
789
+ );
473
790
  }
474
- /**
475
- * Compile animation execution plan
476
- */
477
- _constructExecutionPlan(rootNode) {
478
- const plan = [];
479
- rootNode.construct(plan, 0);
480
- return plan;
791
+ notify() {
792
+ for (const subscriber of this._onUpdateCallbacks) {
793
+ subscriber({
794
+ state: resolveStateToGroup(
795
+ this._state,
796
+ this._propertyKeyMap
797
+ ),
798
+ status: this._status
799
+ });
800
+ }
481
801
  }
482
802
  /**
483
- * Calculates the exact state of the animation at point.
803
+ * @private Internal clock subscription callback.
484
804
  */
485
- _calculateStateAtTime(targetTime, dt = 0) {
486
- if (this._initialState.length === 0 || !this._currentExecutionPlan) {
487
- return [];
488
- }
489
- const nextState = [...this._initialState];
490
- let stateAtLastStartTime = [...this._initialState];
491
- for (const segment of this._currentExecutionPlan) {
492
- if (targetTime < segment.startTime) {
493
- continue;
494
- }
495
- if (!segment.node.props.timing) {
496
- throw new Error(
497
- `[Timeline] timing should be provided. Please specify timing using a.timing.(...). Check target segment: ${JSON.stringify(segment, null, 2)}.`,
498
- { cause: segment }
499
- );
500
- }
501
- stateAtLastStartTime = [...nextState];
502
- const { keyMap, values: toValues } = this._resolveGroup(
503
- segment.node.props.to
504
- );
505
- const isRecordAni = this._propertyKeyMap !== null && keyMap !== null;
506
- let fromValues = [];
507
- if (isRecordAni) {
508
- for (const key of keyMap.keys()) {
509
- fromValues.push(
510
- stateAtLastStartTime[this._propertyKeyMap.get(key)]
511
- );
512
- }
513
- } else {
514
- fromValues = stateAtLastStartTime;
515
- }
516
- let finalAnimeValues = [];
517
- const localTime = targetTime - segment.startTime;
518
- const segmentDef = {
519
- from: fromValues,
520
- to: toValues,
521
- duration: segment.node.duration,
522
- timing: segment.node.props.timing
523
- };
524
- const segmentState = calculateSegmentState(
525
- localTime,
526
- segmentDef,
527
- dt
528
- );
529
- if (segmentState.isComplete) {
530
- finalAnimeValues = toValues;
805
+ update(dt) {
806
+ if (this._status !== "PLAYING") return;
807
+ if (this._delay > 0) {
808
+ this._delay -= dt;
809
+ if (this._delay < 0) {
810
+ dt = -this._delay;
811
+ this._delay = 0;
531
812
  } else {
532
- finalAnimeValues = segmentState.values;
813
+ return;
533
814
  }
534
- if (isRecordAni) {
535
- let i = 0;
536
- for (const key of keyMap.keys()) {
537
- const stateIndex = this._propertyKeyMap.get(key);
538
- if (stateIndex === -1) {
539
- continue;
540
- }
541
- nextState[stateIndex] = finalAnimeValues[i];
542
- i++;
543
- }
815
+ }
816
+ this._masterTime += dt;
817
+ if (this._masterTime >= this.duration) this._masterTime = this.duration;
818
+ this._state = this._calculateStateAtTime(this._masterTime, dt);
819
+ this.notify();
820
+ if (isEndOfAnimation(this._masterTime, this.duration)) {
821
+ this._repeatCount += 1;
822
+ const noRepeat = (this._currentConfig.repeat ?? 0) === 0;
823
+ if (noRepeat) {
824
+ this._status = "ENDED";
825
+ this._clock.unsubscribe(this);
826
+ this.notify();
544
827
  } else {
545
- for (let i = 0; i < finalAnimeValues.length; i++) {
546
- nextState[i] = finalAnimeValues[i];
547
- }
828
+ this.play(this._currentConfig);
548
829
  }
549
830
  }
550
- return nextState;
551
- }
552
- _resolveExecutionPlan(keyframes, durations) {
553
- if (!keyframes && !durations) {
554
- return [...this._baseExecutionPlan];
555
- }
556
- const segmentNodes = this._baseExecutionPlan.filter(
557
- (segment) => segment.node.type === "SEGMENT"
558
- );
559
- const segLength = segmentNodes.length;
560
- if (keyframes && keyframes.length !== segLength) {
561
- throw new Error(
562
- `Timeline keyframe mismatch: Expected ${segLength} keyframes, but received ${keyframes.length}.`
563
- );
564
- }
565
- if (durations && durations.length !== segLength) {
566
- throw new Error(
567
- `Timeline keyframe mismatch: Expected ${segLength} durations, but received ${durations.length}.`
568
- );
569
- }
570
- const newPlan = [];
571
- let keyframeIndex = 0;
572
- for (const segment of this._baseExecutionPlan) {
573
- if (segment.node.type === "SEGMENT") {
574
- const dynamicTo = keyframes?.[keyframeIndex];
575
- const dynamicDuration = durations?.[keyframeIndex];
576
- const newSegmentProps = {
577
- ...segment.node.props,
578
- // >> dynamic to
579
- ...dynamicTo && {
580
- to: dynamicTo === "keep" ? segment.node.props.to : dynamicTo
581
- },
582
- // >> dynamic duration
583
- ...dynamicDuration && {
584
- duration: dynamicDuration === "keep" ? segment.node.props.duration : dynamicDuration
585
- }
586
- };
587
- const newSegment = new SegmentNode(
588
- newSegmentProps,
589
- segment.node.id
590
- );
591
- newPlan.push({ ...segment, node: newSegment });
592
- keyframeIndex++;
593
- } else {
594
- newPlan.push({ ...segment });
595
- }
596
- }
597
- return newPlan;
598
- }
599
- notify() {
600
- for (const subscriber of this._onUpdateCallbacks) {
601
- subscriber({
602
- state: this._resolveStateToGroup(this._state),
603
- status: this._status
604
- });
605
- }
606
831
  }
832
+ /**
833
+ * Plays animation.
834
+ * @param config {@link https://developer.mozilla.org/en-US/docs/Web/API/Window/requestAnimationFrame RequestAnimationFrame API} based config.
835
+ * @param canBeIntercepted if `true` animation can be intercepted even if already animation started.
836
+ */
607
837
  play(config, canBeIntercepted = true) {
608
- if (this._status === "PLAYING" && !canBeIntercepted) {
609
- return;
610
- }
611
- const isRepeating = this._currentConfig?.repeat && this._currentConfig?.repeat >= 1;
838
+ if (this._status === "PLAYING" && !canBeIntercepted) return;
839
+ const isRepeating = (this._currentConfig?.repeat ?? 0) >= 1;
612
840
  const savedRepeatCount = isRepeating ? this._repeatCount : 0;
613
841
  this.reset(false);
614
842
  this._repeatCount = savedRepeatCount;
@@ -617,17 +845,20 @@ var Timeline = class {
617
845
  return;
618
846
  }
619
847
  this._currentConfig = config;
848
+ if (this._repeatCount === 0) {
849
+ this._delay = (this._currentConfig.delay ?? 0) * 1e-3;
850
+ }
620
851
  this._currentExecutionPlan = this._resolveExecutionPlan(
621
852
  config.keyframes,
622
853
  config.durations
623
854
  );
624
- const { keyMap: keys, values } = this._resolveGroup(config.from);
625
- this._propertyKeyMap = keys;
855
+ const { keyMap, values } = resolveGroup(config.from);
856
+ this._propertyKeyMap = keyMap;
626
857
  this._state = values;
627
858
  this._initialState = values;
628
859
  this._status = "PLAYING";
629
860
  this._clock.subscribe(this);
630
- this.update(0);
861
+ this.notify();
631
862
  }
632
863
  pause() {
633
864
  this._status = "PAUSED";
@@ -642,16 +873,14 @@ var Timeline = class {
642
873
  this._status = "IDLE";
643
874
  this._currentConfig = null;
644
875
  this._masterTime = 0;
876
+ this._delay = 0;
645
877
  this._state = [];
646
878
  this._initialState = [];
647
879
  this._propertyKeyMap = null;
648
- this._segmentStartStates.clear();
649
880
  this._currentExecutionPlan = null;
650
881
  this._clock.unsubscribe(this);
651
882
  this._repeatCount = 0;
652
- if (notify) {
653
- this.notify();
654
- }
883
+ if (notify) this.notify();
655
884
  }
656
885
  seek(targetTime) {
657
886
  if (this._status === "PLAYING" || this._status === "ENDED") {
@@ -662,78 +891,50 @@ var Timeline = class {
662
891
  this._state = this._calculateStateAtTime(seekTime, 0);
663
892
  this.notify();
664
893
  }
665
- getCurrentValue() {
666
- if (this._state.length === 0) return null;
667
- return this._resolveStateToGroup(this._state);
668
- }
894
+ /**
895
+ * When timeline updates, subscribes on update callback.
896
+ * @param callback Subscription callback.
897
+ * @returns Unsubscribe.
898
+ */
669
899
  onUpdate(callback) {
670
900
  this._onUpdateCallbacks.add(callback);
671
901
  return () => {
672
902
  this._onUpdateCallbacks.delete(callback);
673
903
  };
674
904
  }
675
- update(dt) {
676
- if (this._status !== "PLAYING") {
677
- return;
678
- }
679
- this._masterTime += dt;
680
- if (this._masterTime >= this.duration) {
681
- this._masterTime = this.duration;
682
- }
683
- this._state = this._calculateStateAtTime(this._masterTime, dt);
684
- this.notify();
685
- if (isEndOfAnimation(this._masterTime, this.duration)) {
686
- this._repeatCount += 1;
687
- if (!this._currentConfig) {
688
- throw new Error(
689
- `[Timeline] currentConfig can not be null when update(dt)`
690
- );
691
- }
692
- const noRepeat = (this._currentConfig.repeat ?? 0) === 0;
693
- if (noRepeat) {
694
- this._status = "ENDED";
695
- this._clock.unsubscribe(this);
696
- this.notify();
697
- } else {
698
- this.play(this._currentConfig);
699
- }
700
- }
701
- }
702
905
  };
703
- function timeline(rootNode, clock) {
704
- return new Timeline(rootNode, clock);
906
+ function rafTimeline(rootNode, clock) {
907
+ return new RafAniTimeline(rootNode, clock);
705
908
  }
706
909
 
707
- // src/ani/states.ts
910
+ // src/ani/raf/states.ts
708
911
  function createStates(config) {
709
912
  let State = config.initial;
710
- let Timeline2 = timeline(
913
+ let Timeline = rafTimeline(
711
914
  config.states[State],
712
915
  config.clock
713
916
  );
714
917
  const subs = /* @__PURE__ */ new Set();
715
- const notify = (timeline2) => {
918
+ const notify = (timeline) => {
716
919
  for (const Sub of subs) {
717
- Sub(timeline2);
920
+ Sub(timeline);
718
921
  }
719
922
  };
720
923
  return {
721
- timeline: () => Timeline2,
924
+ timeline: () => Timeline,
925
+ state: () => State,
722
926
  onTimelineChange(callback) {
723
927
  subs.add(callback);
724
928
  return () => subs.delete(callback);
725
929
  },
726
930
  transitionTo(newState, timelineConfig, canBeIntercepted) {
727
- if (!config.states[newState] || State === newState) {
728
- return;
729
- }
730
931
  const from = timelineConfig?.from ?? // 1. config
731
- Timeline2.getCurrentValue() ?? // 2. last value
932
+ Timeline.getCurrentValue() ?? // 2. last value
732
933
  config.initialFrom;
733
934
  State = newState;
734
- Timeline2 = timeline(config.states[State], config.clock);
735
- notify(Timeline2);
736
- Timeline2.play(
935
+ Timeline = rafTimeline(config.states[State], config.clock);
936
+ notify(Timeline);
937
+ Timeline.play(
737
938
  {
738
939
  ...timelineConfig,
739
940
  from
@@ -744,77 +945,6 @@ function createStates(config) {
744
945
  };
745
946
  }
746
947
 
747
- // src/event/manager.ts
748
- var EventManager = class _EventManager {
749
- constructor(supportedEvents) {
750
- this.supportedEvents = supportedEvents;
751
- this._element = null;
752
- this._animeGetter = null;
753
- this.setAnimeGetter = (animeGetter) => {
754
- this._animeGetter = animeGetter;
755
- };
756
- this.eventMap = /* @__PURE__ */ new Map();
757
- this.withAnimeValue = (listener) => {
758
- const withAnime = (e) => {
759
- listener(this.animeGetter(), e);
760
- };
761
- return withAnime;
762
- };
763
- this.add = (eventName, listener, options) => {
764
- const withAnime = this.withAnimeValue(listener);
765
- this.eventMap.set(eventName, withAnime);
766
- this.targetElement.addEventListener(
767
- eventName,
768
- this.eventMap.get(eventName),
769
- options
770
- );
771
- };
772
- this.cleanupOne = (eventName) => {
773
- const removeListener = this.eventMap.get(eventName);
774
- if (!removeListener) return false;
775
- this.targetElement.removeEventListener(eventName, removeListener);
776
- return true;
777
- };
778
- this.cleanupAll = () => {
779
- const clearResponse = [];
780
- for (const evtName of this.eventMap.keys()) {
781
- const res = this.cleanupOne(evtName);
782
- clearResponse.push(res);
783
- }
784
- return clearResponse.some((t) => t === false) === false;
785
- };
786
- this.attach = (handlers) => {
787
- Object.entries(handlers).forEach(([eventKey, handler]) => {
788
- this.add(
789
- _EventManager.getEvtKey(eventKey),
790
- handler
791
- );
792
- });
793
- };
794
- }
795
- get targetElement() {
796
- if (!this._element) throw new Error("EventManger, bind element first");
797
- return this._element;
798
- }
799
- get animeGetter() {
800
- if (!this._animeGetter)
801
- throw new Error("EventManager, animeGetter should be provided");
802
- return this._animeGetter;
803
- }
804
- /**
805
- * get pure `{event_name}`
806
- * @param key onX`{event_name}`
807
- */
808
- static getEvtKey(key) {
809
- const removed = key.substring(2, key.length);
810
- const Capitalized = `${removed[0].toLowerCase()}${removed.substring(1, key.length)}`;
811
- return Capitalized;
812
- }
813
- bind(element) {
814
- this._element = element;
815
- }
816
- };
817
-
818
948
  // src/style/create_sheet.ts
819
949
  var TransformFunctionMap = {
820
950
  // deg
@@ -902,39 +1032,285 @@ function createStyleSheet(animeStyleValue, resolver) {
902
1032
  return styleAccumulator;
903
1033
  }
904
1034
 
1035
+ // src/ani/waapi/compiler/resolver.ts
1036
+ function resolveStateAt(plan, initialFrom, targetTime, dt) {
1037
+ const { keyMap, values: initialValues } = resolveGroup(initialFrom);
1038
+ const rawResultState = resolvePlanState(
1039
+ plan,
1040
+ initialValues,
1041
+ keyMap,
1042
+ targetTime,
1043
+ dt
1044
+ );
1045
+ return resolveStateToGroup(rawResultState, keyMap);
1046
+ }
1047
+
1048
+ // src/ani/waapi/compiler/timing_compiler.ts
1049
+ function compileTiming(timing) {
1050
+ if (!timing) {
1051
+ return "linear";
1052
+ }
1053
+ if (timing instanceof LinearTimingFunction) {
1054
+ return "linear";
1055
+ }
1056
+ if (timing instanceof BezierTimingFunction) {
1057
+ const { p2, p3 } = timing.opt;
1058
+ return `cubic-bezier(${p2.x}, ${p2.y}, ${p3.x}, ${p3.y})`;
1059
+ }
1060
+ return null;
1061
+ }
1062
+
1063
+ // src/ani/waapi/compiler/keyframe_compiler.ts
1064
+ function compileToKeyframes(plan, initialFrom) {
1065
+ if (plan.length === 0) {
1066
+ return [];
1067
+ }
1068
+ const FPS = 60;
1069
+ const SAMPLE_RATE = 1 / FPS;
1070
+ const duration = Math.max(...plan.map((s) => s.endTime));
1071
+ if (duration === 0) {
1072
+ const state = resolveStateAt(plan, initialFrom, 0, SAMPLE_RATE);
1073
+ const style = createStyleSheet(state);
1074
+ return [
1075
+ { offset: 0, ...style },
1076
+ { offset: 1, ...style }
1077
+ ];
1078
+ }
1079
+ const timePoints = /* @__PURE__ */ new Set([0, duration]);
1080
+ for (const seg of plan) {
1081
+ timePoints.add(seg.startTime);
1082
+ timePoints.add(seg.endTime);
1083
+ }
1084
+ const sortedTimes = Array.from(timePoints).sort((a2, b) => a2 - b);
1085
+ const keyframes = [];
1086
+ const getEasingForInterval = (t, nextT) => {
1087
+ const activeSegments = plan.filter(
1088
+ (s) => s.startTime <= t && s.endTime >= nextT
1089
+ );
1090
+ if (activeSegments.length === 0) return "linear";
1091
+ const timings = activeSegments.map((s) => s.node.props.timing).filter((t2) => t2 !== void 0);
1092
+ if (timings.length === 0) return "linear";
1093
+ const firstTiming = timings[0];
1094
+ const allSame = timings.every((t2) => t2 === firstTiming);
1095
+ if (allSame && firstTiming instanceof TimingFunction) {
1096
+ return compileTiming(firstTiming);
1097
+ }
1098
+ return null;
1099
+ };
1100
+ for (let i = 0; i < sortedTimes.length; i++) {
1101
+ const currT = sortedTimes[i];
1102
+ const state = resolveStateAt(plan, initialFrom, currT, SAMPLE_RATE);
1103
+ const style = createStyleSheet(state);
1104
+ const keyframe = {
1105
+ offset: currT / duration,
1106
+ ...style
1107
+ };
1108
+ keyframes.push(keyframe);
1109
+ if (i < sortedTimes.length - 1) {
1110
+ const nextT = sortedTimes[i + 1];
1111
+ const easing = getEasingForInterval(currT, nextT);
1112
+ if (easing === null) {
1113
+ let sampleT = currT + SAMPLE_RATE;
1114
+ while (sampleT < nextT) {
1115
+ const sampleState = resolveStateAt(
1116
+ plan,
1117
+ initialFrom,
1118
+ sampleT,
1119
+ SAMPLE_RATE
1120
+ );
1121
+ const sampleStyle = createStyleSheet(
1122
+ sampleState
1123
+ );
1124
+ keyframes.push({
1125
+ offset: sampleT / duration,
1126
+ ...sampleStyle,
1127
+ easing: "linear"
1128
+ });
1129
+ sampleT += SAMPLE_RATE;
1130
+ }
1131
+ keyframe.easing = "linear";
1132
+ } else {
1133
+ keyframe.easing = easing;
1134
+ }
1135
+ }
1136
+ }
1137
+ return keyframes;
1138
+ }
1139
+
1140
+ // src/ani/waapi/timeline.ts
1141
+ var WebAniTimeline = class extends TimelineBase {
1142
+ constructor(rootNode) {
1143
+ super(rootNode);
1144
+ this._animation = null;
1145
+ this._keyframes = [];
1146
+ }
1147
+ /**
1148
+ * Plays animation.
1149
+ * @param target Target element.
1150
+ * @param config {@link https://developer.mozilla.org/en-US/docs/Web/API/Web_Animations_API Web Animations API} based config.
1151
+ */
1152
+ play(target, config) {
1153
+ if (this._animation) {
1154
+ this._animation.cancel();
1155
+ }
1156
+ this._currentExecutionPlan = this._resolveExecutionPlan(
1157
+ config.keyframes,
1158
+ config.durations
1159
+ );
1160
+ this._keyframes = compileToKeyframes(
1161
+ this._currentExecutionPlan,
1162
+ config.from
1163
+ );
1164
+ if (this._keyframes.length === 0) {
1165
+ return null;
1166
+ }
1167
+ const totalDurationMs = this._currentExecutionPlan.reduce(
1168
+ (max, seg) => Math.max(max, seg.endTime),
1169
+ 0
1170
+ ) * 1e3;
1171
+ const effect = new KeyframeEffect(target, this._keyframes, {
1172
+ duration: totalDurationMs,
1173
+ iterations: config.repeat ?? 1,
1174
+ delay: config.delay ?? 0,
1175
+ fill: "forwards"
1176
+ });
1177
+ this._animation = new Animation(effect, document.timeline);
1178
+ this._animation.play();
1179
+ return this._animation;
1180
+ }
1181
+ pause() {
1182
+ this._animation?.pause();
1183
+ }
1184
+ resume() {
1185
+ this._animation?.play();
1186
+ }
1187
+ reset() {
1188
+ this._animation?.cancel();
1189
+ this._animation = null;
1190
+ }
1191
+ seek(targetTime) {
1192
+ if (this._animation) {
1193
+ this._animation.currentTime = targetTime * 1e3;
1194
+ }
1195
+ }
1196
+ /**
1197
+ * Native animation object.
1198
+ *
1199
+ * @see {@link https://developer.mozilla.org/en-US/docs/Web/API/Animation Animation}.
1200
+ */
1201
+ get nativeAnimation() {
1202
+ return this._animation;
1203
+ }
1204
+ };
1205
+ function webTimeline(rootNode) {
1206
+ return new WebAniTimeline(rootNode);
1207
+ }
1208
+
1209
+ // src/event/manager.ts
1210
+ var EventManager = class _EventManager {
1211
+ constructor(supportedEvents) {
1212
+ this.supportedEvents = supportedEvents;
1213
+ this._element = null;
1214
+ this._animeGetter = null;
1215
+ this.setAnimeGetter = (animeGetter) => {
1216
+ this._animeGetter = animeGetter;
1217
+ };
1218
+ this.eventMap = /* @__PURE__ */ new Map();
1219
+ this.withAnimeValue = (listener) => {
1220
+ const withAnime = (e) => {
1221
+ listener(this.animeGetter(), e);
1222
+ };
1223
+ return withAnime;
1224
+ };
1225
+ this.add = (eventName, listener, options) => {
1226
+ const withAnime = this.withAnimeValue(listener);
1227
+ this.eventMap.set(eventName, withAnime);
1228
+ this.targetElement.addEventListener(
1229
+ eventName,
1230
+ this.eventMap.get(eventName),
1231
+ options
1232
+ );
1233
+ };
1234
+ this.cleanupOne = (eventName) => {
1235
+ const removeListener = this.eventMap.get(eventName);
1236
+ if (!removeListener) return false;
1237
+ this.targetElement.removeEventListener(eventName, removeListener);
1238
+ return true;
1239
+ };
1240
+ this.cleanupAll = () => {
1241
+ const clearResponse = [];
1242
+ for (const evtName of this.eventMap.keys()) {
1243
+ const res = this.cleanupOne(evtName);
1244
+ clearResponse.push(res);
1245
+ }
1246
+ return clearResponse.some((t) => t === false) === false;
1247
+ };
1248
+ this.attach = (handlers) => {
1249
+ Object.entries(handlers).forEach(([eventKey, handler]) => {
1250
+ this.add(
1251
+ _EventManager.getEvtKey(eventKey),
1252
+ handler
1253
+ );
1254
+ });
1255
+ };
1256
+ }
1257
+ get targetElement() {
1258
+ if (!this._element) throw new Error("EventManger, bind element first");
1259
+ return this._element;
1260
+ }
1261
+ get animeGetter() {
1262
+ if (!this._animeGetter)
1263
+ throw new Error("EventManager, animeGetter should be provided");
1264
+ return this._animeGetter;
1265
+ }
1266
+ /**
1267
+ * get pure `{event_name}`
1268
+ * @param key onX`{event_name}`
1269
+ */
1270
+ static getEvtKey(key) {
1271
+ const removed = key.substring(2, key.length);
1272
+ const Capitalized = `${removed[0].toLowerCase()}${removed.substring(1, key.length)}`;
1273
+ return Capitalized;
1274
+ }
1275
+ bind(element) {
1276
+ this._element = element;
1277
+ }
1278
+ };
1279
+
905
1280
  // src/index.ts
906
1281
  var a = {
907
1282
  timing: T,
1283
+ dynamicTimeline: rafTimeline,
1284
+ timeline: webTimeline,
1285
+ /**
1286
+ * Create animation segment.
1287
+ */
908
1288
  ani,
909
- createStates,
1289
+ /**
1290
+ * Add delay
1291
+ */
910
1292
  delay,
911
1293
  loop,
912
1294
  parallel,
913
1295
  sequence,
914
1296
  stagger,
915
- timeline
1297
+ createStates
916
1298
  };
917
1299
  export {
918
1300
  AnimationClock,
919
- AnimationNode,
920
- CompositionNode,
1301
+ BezierTimingFunction,
921
1302
  EventManager,
922
1303
  LinearTimingFunction,
923
- ParallelNode,
924
- SegmentNode,
925
- SequenceNode,
926
- StaggerNode,
1304
+ RafAniTimeline,
927
1305
  T,
928
- Timeline,
1306
+ TimelineBase,
929
1307
  TimingFunction,
1308
+ WebAniTimeline,
930
1309
  a,
931
- ani,
1310
+ calculateSegmentState,
1311
+ compileToKeyframes,
932
1312
  createStates,
933
1313
  createStyleSheet,
934
- delay,
935
- loop,
936
- parallel,
937
- sequence,
938
- stagger,
939
- timeline
1314
+ rafTimeline,
1315
+ webTimeline
940
1316
  };