@freestylejs/ani-core 1.2.1 → 1.3.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 +108 -39
- package/dist/index.d.cts +32 -3
- package/dist/index.d.ts +32 -3
- package/dist/index.js +106 -39
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -34,7 +34,9 @@ __export(src_exports, {
|
|
|
34
34
|
compileToKeyframes: () => compileToKeyframes,
|
|
35
35
|
createStates: () => createStates,
|
|
36
36
|
createStyleSheet: () => createStyleSheet,
|
|
37
|
+
normalizeRepeatCount: () => normalizeRepeatCount,
|
|
37
38
|
rafTimeline: () => rafTimeline,
|
|
39
|
+
toIterationCount: () => toIterationCount,
|
|
38
40
|
webTimeline: () => webTimeline
|
|
39
41
|
});
|
|
40
42
|
module.exports = __toCommonJS(src_exports);
|
|
@@ -436,6 +438,14 @@ function ani(props, id) {
|
|
|
436
438
|
}
|
|
437
439
|
|
|
438
440
|
// src/nodes/composition.ts
|
|
441
|
+
function cloneCompositionNodeWithChildren(source, children) {
|
|
442
|
+
const clone = Object.create(
|
|
443
|
+
Object.getPrototypeOf(source)
|
|
444
|
+
);
|
|
445
|
+
Object.assign(clone, source);
|
|
446
|
+
clone.children = children;
|
|
447
|
+
return clone;
|
|
448
|
+
}
|
|
439
449
|
var CompositionNode = class _CompositionNode extends AnimationNode {
|
|
440
450
|
constructor(children, timing, id) {
|
|
441
451
|
super(id);
|
|
@@ -453,8 +463,11 @@ var CompositionNode = class _CompositionNode extends AnimationNode {
|
|
|
453
463
|
);
|
|
454
464
|
}
|
|
455
465
|
if (child instanceof _CompositionNode) {
|
|
456
|
-
|
|
457
|
-
return
|
|
466
|
+
const adjustedChildren = adjustTiming(child.children);
|
|
467
|
+
return cloneCompositionNodeWithChildren(
|
|
468
|
+
child,
|
|
469
|
+
adjustedChildren
|
|
470
|
+
);
|
|
458
471
|
}
|
|
459
472
|
return child;
|
|
460
473
|
});
|
|
@@ -585,6 +598,17 @@ function stagger(children, offset, timing, id) {
|
|
|
585
598
|
}
|
|
586
599
|
|
|
587
600
|
// src/ani/core/interface/timeline_interface.ts
|
|
601
|
+
function normalizeRepeatCount(repeat) {
|
|
602
|
+
if (repeat === Infinity) return Infinity;
|
|
603
|
+
if (!Number.isFinite(repeat) || repeat === void 0 || repeat <= 0) {
|
|
604
|
+
return 0;
|
|
605
|
+
}
|
|
606
|
+
return Math.floor(repeat);
|
|
607
|
+
}
|
|
608
|
+
function toIterationCount(repeat) {
|
|
609
|
+
const normalized = normalizeRepeatCount(repeat);
|
|
610
|
+
return normalized === Infinity ? Infinity : normalized + 1;
|
|
611
|
+
}
|
|
588
612
|
var TimelineBase = class {
|
|
589
613
|
constructor(rootNode) {
|
|
590
614
|
this.rootNode = rootNode;
|
|
@@ -634,10 +658,10 @@ var TimelineBase = class {
|
|
|
634
658
|
const dynamicDuration = durations?.[keyframeIndex];
|
|
635
659
|
const newSegmentProps = {
|
|
636
660
|
...segment.node.props,
|
|
637
|
-
...dynamicTo && dynamicTo !== "keep" && {
|
|
661
|
+
...dynamicTo !== void 0 && dynamicTo !== "keep" && {
|
|
638
662
|
to: dynamicTo
|
|
639
663
|
},
|
|
640
|
-
...dynamicDuration && dynamicDuration !== "keep" && {
|
|
664
|
+
...dynamicDuration !== void 0 && dynamicDuration !== "keep" && {
|
|
641
665
|
duration: dynamicDuration
|
|
642
666
|
}
|
|
643
667
|
};
|
|
@@ -683,9 +707,20 @@ var AnimationClock = class _AnimationClock {
|
|
|
683
707
|
* @returns clock
|
|
684
708
|
*/
|
|
685
709
|
static create(maxDeltaTime = 1 / 10) {
|
|
686
|
-
_AnimationClock.clock
|
|
710
|
+
if (!_AnimationClock.clock) {
|
|
711
|
+
_AnimationClock.clock = new _AnimationClock(maxDeltaTime);
|
|
712
|
+
}
|
|
687
713
|
return _AnimationClock.clock;
|
|
688
714
|
}
|
|
715
|
+
/**
|
|
716
|
+
* Reconfigure singleton clock.
|
|
717
|
+
* If not created yet, creates one with provided maxDeltaTime.
|
|
718
|
+
*/
|
|
719
|
+
static configure(maxDeltaTime) {
|
|
720
|
+
const clock = _AnimationClock.create(maxDeltaTime);
|
|
721
|
+
clock.maxDeltaTime = maxDeltaTime;
|
|
722
|
+
return clock;
|
|
723
|
+
}
|
|
689
724
|
subscribe(animatable) {
|
|
690
725
|
this.subscribers.add(animatable);
|
|
691
726
|
if (!this.animationFrameId) {
|
|
@@ -796,7 +831,7 @@ var RafAniTimeline = class extends TimelineBase {
|
|
|
796
831
|
this._currentConfig = null;
|
|
797
832
|
this._state = [];
|
|
798
833
|
this._initialState = [];
|
|
799
|
-
this.
|
|
834
|
+
this._remainingRepeats = 0;
|
|
800
835
|
this._propertyKeyMap = null;
|
|
801
836
|
this._onUpdateCallbacks = /* @__PURE__ */ new Set();
|
|
802
837
|
this._clock = clock ?? AnimationClock.create();
|
|
@@ -829,6 +864,26 @@ var RafAniTimeline = class extends TimelineBase {
|
|
|
829
864
|
dt
|
|
830
865
|
);
|
|
831
866
|
}
|
|
867
|
+
_resolveRuntimeState(config) {
|
|
868
|
+
this._currentExecutionPlan = this._resolveExecutionPlan(
|
|
869
|
+
config.keyframes,
|
|
870
|
+
config.durations
|
|
871
|
+
);
|
|
872
|
+
const { keyMap, values } = resolveGroup(config.from);
|
|
873
|
+
this._propertyKeyMap = keyMap;
|
|
874
|
+
this._state = values;
|
|
875
|
+
this._initialState = values;
|
|
876
|
+
this._masterTime = 0;
|
|
877
|
+
}
|
|
878
|
+
_restartForRepeat() {
|
|
879
|
+
if (!this._currentConfig) {
|
|
880
|
+
return;
|
|
881
|
+
}
|
|
882
|
+
this._delay = 0;
|
|
883
|
+
this._resolveRuntimeState(this._currentConfig);
|
|
884
|
+
this._status = "PLAYING";
|
|
885
|
+
this.notify();
|
|
886
|
+
}
|
|
832
887
|
notify() {
|
|
833
888
|
for (const subscriber of this._onUpdateCallbacks) {
|
|
834
889
|
subscriber({
|
|
@@ -859,14 +914,15 @@ var RafAniTimeline = class extends TimelineBase {
|
|
|
859
914
|
this._state = this._calculateStateAtTime(this._masterTime, dt);
|
|
860
915
|
this.notify();
|
|
861
916
|
if (isEndOfAnimation(this._masterTime, this.duration)) {
|
|
862
|
-
this.
|
|
863
|
-
|
|
864
|
-
|
|
917
|
+
if (this._remainingRepeats === Infinity || this._remainingRepeats > 0) {
|
|
918
|
+
if (this._remainingRepeats !== Infinity) {
|
|
919
|
+
this._remainingRepeats -= 1;
|
|
920
|
+
}
|
|
921
|
+
this._restartForRepeat();
|
|
922
|
+
} else {
|
|
865
923
|
this._status = "ENDED";
|
|
866
924
|
this._clock.unsubscribe(this);
|
|
867
925
|
this.notify();
|
|
868
|
-
} else {
|
|
869
|
-
this.play(this._currentConfig);
|
|
870
926
|
}
|
|
871
927
|
}
|
|
872
928
|
}
|
|
@@ -877,27 +933,11 @@ var RafAniTimeline = class extends TimelineBase {
|
|
|
877
933
|
*/
|
|
878
934
|
play(config, canBeIntercepted = true) {
|
|
879
935
|
if (this._status === "PLAYING" && !canBeIntercepted) return;
|
|
880
|
-
|
|
881
|
-
const savedRepeatCount = isRepeating ? this._repeatCount : 0;
|
|
882
|
-
const isPlaying = this._status === "PLAYING";
|
|
883
|
-
this.reset(false, !isPlaying);
|
|
884
|
-
this._repeatCount = savedRepeatCount;
|
|
885
|
-
if (isRepeating && this._repeatCount >= config.repeat) {
|
|
886
|
-
this._repeatCount = 0;
|
|
887
|
-
return;
|
|
888
|
-
}
|
|
936
|
+
this.reset(false, true);
|
|
889
937
|
this._currentConfig = config;
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
this._currentExecutionPlan = this._resolveExecutionPlan(
|
|
894
|
-
config.keyframes,
|
|
895
|
-
config.durations
|
|
896
|
-
);
|
|
897
|
-
const { keyMap, values } = resolveGroup(config.from);
|
|
898
|
-
this._propertyKeyMap = keyMap;
|
|
899
|
-
this._state = values;
|
|
900
|
-
this._initialState = values;
|
|
938
|
+
this._remainingRepeats = normalizeRepeatCount(config.repeat);
|
|
939
|
+
this._delay = (this._currentConfig.delay ?? 0) * 1e-3;
|
|
940
|
+
this._resolveRuntimeState(config);
|
|
901
941
|
this._status = "PLAYING";
|
|
902
942
|
this._clock.subscribe(this);
|
|
903
943
|
this.notify();
|
|
@@ -923,7 +963,7 @@ var RafAniTimeline = class extends TimelineBase {
|
|
|
923
963
|
if (unsubscribeClock) {
|
|
924
964
|
this._clock.unsubscribe(this);
|
|
925
965
|
}
|
|
926
|
-
this.
|
|
966
|
+
this._remainingRepeats = 0;
|
|
927
967
|
if (notify) this.notify();
|
|
928
968
|
}
|
|
929
969
|
seek(targetTime) {
|
|
@@ -972,9 +1012,11 @@ function createStates(config) {
|
|
|
972
1012
|
return () => subs.delete(callback);
|
|
973
1013
|
},
|
|
974
1014
|
transitionTo(newState, timelineConfig, canBeIntercepted) {
|
|
1015
|
+
const previousTimeline = Timeline;
|
|
975
1016
|
const from = timelineConfig?.from ?? // 1. config
|
|
976
1017
|
Timeline.getCurrentValue() ?? // 2. last value
|
|
977
1018
|
config.initialFrom;
|
|
1019
|
+
previousTimeline.reset(false);
|
|
978
1020
|
State = newState;
|
|
979
1021
|
Timeline = rafTimeline(config.states[State], config.clock);
|
|
980
1022
|
notify(Timeline);
|
|
@@ -1105,7 +1147,7 @@ function compileTiming(timing) {
|
|
|
1105
1147
|
}
|
|
1106
1148
|
|
|
1107
1149
|
// src/ani/waapi/compiler/keyframe_compiler.ts
|
|
1108
|
-
function compileToKeyframes(plan, initialFrom) {
|
|
1150
|
+
function compileToKeyframes(plan, initialFrom, resolver) {
|
|
1109
1151
|
if (plan.length === 0) {
|
|
1110
1152
|
return [];
|
|
1111
1153
|
}
|
|
@@ -1114,7 +1156,10 @@ function compileToKeyframes(plan, initialFrom) {
|
|
|
1114
1156
|
const duration = Math.max(...plan.map((s) => s.endTime));
|
|
1115
1157
|
if (duration === 0) {
|
|
1116
1158
|
const state = resolveStateAt(plan, initialFrom, 0, SAMPLE_RATE);
|
|
1117
|
-
const style = createStyleSheet(
|
|
1159
|
+
const style = createStyleSheet(
|
|
1160
|
+
state,
|
|
1161
|
+
resolver
|
|
1162
|
+
);
|
|
1118
1163
|
return [
|
|
1119
1164
|
{ offset: 0, ...style },
|
|
1120
1165
|
{ offset: 1, ...style }
|
|
@@ -1144,7 +1189,10 @@ function compileToKeyframes(plan, initialFrom) {
|
|
|
1144
1189
|
for (let i = 0; i < sortedTimes.length; i++) {
|
|
1145
1190
|
const currT = sortedTimes[i];
|
|
1146
1191
|
const state = resolveStateAt(plan, initialFrom, currT, SAMPLE_RATE);
|
|
1147
|
-
const style = createStyleSheet(
|
|
1192
|
+
const style = createStyleSheet(
|
|
1193
|
+
state,
|
|
1194
|
+
resolver
|
|
1195
|
+
);
|
|
1148
1196
|
const keyframe = {
|
|
1149
1197
|
offset: currT / duration,
|
|
1150
1198
|
...style
|
|
@@ -1163,7 +1211,8 @@ function compileToKeyframes(plan, initialFrom) {
|
|
|
1163
1211
|
SAMPLE_RATE
|
|
1164
1212
|
);
|
|
1165
1213
|
const sampleStyle = createStyleSheet(
|
|
1166
|
-
sampleState
|
|
1214
|
+
sampleState,
|
|
1215
|
+
resolver
|
|
1167
1216
|
);
|
|
1168
1217
|
keyframes.push({
|
|
1169
1218
|
offset: sampleT / duration,
|
|
@@ -1203,7 +1252,8 @@ var WebAniTimeline = class extends TimelineBase {
|
|
|
1203
1252
|
);
|
|
1204
1253
|
this._keyframes = compileToKeyframes(
|
|
1205
1254
|
this._currentExecutionPlan,
|
|
1206
|
-
config.from
|
|
1255
|
+
config.from,
|
|
1256
|
+
config.propertyResolver
|
|
1207
1257
|
);
|
|
1208
1258
|
if (this._keyframes.length === 0) {
|
|
1209
1259
|
return null;
|
|
@@ -1214,9 +1264,10 @@ var WebAniTimeline = class extends TimelineBase {
|
|
|
1214
1264
|
) * 1e3;
|
|
1215
1265
|
const effect = new KeyframeEffect(target, this._keyframes, {
|
|
1216
1266
|
duration: totalDurationMs,
|
|
1217
|
-
iterations: config.repeat
|
|
1267
|
+
iterations: toIterationCount(config.repeat),
|
|
1218
1268
|
delay: config.delay ?? 0,
|
|
1219
|
-
fill: "forwards"
|
|
1269
|
+
fill: "forwards",
|
|
1270
|
+
...config.keyframeEffect
|
|
1220
1271
|
});
|
|
1221
1272
|
this._animation = new Animation(effect, document.timeline);
|
|
1222
1273
|
this._animation.play();
|
|
@@ -1232,6 +1283,12 @@ var WebAniTimeline = class extends TimelineBase {
|
|
|
1232
1283
|
this._animation?.cancel();
|
|
1233
1284
|
this._animation = null;
|
|
1234
1285
|
}
|
|
1286
|
+
/**
|
|
1287
|
+
* Alias of reset() for WAAPI naming parity.
|
|
1288
|
+
*/
|
|
1289
|
+
cancel() {
|
|
1290
|
+
this.reset();
|
|
1291
|
+
}
|
|
1235
1292
|
seek(targetTime) {
|
|
1236
1293
|
if (this._animation) {
|
|
1237
1294
|
this._animation.currentTime = targetTime * 1e3;
|
|
@@ -1279,6 +1336,7 @@ var EventManager = class _EventManager {
|
|
|
1279
1336
|
const removeListener = this.eventMap.get(eventName);
|
|
1280
1337
|
if (!removeListener) return false;
|
|
1281
1338
|
this.targetElement.removeEventListener(eventName, removeListener);
|
|
1339
|
+
this.eventMap.delete(eventName);
|
|
1282
1340
|
return true;
|
|
1283
1341
|
};
|
|
1284
1342
|
this.cleanupAll = () => {
|
|
@@ -1324,8 +1382,17 @@ var EventManager = class _EventManager {
|
|
|
1324
1382
|
// src/index.ts
|
|
1325
1383
|
var a = {
|
|
1326
1384
|
timing: T,
|
|
1385
|
+
/**
|
|
1386
|
+
* @deprecated Use `rafTimeline` alias for explicit engine naming.
|
|
1387
|
+
*/
|
|
1327
1388
|
dynamicTimeline: rafTimeline,
|
|
1389
|
+
/**
|
|
1390
|
+
* @deprecated Use `waapiTimeline` alias for explicit engine naming.
|
|
1391
|
+
*/
|
|
1328
1392
|
timeline: webTimeline,
|
|
1393
|
+
webTimeline,
|
|
1394
|
+
rafTimeline,
|
|
1395
|
+
waapiTimeline: webTimeline,
|
|
1329
1396
|
/**
|
|
1330
1397
|
* Create animation segment.
|
|
1331
1398
|
*/
|
|
@@ -1356,6 +1423,8 @@ var a = {
|
|
|
1356
1423
|
compileToKeyframes,
|
|
1357
1424
|
createStates,
|
|
1358
1425
|
createStyleSheet,
|
|
1426
|
+
normalizeRepeatCount,
|
|
1359
1427
|
rafTimeline,
|
|
1428
|
+
toIterationCount,
|
|
1360
1429
|
webTimeline
|
|
1361
1430
|
});
|
package/dist/index.d.cts
CHANGED
|
@@ -467,6 +467,15 @@ interface TimelineCommonConfig<G extends Groupable> {
|
|
|
467
467
|
*/
|
|
468
468
|
propertyResolver?: G extends AnimePrimitive ? never : Resolver<G>;
|
|
469
469
|
}
|
|
470
|
+
/**
|
|
471
|
+
* Normalize repeat count as "additional iterations after first play".
|
|
472
|
+
*/
|
|
473
|
+
declare function normalizeRepeatCount(repeat?: number): number;
|
|
474
|
+
/**
|
|
475
|
+
* Converts repeat count to WAAPI iteration count.
|
|
476
|
+
* repeat=0 -> iterations=1, repeat=1 -> iterations=2
|
|
477
|
+
*/
|
|
478
|
+
declare function toIterationCount(repeat?: number): number;
|
|
470
479
|
declare abstract class TimelineBase<G extends Groupable> {
|
|
471
480
|
protected readonly rootNode: AnimationNode<G>;
|
|
472
481
|
readonly duration: number;
|
|
@@ -527,6 +536,11 @@ declare class AnimationClock implements AnimationClockInterface {
|
|
|
527
536
|
* @returns clock
|
|
528
537
|
*/
|
|
529
538
|
static create(maxDeltaTime?: number): AnimationClock;
|
|
539
|
+
/**
|
|
540
|
+
* Reconfigure singleton clock.
|
|
541
|
+
* If not created yet, creates one with provided maxDeltaTime.
|
|
542
|
+
*/
|
|
543
|
+
static configure(maxDeltaTime: number): AnimationClock;
|
|
530
544
|
private constructor();
|
|
531
545
|
subscribe(animatable: Animatable): void;
|
|
532
546
|
unsubscribe(animatable: Animatable): void;
|
|
@@ -561,12 +575,14 @@ declare class RafAniTimeline<G extends Groupable, Ctx = any> extends TimelineBas
|
|
|
561
575
|
get currentConfig(): RafTimelineConfig<G, Ctx> | null;
|
|
562
576
|
private _state;
|
|
563
577
|
private _initialState;
|
|
564
|
-
private
|
|
578
|
+
private _remainingRepeats;
|
|
565
579
|
private _propertyKeyMap;
|
|
566
580
|
private _onUpdateCallbacks;
|
|
567
581
|
constructor(rootNode: AnimationNode<G>, clock?: AnimationClockInterface);
|
|
568
582
|
getCurrentValue(): AniGroup<G> | null;
|
|
569
583
|
private _calculateStateAtTime;
|
|
584
|
+
private _resolveRuntimeState;
|
|
585
|
+
private _restartForRepeat;
|
|
570
586
|
private notify;
|
|
571
587
|
/**
|
|
572
588
|
* @private Internal clock subscription callback.
|
|
@@ -659,7 +675,7 @@ interface WebAniKeyframe extends Record<string, string | number | null> {
|
|
|
659
675
|
* @param plan The resolved execution plan (from TimelineBase).
|
|
660
676
|
* @param initialFrom The initial state (values).
|
|
661
677
|
*/
|
|
662
|
-
declare function compileToKeyframes<G extends Groupable>(plan: ExecutionPlan<G>, initialFrom: G): WebAniKeyframe[];
|
|
678
|
+
declare function compileToKeyframes<G extends Groupable>(plan: ExecutionPlan<G>, initialFrom: G, resolver?: Resolver<Record<string, number>>): WebAniKeyframe[];
|
|
663
679
|
|
|
664
680
|
interface WebAniTimelineConfig<G extends Groupable> extends TimelineCommonConfig<G> {
|
|
665
681
|
/**
|
|
@@ -682,6 +698,10 @@ declare class WebAniTimeline<G extends Groupable> extends TimelineBase<G> {
|
|
|
682
698
|
pause(): void;
|
|
683
699
|
resume(): void;
|
|
684
700
|
reset(): void;
|
|
701
|
+
/**
|
|
702
|
+
* Alias of reset() for WAAPI naming parity.
|
|
703
|
+
*/
|
|
704
|
+
cancel(): void;
|
|
685
705
|
seek(targetTime: number): void;
|
|
686
706
|
/**
|
|
687
707
|
* Native animation object.
|
|
@@ -759,8 +779,17 @@ declare const a: {
|
|
|
759
779
|
readonly easeOut: () => BezierTimingFunction;
|
|
760
780
|
readonly easeInOut: () => BezierTimingFunction;
|
|
761
781
|
};
|
|
782
|
+
/**
|
|
783
|
+
* @deprecated Use `rafTimeline` alias for explicit engine naming.
|
|
784
|
+
*/
|
|
762
785
|
readonly dynamicTimeline: typeof rafTimeline;
|
|
786
|
+
/**
|
|
787
|
+
* @deprecated Use `waapiTimeline` alias for explicit engine naming.
|
|
788
|
+
*/
|
|
763
789
|
readonly timeline: typeof webTimeline;
|
|
790
|
+
readonly webTimeline: typeof webTimeline;
|
|
791
|
+
readonly rafTimeline: typeof rafTimeline;
|
|
792
|
+
readonly waapiTimeline: typeof webTimeline;
|
|
764
793
|
/**
|
|
765
794
|
* Create animation segment.
|
|
766
795
|
*/
|
|
@@ -776,4 +805,4 @@ declare const a: {
|
|
|
776
805
|
readonly createStates: typeof createStates;
|
|
777
806
|
};
|
|
778
807
|
|
|
779
|
-
export { type AniGroup, type AniRefContext, type AniRefProps, type Animatable, AnimationClock, type AnimationClockInterface, type AnimationStateShape, type AnimePrimitive, BezierTimingFunction, type BezierTimingFunctionOpt, type Coord, type EventHandler, type EventHandlerRegistration, type EventKey, EventManager, type ExecutionPlan, type ExecutionSegment, type GetTimeline, type Groupable, type GroupableRecord, type GroupableRecordKey, LinearTimingFunction, type OnUpdateCallback, RafAniTimeline, type RafTimelineConfig, type Resolver, type SegmentDefinition, type SegmentState, type SegmentTiming, type StateController, type StateProps, type StylesheetSupportedLiteral, T, TimelineBase, type TimelineCommonConfig, TimingFunction, type TimingFunctionContext, type WebAniKeyframe, WebAniTimeline, type WebAniTimelineConfig, a, calculateSegmentState, compileToKeyframes, createStates, createStyleSheet, rafTimeline, webTimeline };
|
|
808
|
+
export { type AniGroup, type AniRefContext, type AniRefProps, type Animatable, AnimationClock, type AnimationClockInterface, type AnimationStateShape, type AnimePrimitive, BezierTimingFunction, type BezierTimingFunctionOpt, type Coord, type EventHandler, type EventHandlerRegistration, type EventKey, EventManager, type ExecutionPlan, type ExecutionSegment, type GetTimeline, type Groupable, type GroupableRecord, type GroupableRecordKey, LinearTimingFunction, type OnUpdateCallback, RafAniTimeline, type RafTimelineConfig, type Resolver, type SegmentDefinition, type SegmentState, type SegmentTiming, type StateController, type StateProps, type StylesheetSupportedLiteral, T, TimelineBase, type TimelineCommonConfig, TimingFunction, type TimingFunctionContext, type WebAniKeyframe, WebAniTimeline, type WebAniTimelineConfig, a, calculateSegmentState, compileToKeyframes, createStates, createStyleSheet, normalizeRepeatCount, rafTimeline, toIterationCount, webTimeline };
|
package/dist/index.d.ts
CHANGED
|
@@ -467,6 +467,15 @@ interface TimelineCommonConfig<G extends Groupable> {
|
|
|
467
467
|
*/
|
|
468
468
|
propertyResolver?: G extends AnimePrimitive ? never : Resolver<G>;
|
|
469
469
|
}
|
|
470
|
+
/**
|
|
471
|
+
* Normalize repeat count as "additional iterations after first play".
|
|
472
|
+
*/
|
|
473
|
+
declare function normalizeRepeatCount(repeat?: number): number;
|
|
474
|
+
/**
|
|
475
|
+
* Converts repeat count to WAAPI iteration count.
|
|
476
|
+
* repeat=0 -> iterations=1, repeat=1 -> iterations=2
|
|
477
|
+
*/
|
|
478
|
+
declare function toIterationCount(repeat?: number): number;
|
|
470
479
|
declare abstract class TimelineBase<G extends Groupable> {
|
|
471
480
|
protected readonly rootNode: AnimationNode<G>;
|
|
472
481
|
readonly duration: number;
|
|
@@ -527,6 +536,11 @@ declare class AnimationClock implements AnimationClockInterface {
|
|
|
527
536
|
* @returns clock
|
|
528
537
|
*/
|
|
529
538
|
static create(maxDeltaTime?: number): AnimationClock;
|
|
539
|
+
/**
|
|
540
|
+
* Reconfigure singleton clock.
|
|
541
|
+
* If not created yet, creates one with provided maxDeltaTime.
|
|
542
|
+
*/
|
|
543
|
+
static configure(maxDeltaTime: number): AnimationClock;
|
|
530
544
|
private constructor();
|
|
531
545
|
subscribe(animatable: Animatable): void;
|
|
532
546
|
unsubscribe(animatable: Animatable): void;
|
|
@@ -561,12 +575,14 @@ declare class RafAniTimeline<G extends Groupable, Ctx = any> extends TimelineBas
|
|
|
561
575
|
get currentConfig(): RafTimelineConfig<G, Ctx> | null;
|
|
562
576
|
private _state;
|
|
563
577
|
private _initialState;
|
|
564
|
-
private
|
|
578
|
+
private _remainingRepeats;
|
|
565
579
|
private _propertyKeyMap;
|
|
566
580
|
private _onUpdateCallbacks;
|
|
567
581
|
constructor(rootNode: AnimationNode<G>, clock?: AnimationClockInterface);
|
|
568
582
|
getCurrentValue(): AniGroup<G> | null;
|
|
569
583
|
private _calculateStateAtTime;
|
|
584
|
+
private _resolveRuntimeState;
|
|
585
|
+
private _restartForRepeat;
|
|
570
586
|
private notify;
|
|
571
587
|
/**
|
|
572
588
|
* @private Internal clock subscription callback.
|
|
@@ -659,7 +675,7 @@ interface WebAniKeyframe extends Record<string, string | number | null> {
|
|
|
659
675
|
* @param plan The resolved execution plan (from TimelineBase).
|
|
660
676
|
* @param initialFrom The initial state (values).
|
|
661
677
|
*/
|
|
662
|
-
declare function compileToKeyframes<G extends Groupable>(plan: ExecutionPlan<G>, initialFrom: G): WebAniKeyframe[];
|
|
678
|
+
declare function compileToKeyframes<G extends Groupable>(plan: ExecutionPlan<G>, initialFrom: G, resolver?: Resolver<Record<string, number>>): WebAniKeyframe[];
|
|
663
679
|
|
|
664
680
|
interface WebAniTimelineConfig<G extends Groupable> extends TimelineCommonConfig<G> {
|
|
665
681
|
/**
|
|
@@ -682,6 +698,10 @@ declare class WebAniTimeline<G extends Groupable> extends TimelineBase<G> {
|
|
|
682
698
|
pause(): void;
|
|
683
699
|
resume(): void;
|
|
684
700
|
reset(): void;
|
|
701
|
+
/**
|
|
702
|
+
* Alias of reset() for WAAPI naming parity.
|
|
703
|
+
*/
|
|
704
|
+
cancel(): void;
|
|
685
705
|
seek(targetTime: number): void;
|
|
686
706
|
/**
|
|
687
707
|
* Native animation object.
|
|
@@ -759,8 +779,17 @@ declare const a: {
|
|
|
759
779
|
readonly easeOut: () => BezierTimingFunction;
|
|
760
780
|
readonly easeInOut: () => BezierTimingFunction;
|
|
761
781
|
};
|
|
782
|
+
/**
|
|
783
|
+
* @deprecated Use `rafTimeline` alias for explicit engine naming.
|
|
784
|
+
*/
|
|
762
785
|
readonly dynamicTimeline: typeof rafTimeline;
|
|
786
|
+
/**
|
|
787
|
+
* @deprecated Use `waapiTimeline` alias for explicit engine naming.
|
|
788
|
+
*/
|
|
763
789
|
readonly timeline: typeof webTimeline;
|
|
790
|
+
readonly webTimeline: typeof webTimeline;
|
|
791
|
+
readonly rafTimeline: typeof rafTimeline;
|
|
792
|
+
readonly waapiTimeline: typeof webTimeline;
|
|
764
793
|
/**
|
|
765
794
|
* Create animation segment.
|
|
766
795
|
*/
|
|
@@ -776,4 +805,4 @@ declare const a: {
|
|
|
776
805
|
readonly createStates: typeof createStates;
|
|
777
806
|
};
|
|
778
807
|
|
|
779
|
-
export { type AniGroup, type AniRefContext, type AniRefProps, type Animatable, AnimationClock, type AnimationClockInterface, type AnimationStateShape, type AnimePrimitive, BezierTimingFunction, type BezierTimingFunctionOpt, type Coord, type EventHandler, type EventHandlerRegistration, type EventKey, EventManager, type ExecutionPlan, type ExecutionSegment, type GetTimeline, type Groupable, type GroupableRecord, type GroupableRecordKey, LinearTimingFunction, type OnUpdateCallback, RafAniTimeline, type RafTimelineConfig, type Resolver, type SegmentDefinition, type SegmentState, type SegmentTiming, type StateController, type StateProps, type StylesheetSupportedLiteral, T, TimelineBase, type TimelineCommonConfig, TimingFunction, type TimingFunctionContext, type WebAniKeyframe, WebAniTimeline, type WebAniTimelineConfig, a, calculateSegmentState, compileToKeyframes, createStates, createStyleSheet, rafTimeline, webTimeline };
|
|
808
|
+
export { type AniGroup, type AniRefContext, type AniRefProps, type Animatable, AnimationClock, type AnimationClockInterface, type AnimationStateShape, type AnimePrimitive, BezierTimingFunction, type BezierTimingFunctionOpt, type Coord, type EventHandler, type EventHandlerRegistration, type EventKey, EventManager, type ExecutionPlan, type ExecutionSegment, type GetTimeline, type Groupable, type GroupableRecord, type GroupableRecordKey, LinearTimingFunction, type OnUpdateCallback, RafAniTimeline, type RafTimelineConfig, type Resolver, type SegmentDefinition, type SegmentState, type SegmentTiming, type StateController, type StateProps, type StylesheetSupportedLiteral, T, TimelineBase, type TimelineCommonConfig, TimingFunction, type TimingFunctionContext, type WebAniKeyframe, WebAniTimeline, type WebAniTimelineConfig, a, calculateSegmentState, compileToKeyframes, createStates, createStyleSheet, normalizeRepeatCount, rafTimeline, toIterationCount, webTimeline };
|
package/dist/index.js
CHANGED
|
@@ -395,6 +395,14 @@ function ani(props, id) {
|
|
|
395
395
|
}
|
|
396
396
|
|
|
397
397
|
// src/nodes/composition.ts
|
|
398
|
+
function cloneCompositionNodeWithChildren(source, children) {
|
|
399
|
+
const clone = Object.create(
|
|
400
|
+
Object.getPrototypeOf(source)
|
|
401
|
+
);
|
|
402
|
+
Object.assign(clone, source);
|
|
403
|
+
clone.children = children;
|
|
404
|
+
return clone;
|
|
405
|
+
}
|
|
398
406
|
var CompositionNode = class _CompositionNode extends AnimationNode {
|
|
399
407
|
constructor(children, timing, id) {
|
|
400
408
|
super(id);
|
|
@@ -412,8 +420,11 @@ var CompositionNode = class _CompositionNode extends AnimationNode {
|
|
|
412
420
|
);
|
|
413
421
|
}
|
|
414
422
|
if (child instanceof _CompositionNode) {
|
|
415
|
-
|
|
416
|
-
return
|
|
423
|
+
const adjustedChildren = adjustTiming(child.children);
|
|
424
|
+
return cloneCompositionNodeWithChildren(
|
|
425
|
+
child,
|
|
426
|
+
adjustedChildren
|
|
427
|
+
);
|
|
417
428
|
}
|
|
418
429
|
return child;
|
|
419
430
|
});
|
|
@@ -544,6 +555,17 @@ function stagger(children, offset, timing, id) {
|
|
|
544
555
|
}
|
|
545
556
|
|
|
546
557
|
// src/ani/core/interface/timeline_interface.ts
|
|
558
|
+
function normalizeRepeatCount(repeat) {
|
|
559
|
+
if (repeat === Infinity) return Infinity;
|
|
560
|
+
if (!Number.isFinite(repeat) || repeat === void 0 || repeat <= 0) {
|
|
561
|
+
return 0;
|
|
562
|
+
}
|
|
563
|
+
return Math.floor(repeat);
|
|
564
|
+
}
|
|
565
|
+
function toIterationCount(repeat) {
|
|
566
|
+
const normalized = normalizeRepeatCount(repeat);
|
|
567
|
+
return normalized === Infinity ? Infinity : normalized + 1;
|
|
568
|
+
}
|
|
547
569
|
var TimelineBase = class {
|
|
548
570
|
constructor(rootNode) {
|
|
549
571
|
this.rootNode = rootNode;
|
|
@@ -593,10 +615,10 @@ var TimelineBase = class {
|
|
|
593
615
|
const dynamicDuration = durations?.[keyframeIndex];
|
|
594
616
|
const newSegmentProps = {
|
|
595
617
|
...segment.node.props,
|
|
596
|
-
...dynamicTo && dynamicTo !== "keep" && {
|
|
618
|
+
...dynamicTo !== void 0 && dynamicTo !== "keep" && {
|
|
597
619
|
to: dynamicTo
|
|
598
620
|
},
|
|
599
|
-
...dynamicDuration && dynamicDuration !== "keep" && {
|
|
621
|
+
...dynamicDuration !== void 0 && dynamicDuration !== "keep" && {
|
|
600
622
|
duration: dynamicDuration
|
|
601
623
|
}
|
|
602
624
|
};
|
|
@@ -642,9 +664,20 @@ var AnimationClock = class _AnimationClock {
|
|
|
642
664
|
* @returns clock
|
|
643
665
|
*/
|
|
644
666
|
static create(maxDeltaTime = 1 / 10) {
|
|
645
|
-
_AnimationClock.clock
|
|
667
|
+
if (!_AnimationClock.clock) {
|
|
668
|
+
_AnimationClock.clock = new _AnimationClock(maxDeltaTime);
|
|
669
|
+
}
|
|
646
670
|
return _AnimationClock.clock;
|
|
647
671
|
}
|
|
672
|
+
/**
|
|
673
|
+
* Reconfigure singleton clock.
|
|
674
|
+
* If not created yet, creates one with provided maxDeltaTime.
|
|
675
|
+
*/
|
|
676
|
+
static configure(maxDeltaTime) {
|
|
677
|
+
const clock = _AnimationClock.create(maxDeltaTime);
|
|
678
|
+
clock.maxDeltaTime = maxDeltaTime;
|
|
679
|
+
return clock;
|
|
680
|
+
}
|
|
648
681
|
subscribe(animatable) {
|
|
649
682
|
this.subscribers.add(animatable);
|
|
650
683
|
if (!this.animationFrameId) {
|
|
@@ -755,7 +788,7 @@ var RafAniTimeline = class extends TimelineBase {
|
|
|
755
788
|
this._currentConfig = null;
|
|
756
789
|
this._state = [];
|
|
757
790
|
this._initialState = [];
|
|
758
|
-
this.
|
|
791
|
+
this._remainingRepeats = 0;
|
|
759
792
|
this._propertyKeyMap = null;
|
|
760
793
|
this._onUpdateCallbacks = /* @__PURE__ */ new Set();
|
|
761
794
|
this._clock = clock ?? AnimationClock.create();
|
|
@@ -788,6 +821,26 @@ var RafAniTimeline = class extends TimelineBase {
|
|
|
788
821
|
dt
|
|
789
822
|
);
|
|
790
823
|
}
|
|
824
|
+
_resolveRuntimeState(config) {
|
|
825
|
+
this._currentExecutionPlan = this._resolveExecutionPlan(
|
|
826
|
+
config.keyframes,
|
|
827
|
+
config.durations
|
|
828
|
+
);
|
|
829
|
+
const { keyMap, values } = resolveGroup(config.from);
|
|
830
|
+
this._propertyKeyMap = keyMap;
|
|
831
|
+
this._state = values;
|
|
832
|
+
this._initialState = values;
|
|
833
|
+
this._masterTime = 0;
|
|
834
|
+
}
|
|
835
|
+
_restartForRepeat() {
|
|
836
|
+
if (!this._currentConfig) {
|
|
837
|
+
return;
|
|
838
|
+
}
|
|
839
|
+
this._delay = 0;
|
|
840
|
+
this._resolveRuntimeState(this._currentConfig);
|
|
841
|
+
this._status = "PLAYING";
|
|
842
|
+
this.notify();
|
|
843
|
+
}
|
|
791
844
|
notify() {
|
|
792
845
|
for (const subscriber of this._onUpdateCallbacks) {
|
|
793
846
|
subscriber({
|
|
@@ -818,14 +871,15 @@ var RafAniTimeline = class extends TimelineBase {
|
|
|
818
871
|
this._state = this._calculateStateAtTime(this._masterTime, dt);
|
|
819
872
|
this.notify();
|
|
820
873
|
if (isEndOfAnimation(this._masterTime, this.duration)) {
|
|
821
|
-
this.
|
|
822
|
-
|
|
823
|
-
|
|
874
|
+
if (this._remainingRepeats === Infinity || this._remainingRepeats > 0) {
|
|
875
|
+
if (this._remainingRepeats !== Infinity) {
|
|
876
|
+
this._remainingRepeats -= 1;
|
|
877
|
+
}
|
|
878
|
+
this._restartForRepeat();
|
|
879
|
+
} else {
|
|
824
880
|
this._status = "ENDED";
|
|
825
881
|
this._clock.unsubscribe(this);
|
|
826
882
|
this.notify();
|
|
827
|
-
} else {
|
|
828
|
-
this.play(this._currentConfig);
|
|
829
883
|
}
|
|
830
884
|
}
|
|
831
885
|
}
|
|
@@ -836,27 +890,11 @@ var RafAniTimeline = class extends TimelineBase {
|
|
|
836
890
|
*/
|
|
837
891
|
play(config, canBeIntercepted = true) {
|
|
838
892
|
if (this._status === "PLAYING" && !canBeIntercepted) return;
|
|
839
|
-
|
|
840
|
-
const savedRepeatCount = isRepeating ? this._repeatCount : 0;
|
|
841
|
-
const isPlaying = this._status === "PLAYING";
|
|
842
|
-
this.reset(false, !isPlaying);
|
|
843
|
-
this._repeatCount = savedRepeatCount;
|
|
844
|
-
if (isRepeating && this._repeatCount >= config.repeat) {
|
|
845
|
-
this._repeatCount = 0;
|
|
846
|
-
return;
|
|
847
|
-
}
|
|
893
|
+
this.reset(false, true);
|
|
848
894
|
this._currentConfig = config;
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
this._currentExecutionPlan = this._resolveExecutionPlan(
|
|
853
|
-
config.keyframes,
|
|
854
|
-
config.durations
|
|
855
|
-
);
|
|
856
|
-
const { keyMap, values } = resolveGroup(config.from);
|
|
857
|
-
this._propertyKeyMap = keyMap;
|
|
858
|
-
this._state = values;
|
|
859
|
-
this._initialState = values;
|
|
895
|
+
this._remainingRepeats = normalizeRepeatCount(config.repeat);
|
|
896
|
+
this._delay = (this._currentConfig.delay ?? 0) * 1e-3;
|
|
897
|
+
this._resolveRuntimeState(config);
|
|
860
898
|
this._status = "PLAYING";
|
|
861
899
|
this._clock.subscribe(this);
|
|
862
900
|
this.notify();
|
|
@@ -882,7 +920,7 @@ var RafAniTimeline = class extends TimelineBase {
|
|
|
882
920
|
if (unsubscribeClock) {
|
|
883
921
|
this._clock.unsubscribe(this);
|
|
884
922
|
}
|
|
885
|
-
this.
|
|
923
|
+
this._remainingRepeats = 0;
|
|
886
924
|
if (notify) this.notify();
|
|
887
925
|
}
|
|
888
926
|
seek(targetTime) {
|
|
@@ -931,9 +969,11 @@ function createStates(config) {
|
|
|
931
969
|
return () => subs.delete(callback);
|
|
932
970
|
},
|
|
933
971
|
transitionTo(newState, timelineConfig, canBeIntercepted) {
|
|
972
|
+
const previousTimeline = Timeline;
|
|
934
973
|
const from = timelineConfig?.from ?? // 1. config
|
|
935
974
|
Timeline.getCurrentValue() ?? // 2. last value
|
|
936
975
|
config.initialFrom;
|
|
976
|
+
previousTimeline.reset(false);
|
|
937
977
|
State = newState;
|
|
938
978
|
Timeline = rafTimeline(config.states[State], config.clock);
|
|
939
979
|
notify(Timeline);
|
|
@@ -1064,7 +1104,7 @@ function compileTiming(timing) {
|
|
|
1064
1104
|
}
|
|
1065
1105
|
|
|
1066
1106
|
// src/ani/waapi/compiler/keyframe_compiler.ts
|
|
1067
|
-
function compileToKeyframes(plan, initialFrom) {
|
|
1107
|
+
function compileToKeyframes(plan, initialFrom, resolver) {
|
|
1068
1108
|
if (plan.length === 0) {
|
|
1069
1109
|
return [];
|
|
1070
1110
|
}
|
|
@@ -1073,7 +1113,10 @@ function compileToKeyframes(plan, initialFrom) {
|
|
|
1073
1113
|
const duration = Math.max(...plan.map((s) => s.endTime));
|
|
1074
1114
|
if (duration === 0) {
|
|
1075
1115
|
const state = resolveStateAt(plan, initialFrom, 0, SAMPLE_RATE);
|
|
1076
|
-
const style = createStyleSheet(
|
|
1116
|
+
const style = createStyleSheet(
|
|
1117
|
+
state,
|
|
1118
|
+
resolver
|
|
1119
|
+
);
|
|
1077
1120
|
return [
|
|
1078
1121
|
{ offset: 0, ...style },
|
|
1079
1122
|
{ offset: 1, ...style }
|
|
@@ -1103,7 +1146,10 @@ function compileToKeyframes(plan, initialFrom) {
|
|
|
1103
1146
|
for (let i = 0; i < sortedTimes.length; i++) {
|
|
1104
1147
|
const currT = sortedTimes[i];
|
|
1105
1148
|
const state = resolveStateAt(plan, initialFrom, currT, SAMPLE_RATE);
|
|
1106
|
-
const style = createStyleSheet(
|
|
1149
|
+
const style = createStyleSheet(
|
|
1150
|
+
state,
|
|
1151
|
+
resolver
|
|
1152
|
+
);
|
|
1107
1153
|
const keyframe = {
|
|
1108
1154
|
offset: currT / duration,
|
|
1109
1155
|
...style
|
|
@@ -1122,7 +1168,8 @@ function compileToKeyframes(plan, initialFrom) {
|
|
|
1122
1168
|
SAMPLE_RATE
|
|
1123
1169
|
);
|
|
1124
1170
|
const sampleStyle = createStyleSheet(
|
|
1125
|
-
sampleState
|
|
1171
|
+
sampleState,
|
|
1172
|
+
resolver
|
|
1126
1173
|
);
|
|
1127
1174
|
keyframes.push({
|
|
1128
1175
|
offset: sampleT / duration,
|
|
@@ -1162,7 +1209,8 @@ var WebAniTimeline = class extends TimelineBase {
|
|
|
1162
1209
|
);
|
|
1163
1210
|
this._keyframes = compileToKeyframes(
|
|
1164
1211
|
this._currentExecutionPlan,
|
|
1165
|
-
config.from
|
|
1212
|
+
config.from,
|
|
1213
|
+
config.propertyResolver
|
|
1166
1214
|
);
|
|
1167
1215
|
if (this._keyframes.length === 0) {
|
|
1168
1216
|
return null;
|
|
@@ -1173,9 +1221,10 @@ var WebAniTimeline = class extends TimelineBase {
|
|
|
1173
1221
|
) * 1e3;
|
|
1174
1222
|
const effect = new KeyframeEffect(target, this._keyframes, {
|
|
1175
1223
|
duration: totalDurationMs,
|
|
1176
|
-
iterations: config.repeat
|
|
1224
|
+
iterations: toIterationCount(config.repeat),
|
|
1177
1225
|
delay: config.delay ?? 0,
|
|
1178
|
-
fill: "forwards"
|
|
1226
|
+
fill: "forwards",
|
|
1227
|
+
...config.keyframeEffect
|
|
1179
1228
|
});
|
|
1180
1229
|
this._animation = new Animation(effect, document.timeline);
|
|
1181
1230
|
this._animation.play();
|
|
@@ -1191,6 +1240,12 @@ var WebAniTimeline = class extends TimelineBase {
|
|
|
1191
1240
|
this._animation?.cancel();
|
|
1192
1241
|
this._animation = null;
|
|
1193
1242
|
}
|
|
1243
|
+
/**
|
|
1244
|
+
* Alias of reset() for WAAPI naming parity.
|
|
1245
|
+
*/
|
|
1246
|
+
cancel() {
|
|
1247
|
+
this.reset();
|
|
1248
|
+
}
|
|
1194
1249
|
seek(targetTime) {
|
|
1195
1250
|
if (this._animation) {
|
|
1196
1251
|
this._animation.currentTime = targetTime * 1e3;
|
|
@@ -1238,6 +1293,7 @@ var EventManager = class _EventManager {
|
|
|
1238
1293
|
const removeListener = this.eventMap.get(eventName);
|
|
1239
1294
|
if (!removeListener) return false;
|
|
1240
1295
|
this.targetElement.removeEventListener(eventName, removeListener);
|
|
1296
|
+
this.eventMap.delete(eventName);
|
|
1241
1297
|
return true;
|
|
1242
1298
|
};
|
|
1243
1299
|
this.cleanupAll = () => {
|
|
@@ -1283,8 +1339,17 @@ var EventManager = class _EventManager {
|
|
|
1283
1339
|
// src/index.ts
|
|
1284
1340
|
var a = {
|
|
1285
1341
|
timing: T,
|
|
1342
|
+
/**
|
|
1343
|
+
* @deprecated Use `rafTimeline` alias for explicit engine naming.
|
|
1344
|
+
*/
|
|
1286
1345
|
dynamicTimeline: rafTimeline,
|
|
1346
|
+
/**
|
|
1347
|
+
* @deprecated Use `waapiTimeline` alias for explicit engine naming.
|
|
1348
|
+
*/
|
|
1287
1349
|
timeline: webTimeline,
|
|
1350
|
+
webTimeline,
|
|
1351
|
+
rafTimeline,
|
|
1352
|
+
waapiTimeline: webTimeline,
|
|
1288
1353
|
/**
|
|
1289
1354
|
* Create animation segment.
|
|
1290
1355
|
*/
|
|
@@ -1314,6 +1379,8 @@ export {
|
|
|
1314
1379
|
compileToKeyframes,
|
|
1315
1380
|
createStates,
|
|
1316
1381
|
createStyleSheet,
|
|
1382
|
+
normalizeRepeatCount,
|
|
1317
1383
|
rafTimeline,
|
|
1384
|
+
toIterationCount,
|
|
1318
1385
|
webTimeline
|
|
1319
1386
|
};
|