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