@hyperframes/parsers 0.8.127 → 0.8.129
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/composition.d.ts +1 -1
- package/dist/composition.js.map +1 -1
- package/dist/gsapConstants.d.ts +1 -1
- package/dist/gsapConstants.js +5 -5
- package/dist/gsapConstants.js.map +1 -1
- package/dist/gsapParser.d.ts +2 -2
- package/dist/gsapParser.js +63 -41
- package/dist/gsapParser.js.map +1 -1
- package/dist/gsapParserAcorn.d.ts +2 -2
- package/dist/gsapParserAcorn.js +32 -30
- package/dist/gsapParserAcorn.js.map +1 -1
- package/dist/gsapParserExports.d.ts +15 -1
- package/dist/gsapParserExports.js +34 -30
- package/dist/gsapParserExports.js.map +1 -1
- package/dist/{gsapSerialize-CFUDcLqX.d.ts → gsapSerialize-CfSXM_Ez.d.ts} +4 -2
- package/dist/gsapWriterAcorn.d.ts +23 -3
- package/dist/gsapWriterAcorn.js +147 -89
- package/dist/gsapWriterAcorn.js.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.js +35 -31
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
|
@@ -7,6 +7,7 @@ import { K as Keyframe, V as ValidationResult } from './types-Ejqndkej.js';
|
|
|
7
7
|
* without pulling in gsapParser (which depends on recast / @babel/parser).
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
|
+
declare const GSAP_DEFAULT_DURATION = 0.5;
|
|
10
11
|
declare const SUPPORTED_PROPS: string[];
|
|
11
12
|
/** Keys stored on dedicated GsapAnimation fields (not in properties/extras). */
|
|
12
13
|
declare const BUILTIN_VAR_KEYS: ReadonlySet<string>;
|
|
@@ -22,7 +23,7 @@ declare function isXYPositionWrite(a: PositionWrite): boolean;
|
|
|
22
23
|
declare function classifyPropertyGroup(prop: string): PropertyGroupName;
|
|
23
24
|
declare function classifyTweenPropertyGroup(properties: Record<string, unknown>): PropertyGroupName | undefined;
|
|
24
25
|
/**
|
|
25
|
-
* What a Studio hold pins from t=0 before a later keyframed tween: its
|
|
26
|
+
* What a Studio hold pins from t=0 before a later keyframed tween: its 0% keyframe's position props,
|
|
26
27
|
* minus those an earlier timeline tween on the target writes (a global `gsap.set` is a base value).
|
|
27
28
|
*/
|
|
28
29
|
declare function positionHoldForAnimation(animation: GsapAnimation, animations: readonly GsapAnimation[]): Record<string, number> | null;
|
|
@@ -129,6 +130,7 @@ interface GsapKeyframesData<K extends GsapPercentageKeyframe = GsapPercentageKey
|
|
|
129
130
|
keyframes: K[];
|
|
130
131
|
ease?: string;
|
|
131
132
|
easeEach?: string;
|
|
133
|
+
fromMotionPath?: true;
|
|
132
134
|
}
|
|
133
135
|
interface ArcPathSegment {
|
|
134
136
|
curviness: number;
|
|
@@ -214,4 +216,4 @@ declare function gsapAnimationsToKeyframes(animations: GsapAnimation[], elementS
|
|
|
214
216
|
skipBaseSet?: boolean;
|
|
215
217
|
}): Keyframe[];
|
|
216
218
|
|
|
217
|
-
export { type ArcPathConfig as A, BUILTIN_VAR_KEYS as B, DROPPED_VAR_KEYS as D, EXTRAS_KEYS as E, type
|
|
219
|
+
export { type ArcPathConfig as A, BUILTIN_VAR_KEYS as B, DROPPED_VAR_KEYS as D, EXTRAS_KEYS as E, type GsapMethod as G, type KeyframeEditability as K, type MotionPathShape as M, type ParsedGsap as P, SUPPORTED_EASES as S, type GsapAnimation as a, type ArcPathSegment as b, type GsapProvenance as c, type GsapProvenanceKind as d, buildArcPath as e, editabilityForProvenance as f, type GsapKeyframeFormat as g, type GsapKeyframesData as h, type GsapPercentageKeyframe as i, PROPERTY_GROUPS as j, type PropertyGroupName as k, SUPPORTED_PROPS as l, classifyPropertyGroup as m, classifyTweenPropertyGroup as n, getAnimationsForElementId as o, gsapAnimationsToKeyframes as p, keyframesToGsapAnimations as q, type SplitAnimationsOptions as r, serializeGsapAnimations as s, type SplitAnimationsResult as t, GSAP_DEFAULT_DURATION as u, validateCompositionGsap as v, type SourcedGsapPercentageKeyframe as w, isTweenConfigKey as x, isXYPositionWrite as y, positionHoldForAnimation as z };
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { a as GsapAnimation, A as ArcPathConfig, r as SplitAnimationsOptions, t as SplitAnimationsResult, b as ArcPathSegment } from './gsapSerialize-CfSXM_Ez.js';
|
|
2
2
|
import './types-Ejqndkej.js';
|
|
3
3
|
|
|
4
4
|
type TweenTarget = Pick<GsapAnimation, "targetSelector" | "hasPartialSelector">;
|
|
5
5
|
type TweenTime = Pick<GsapAnimation, "position" | "implicitPosition">;
|
|
6
|
-
declare function clipTweenMatcher(clipSelectors: string | readonly string[], root?: ParentNode): (tween: TweenTarget) => boolean;
|
|
6
|
+
declare function clipTweenMatcher(clipSelectors: string | readonly string[], root?: ParentNode, queries?: Map<string, Element[]>): (tween: TweenTarget) => boolean;
|
|
7
7
|
/** Where a GSAP script's clips live: linkedom keeps a `<template>`'s children under it, out of document queries. */
|
|
8
8
|
declare function clipQueryRoot(script: Element): ParentNode;
|
|
9
9
|
/** A written position; an implicit one follows the tween before it and must stay unwritten. */
|
|
@@ -21,6 +21,26 @@ declare function updateAnimationInScript(script: string, animationId: string, up
|
|
|
21
21
|
* (used by timeline clip-move to keep GSAP positions in sync with the clip start).
|
|
22
22
|
*/
|
|
23
23
|
declare function shiftPositionsInScript(script: string, targetSelector: string, delta: number, root?: ParentNode): string;
|
|
24
|
+
type ClipTweenRetime = {
|
|
25
|
+
kind: "shift";
|
|
26
|
+
targetSelector: string;
|
|
27
|
+
delta: number;
|
|
28
|
+
} | {
|
|
29
|
+
kind: "scale";
|
|
30
|
+
targetSelector: string;
|
|
31
|
+
oldStart: number;
|
|
32
|
+
oldDuration: number;
|
|
33
|
+
newStart: number;
|
|
34
|
+
newDuration: number;
|
|
35
|
+
};
|
|
36
|
+
/**
|
|
37
|
+
* Applies `retimes` in order with one parse: the bytes equal running shift/scalePositionsInScript once
|
|
38
|
+
* per retime. `changed[i]` says whether retime i moved a value.
|
|
39
|
+
*/
|
|
40
|
+
declare function retimeClipTweensInScript(script: string, retimes: readonly ClipTweenRetime[], root?: ParentNode): {
|
|
41
|
+
script: string;
|
|
42
|
+
changed: boolean[];
|
|
43
|
+
};
|
|
24
44
|
/** Copies each tween on `fromSelector` for `toSelector`, `delta` seconds later, in its own argument text. Exact or
|
|
25
45
|
* absent: only a tween at a number, written straight in the timeline's own block, is copied. */
|
|
26
46
|
declare function copyAnimationsInScript(script: string, fromSelector: string, toSelector: string, delta: number): string;
|
|
@@ -177,4 +197,4 @@ type UnrollElement = {
|
|
|
177
197
|
*/
|
|
178
198
|
declare function unrollDynamicAnimations(script: string, animationId: string, elements: UnrollElement[]): string;
|
|
179
199
|
|
|
180
|
-
export { type UnrollElement, addAnimationToScript, addAnimationWithKeyframesToScript, addKeyframeToScript, addLabelToScript, addMotionPathPointInScript, addMotionPathToScript, clipQueryRoot, clipTweenMatcher, convertToKeyframesFromScript, copyAnimationsInScript, dedupePositionWritesInScript, hasExplicitTime, materializeKeyframesFromScript, moveKeyframeInScript, removeAllKeyframesFromScript, removeAnimationFromScript, removeArcPathFromScript, removeKeyframeFromScript, removeLabelFromScript, removeMotionPathPointInScript, removePropertyFromAnimation, replaceTweenWithKeyframesInScript, resizeKeyframedTweenInScript, scalePositionsInScript, setArcPathInScript, shiftPositionsInScript, splitAnimationsInScript, splitIntoPropertyGroupsFromScript, syncPositionHoldsBeforeKeyframes, unrollDynamicAnimations, updateAnimationInScript, updateArcSegmentInScript, updateKeyframeInScript, updateMotionPathPointInScript };
|
|
200
|
+
export { type ClipTweenRetime, type UnrollElement, addAnimationToScript, addAnimationWithKeyframesToScript, addKeyframeToScript, addLabelToScript, addMotionPathPointInScript, addMotionPathToScript, clipQueryRoot, clipTweenMatcher, convertToKeyframesFromScript, copyAnimationsInScript, dedupePositionWritesInScript, hasExplicitTime, materializeKeyframesFromScript, moveKeyframeInScript, removeAllKeyframesFromScript, removeAnimationFromScript, removeArcPathFromScript, removeKeyframeFromScript, removeLabelFromScript, removeMotionPathPointInScript, removePropertyFromAnimation, replaceTweenWithKeyframesInScript, resizeKeyframedTweenInScript, retimeClipTweensInScript, scalePositionsInScript, setArcPathInScript, shiftPositionsInScript, splitAnimationsInScript, splitIntoPropertyGroupsFromScript, syncPositionHoldsBeforeKeyframes, unrollDynamicAnimations, updateAnimationInScript, updateArcSegmentInScript, updateKeyframeInScript, updateMotionPathPointInScript };
|
package/dist/gsapWriterAcorn.js
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import MagicString from "magic-string";
|
|
3
3
|
|
|
4
4
|
// src/gsapConstants.ts
|
|
5
|
+
var GSAP_DEFAULT_DURATION = 0.5;
|
|
5
6
|
var BUILTIN_VAR_KEYS = /* @__PURE__ */ new Set(["duration", "ease", "delay"]);
|
|
6
7
|
var DROPPED_VAR_KEYS = /* @__PURE__ */ new Set([
|
|
7
8
|
"onComplete",
|
|
@@ -60,16 +61,14 @@ function positionHoldForAnimation(animation, animations) {
|
|
|
60
61
|
if (!animation.keyframes) return null;
|
|
61
62
|
const start = knownStart(animation) ?? 0;
|
|
62
63
|
if (!(start > 1e-3)) return null;
|
|
63
|
-
const
|
|
64
|
-
|
|
65
|
-
)[0];
|
|
66
|
-
if (!first) return null;
|
|
64
|
+
const atStart = animation.keyframes.keyframes.find((keyframe) => keyframe.percentage === 0);
|
|
65
|
+
if (!atStart) return null;
|
|
67
66
|
const earlier = animations.filter((other) => {
|
|
68
67
|
const otherStart = knownStart(other);
|
|
69
68
|
return other !== animation && !other.global && other.targetSelector === animation.targetSelector && otherStart !== void 0 && otherStart < start - 1e-3;
|
|
70
69
|
});
|
|
71
70
|
const position = {};
|
|
72
|
-
for (const [property, value] of Object.entries(
|
|
71
|
+
for (const [property, value] of Object.entries(atStart.properties)) {
|
|
73
72
|
if (classifyPropertyGroup(property) !== "position" || typeof value !== "number") continue;
|
|
74
73
|
if (earlier.some((other) => writesProperty(other, property))) continue;
|
|
75
74
|
position[property] = value;
|
|
@@ -78,6 +77,9 @@ function positionHoldForAnimation(animation, animations) {
|
|
|
78
77
|
}
|
|
79
78
|
|
|
80
79
|
// src/gsapSerialize.ts
|
|
80
|
+
function authorsKeyframes(anim) {
|
|
81
|
+
return anim.keyframes !== void 0 || anim.hasUnresolvedKeyframes === true;
|
|
82
|
+
}
|
|
81
83
|
function mergePercentageKeyframes(keyframes) {
|
|
82
84
|
const byPercentage = /* @__PURE__ */ new Map();
|
|
83
85
|
for (const keyframe of keyframes) {
|
|
@@ -229,34 +231,27 @@ function readProvenance(node) {
|
|
|
229
231
|
var roundPercentage = (percentage) => Math.round(percentage * 10) / 10;
|
|
230
232
|
var OBJECT_ARRAY_PERCENTAGE_TOLERANCE = 2;
|
|
231
233
|
function getObjectArrayKeyframeTiming(durations) {
|
|
232
|
-
const
|
|
233
|
-
if (
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
return null;
|
|
238
|
-
}
|
|
239
|
-
const totalDuration = durations.reduce((sum, duration) => sum + duration, 0);
|
|
240
|
-
let cumulative = 0;
|
|
241
|
-
return {
|
|
242
|
-
percentages: durations.map((duration) => {
|
|
243
|
-
cumulative += duration;
|
|
244
|
-
return roundPercentage(cumulative / totalDuration * 100);
|
|
245
|
-
}),
|
|
246
|
-
totalDuration
|
|
247
|
-
};
|
|
234
|
+
const steps = durations.map((duration) => duration ?? GSAP_DEFAULT_DURATION);
|
|
235
|
+
if (!steps.every(
|
|
236
|
+
(duration) => typeof duration === "number" && Number.isFinite(duration) && duration > 0
|
|
237
|
+
)) {
|
|
238
|
+
return null;
|
|
248
239
|
}
|
|
249
|
-
const
|
|
240
|
+
const totalDuration = steps.reduce((sum, duration) => sum + duration, 0);
|
|
241
|
+
let cumulative = 0;
|
|
250
242
|
return {
|
|
251
|
-
percentages:
|
|
252
|
-
|
|
253
|
-
|
|
243
|
+
percentages: steps.map((duration) => {
|
|
244
|
+
cumulative += duration;
|
|
245
|
+
return roundPercentage(cumulative / totalDuration * 100);
|
|
246
|
+
}),
|
|
247
|
+
totalDuration
|
|
254
248
|
};
|
|
255
249
|
}
|
|
256
250
|
function getCompatibleObjectArrayKeyframeTiming(durations, outerDuration) {
|
|
257
251
|
const timing = getObjectArrayKeyframeTiming(durations);
|
|
258
252
|
if (!timing) return null;
|
|
259
|
-
|
|
253
|
+
const stepsAuthorDuration = durations.some((duration) => duration !== void 0);
|
|
254
|
+
if (!stepsAuthorDuration || outerDuration === void 0) return timing;
|
|
260
255
|
if (typeof outerDuration === "number" && Math.abs(outerDuration - timing.totalDuration) <= Number.EPSILON) {
|
|
261
256
|
return timing;
|
|
262
257
|
}
|
|
@@ -852,6 +847,7 @@ function parsePercentageKeyframes(node, scope, source) {
|
|
|
852
847
|
if (typeof key !== "string") continue;
|
|
853
848
|
const pctMatch = PERCENTAGE_KEY_RE.exec(key);
|
|
854
849
|
if (pctMatch) {
|
|
850
|
+
if (!isPlainStep(prop.value)) return void 0;
|
|
855
851
|
const percentage = Number.parseFloat(pctMatch[1] ?? "0");
|
|
856
852
|
const record = objectExpressionToRecord(prop.value, scope, source);
|
|
857
853
|
const properties = {};
|
|
@@ -870,6 +866,8 @@ function parsePercentageKeyframes(node, scope, source) {
|
|
|
870
866
|
ease = tryResolveStringProp(prop.value, scope, source) ?? ease;
|
|
871
867
|
} else if (key === "easeEach") {
|
|
872
868
|
easeEach = tryResolveStringProp(prop.value, scope, source) ?? easeEach;
|
|
869
|
+
} else {
|
|
870
|
+
return void 0;
|
|
873
871
|
}
|
|
874
872
|
}
|
|
875
873
|
keyframes.sort((a, b) => a.percentage - b.percentage);
|
|
@@ -893,12 +891,19 @@ function computeKeyframesTotalDuration(varsNode, scope, source) {
|
|
|
893
891
|
}
|
|
894
892
|
return getObjectArrayKeyframeTiming(durations)?.totalDuration;
|
|
895
893
|
}
|
|
896
|
-
|
|
894
|
+
function staticKeyName(prop) {
|
|
895
|
+
if (prop.type !== "ObjectProperty" && prop.type !== "Property") return void 0;
|
|
896
|
+
if (prop.method || prop.kind && prop.kind !== "init") return void 0;
|
|
897
|
+
const key = prop.computed ? prop.key?.type === "Literal" && prop.key.value : prop.key?.name ?? prop.key?.value;
|
|
898
|
+
return typeof key === "string" ? key : void 0;
|
|
899
|
+
}
|
|
900
|
+
var isPlainObject = (node) => node?.type === "ObjectExpression" && (node.properties ?? []).every((p) => staticKeyName(p) !== void 0);
|
|
901
|
+
var isPlainStep = (node) => node?.type === "Literal" || isPlainObject(node);
|
|
897
902
|
function parseObjectArrayKeyframes(node, scope, source) {
|
|
898
903
|
const elements = node.elements ?? [];
|
|
899
904
|
const raw = [];
|
|
900
905
|
for (const el of elements) {
|
|
901
|
-
if (!
|
|
906
|
+
if (!isPlainObject(el)) return void 0;
|
|
902
907
|
const record = objectExpressionToRecord(el, scope, source);
|
|
903
908
|
const properties = {};
|
|
904
909
|
let duration;
|
|
@@ -937,9 +942,8 @@ function parseSimpleArrayKeyframes(node, scope) {
|
|
|
937
942
|
const values = [];
|
|
938
943
|
for (const el of prop.value.elements ?? []) {
|
|
939
944
|
const val = resolveNode(el, scope);
|
|
940
|
-
if (typeof val
|
|
941
|
-
|
|
942
|
-
}
|
|
945
|
+
if (typeof val !== "number" && typeof val !== "string") return void 0;
|
|
946
|
+
values.push(val);
|
|
943
947
|
}
|
|
944
948
|
if (values.length > 0) arrayProps.set(key, values);
|
|
945
949
|
} else if (key === "ease") {
|
|
@@ -972,6 +976,7 @@ function parseKeyframesNode(node, scope, source) {
|
|
|
972
976
|
}
|
|
973
977
|
if (node.type !== "ObjectExpression") return void 0;
|
|
974
978
|
const props = node.properties ?? [];
|
|
979
|
+
if (!props.every((p) => staticKeyName(p) !== void 0)) return void 0;
|
|
975
980
|
let hasPercentageKey = false;
|
|
976
981
|
let hasArrayValue = false;
|
|
977
982
|
for (const prop of props) {
|
|
@@ -1072,7 +1077,7 @@ function tweenCallToAnimation(call, scope, source, identifierBindings) {
|
|
|
1072
1077
|
percentage: waypoints.length > 1 ? Math.round(i / (waypoints.length - 1) * 100) : 0,
|
|
1073
1078
|
properties: { x: wp.x, y: wp.y }
|
|
1074
1079
|
}));
|
|
1075
|
-
keyframesData = { format: "percentage", keyframes: kf };
|
|
1080
|
+
keyframesData = { format: "percentage", keyframes: kf, fromMotionPath: true };
|
|
1076
1081
|
} else {
|
|
1077
1082
|
const kfs = keyframesData.keyframes;
|
|
1078
1083
|
if (kfs.length === waypoints.length) {
|
|
@@ -1102,10 +1107,10 @@ function tweenCallToAnimation(call, scope, source, identifierBindings) {
|
|
|
1102
1107
|
const position = typeof posVal === "number" ? posVal : typeof posVal === "string" ? posVal : hasPositionArg ? `__raw:${source.slice(call.positionArg.start, call.positionArg.end)}` : 0;
|
|
1103
1108
|
let duration = typeof vars.duration === "number" ? vars.duration : void 0;
|
|
1104
1109
|
const ease = typeof vars.ease === "string" ? vars.ease : void 0;
|
|
1105
|
-
|
|
1110
|
+
const durationUnresolved = call.method !== "set" && duration === void 0 && hasUnknownDuration(call.varsArg, scope);
|
|
1111
|
+
if (duration === void 0 && keyframesData && !durationUnresolved) {
|
|
1106
1112
|
duration = computeKeyframesTotalDuration(call.varsArg, scope, source);
|
|
1107
1113
|
}
|
|
1108
|
-
const durationUnresolved = call.method !== "set" && duration === void 0 && hasUnknownDuration(call.varsArg, scope);
|
|
1109
1114
|
let selector = call.selector;
|
|
1110
1115
|
let targetIdentity;
|
|
1111
1116
|
if (selector === "__unresolved__") {
|
|
@@ -1159,7 +1164,6 @@ function tweenCallToAnimation(call, scope, source, identifierBindings) {
|
|
|
1159
1164
|
if (provenance) anim.provenance = provenance;
|
|
1160
1165
|
return anim;
|
|
1161
1166
|
}
|
|
1162
|
-
var GSAP_DEFAULT_DURATION = 0.5;
|
|
1163
1167
|
function resolvePositionString(pos, cursor, prevStart) {
|
|
1164
1168
|
const trimmed = pos.trim();
|
|
1165
1169
|
if (trimmed === "") return cursor;
|
|
@@ -1192,7 +1196,7 @@ function applyTimelineDefaults(anims, defaults) {
|
|
|
1192
1196
|
if (defaults.duration !== void 0) anim.duration = defaults.duration;
|
|
1193
1197
|
else if (defaults.durationUnresolved) anim.durationUnresolved = true;
|
|
1194
1198
|
}
|
|
1195
|
-
if (anim.ease === void 0 && defaults.ease !== void 0 && !anim.keyframes) {
|
|
1199
|
+
if (anim.ease === void 0 && defaults.ease !== void 0 && (!anim.keyframes || anim.keyframes.fromMotionPath)) {
|
|
1196
1200
|
anim.ease = defaults.ease;
|
|
1197
1201
|
}
|
|
1198
1202
|
}
|
|
@@ -1361,14 +1365,25 @@ function parseGsapScriptAcornForWrite(script) {
|
|
|
1361
1365
|
import * as acornWalk2 from "acorn-walk";
|
|
1362
1366
|
|
|
1363
1367
|
// src/clipTweens.ts
|
|
1364
|
-
function clipTweenMatcher(clipSelectors, root) {
|
|
1368
|
+
function clipTweenMatcher(clipSelectors, root, queries = /* @__PURE__ */ new Map()) {
|
|
1365
1369
|
const own = typeof clipSelectors === "string" ? [clipSelectors] : clipSelectors;
|
|
1366
|
-
|
|
1370
|
+
if (!root)
|
|
1371
|
+
return ({ targetSelector, hasPartialSelector }) => !hasPartialSelector && own.includes(targetSelector);
|
|
1372
|
+
const queryAll = (selector) => {
|
|
1373
|
+
if (ID_SELECTOR.test(selector)) {
|
|
1374
|
+
if (!queries.has(ALL_IDS)) indexIds(root, queries);
|
|
1375
|
+
return queries.get(selector) ?? [];
|
|
1376
|
+
}
|
|
1377
|
+
let found = queries.get(selector);
|
|
1378
|
+
if (!found) queries.set(selector, found = queryRoot(root, selector));
|
|
1379
|
+
return found;
|
|
1380
|
+
};
|
|
1381
|
+
const clips = own.flatMap((selector) => queryAll(selector));
|
|
1367
1382
|
return ({ targetSelector, hasPartialSelector }) => {
|
|
1368
1383
|
if (hasPartialSelector) return false;
|
|
1369
1384
|
if (own.includes(targetSelector)) return true;
|
|
1370
|
-
if (
|
|
1371
|
-
const targets = queryAll(
|
|
1385
|
+
if (clips.length === 0) return false;
|
|
1386
|
+
const targets = queryAll(targetSelector);
|
|
1372
1387
|
return targets.length > 0 && targets.every((target) => {
|
|
1373
1388
|
const owner = target.closest("[data-start]");
|
|
1374
1389
|
return clips.includes(target) || owner !== null && clips.includes(owner);
|
|
@@ -1381,7 +1396,20 @@ function clipQueryRoot(script) {
|
|
|
1381
1396
|
function hasExplicitTime(animation) {
|
|
1382
1397
|
return typeof animation.position === "number" && !animation.implicitPosition;
|
|
1383
1398
|
}
|
|
1384
|
-
|
|
1399
|
+
var ID_SELECTOR = /^#-?[A-Za-z_][\w-]*$/;
|
|
1400
|
+
var ALL_IDS = "[id]";
|
|
1401
|
+
function indexIds(root, queries) {
|
|
1402
|
+
const all = queryRoot(root, ALL_IDS);
|
|
1403
|
+
queries.set(ALL_IDS, all);
|
|
1404
|
+
for (const el of all) {
|
|
1405
|
+
const key = `#${el.id}`;
|
|
1406
|
+
if (!ID_SELECTOR.test(key)) continue;
|
|
1407
|
+
const list = queries.get(key);
|
|
1408
|
+
if (list) list.push(el);
|
|
1409
|
+
else queries.set(key, [el]);
|
|
1410
|
+
}
|
|
1411
|
+
}
|
|
1412
|
+
function queryRoot(root, selector) {
|
|
1385
1413
|
try {
|
|
1386
1414
|
return Array.from(root.querySelectorAll(selector));
|
|
1387
1415
|
} catch {
|
|
@@ -1557,7 +1585,7 @@ function updateAnimationInScript(script, animationId, updates) {
|
|
|
1557
1585
|
const parsed = parseGsapScriptAcornForWrite(script);
|
|
1558
1586
|
if (!parsed) return script;
|
|
1559
1587
|
const target = parsed.located.find((l) => l.id === animationId);
|
|
1560
|
-
if (!target) return script;
|
|
1588
|
+
if (!target || updates.properties && target.animation.hasUnresolvedKeyframes) return script;
|
|
1561
1589
|
const ms = new MagicString(script);
|
|
1562
1590
|
const { call } = target;
|
|
1563
1591
|
if (updates.properties) {
|
|
@@ -1621,17 +1649,54 @@ function overwritePosition(ms, call, position) {
|
|
|
1621
1649
|
}
|
|
1622
1650
|
}
|
|
1623
1651
|
function shiftPositionsInScript(script, targetSelector, delta, root) {
|
|
1624
|
-
|
|
1625
|
-
|
|
1626
|
-
|
|
1652
|
+
return retimeClipTweensInScript(script, [{ kind: "shift", targetSelector, delta }], root).script;
|
|
1653
|
+
}
|
|
1654
|
+
var isLiveRetime = (r) => r.kind === "shift" || r.oldDuration > 0 && r.newDuration > 0;
|
|
1655
|
+
function applyRetime(animation, retime) {
|
|
1656
|
+
if (retime.kind === "shift") {
|
|
1657
|
+
if (!hasExplicitTime(animation)) return { position: false, duration: false };
|
|
1658
|
+
animation.position = shiftedPosition(animation.position, retime.delta);
|
|
1659
|
+
return { position: true, duration: false };
|
|
1660
|
+
}
|
|
1661
|
+
const touched = { position: false, duration: false };
|
|
1662
|
+
if (!isLiveRetime(retime) || typeof animation.position !== "number") return touched;
|
|
1663
|
+
const ratio = retime.newDuration / retime.oldDuration;
|
|
1664
|
+
if (hasExplicitTime(animation)) {
|
|
1665
|
+
const scaled = retime.newStart + (animation.position - retime.oldStart) * ratio;
|
|
1666
|
+
animation.position = Math.max(0, Math.round(scaled * 1e3) / 1e3);
|
|
1667
|
+
touched.position = true;
|
|
1668
|
+
}
|
|
1669
|
+
if (typeof animation.duration === "number" && animation.duration > 0) {
|
|
1670
|
+
animation.duration = Math.max(1e-3, Math.round(animation.duration * ratio * 1e3) / 1e3);
|
|
1671
|
+
touched.duration = true;
|
|
1672
|
+
}
|
|
1673
|
+
return touched;
|
|
1674
|
+
}
|
|
1675
|
+
function retimeClipTweensInScript(script, retimes, root) {
|
|
1676
|
+
const changed = retimes.map(() => false);
|
|
1677
|
+
const parsed = retimes.some(isLiveRetime) ? parseGsapScriptAcornForWrite(script) : null;
|
|
1678
|
+
if (!parsed) return { script, changed };
|
|
1679
|
+
const queries = /* @__PURE__ */ new Map();
|
|
1680
|
+
const matchers = retimes.map((r) => clipTweenMatcher(r.targetSelector, root, queries));
|
|
1627
1681
|
const ms = new MagicString(script);
|
|
1628
|
-
let
|
|
1682
|
+
let wrote = false;
|
|
1629
1683
|
for (const entry of parsed.located) {
|
|
1630
|
-
|
|
1631
|
-
|
|
1632
|
-
|
|
1684
|
+
const animation = { ...entry.animation };
|
|
1685
|
+
let position = false;
|
|
1686
|
+
let duration = false;
|
|
1687
|
+
retimes.forEach((retime, i) => {
|
|
1688
|
+
if (!matchers[i](animation)) return;
|
|
1689
|
+
const before = [animation.position, animation.duration];
|
|
1690
|
+
const touched = applyRetime(animation, retime);
|
|
1691
|
+
position ||= touched.position;
|
|
1692
|
+
duration ||= touched.duration;
|
|
1693
|
+
if (before[0] !== animation.position || before[1] !== animation.duration) changed[i] = true;
|
|
1694
|
+
});
|
|
1695
|
+
if (position) overwritePosition(ms, entry.call, animation.position);
|
|
1696
|
+
if (duration) upsertProp(ms, entry.call.varsArg, "duration", animation.duration);
|
|
1697
|
+
wrote ||= position || duration;
|
|
1633
1698
|
}
|
|
1634
|
-
return
|
|
1699
|
+
return { script: wrote ? ms.toString() : script, changed };
|
|
1635
1700
|
}
|
|
1636
1701
|
function copyAnimationsInScript(script, fromSelector, toSelector, delta) {
|
|
1637
1702
|
const parsed = parseGsapScriptAcornForWrite(script);
|
|
@@ -1703,29 +1768,11 @@ function isLoopOrForEach(node) {
|
|
|
1703
1768
|
return isLoopNode(node) || isForEachStatement(node) || node?.type === "DoWhileStatement";
|
|
1704
1769
|
}
|
|
1705
1770
|
function scalePositionsInScript(script, targetSelector, oldStart, oldDuration, newStart, newDuration, root) {
|
|
1706
|
-
|
|
1707
|
-
|
|
1708
|
-
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
|
-
const ms = new MagicString(script);
|
|
1712
|
-
let changed = false;
|
|
1713
|
-
for (const entry of parsed.located) {
|
|
1714
|
-
if (!carries(entry.animation) || typeof entry.animation.position !== "number") continue;
|
|
1715
|
-
if (hasExplicitTime(entry.animation)) {
|
|
1716
|
-
const newPos = Math.max(
|
|
1717
|
-
0,
|
|
1718
|
-
Math.round((newStart + (entry.animation.position - oldStart) * ratio) * 1e3) / 1e3
|
|
1719
|
-
);
|
|
1720
|
-
overwritePosition(ms, entry.call, newPos);
|
|
1721
|
-
}
|
|
1722
|
-
if (typeof entry.animation.duration === "number" && entry.animation.duration > 0) {
|
|
1723
|
-
const newDur = Math.max(1e-3, Math.round(entry.animation.duration * ratio * 1e3) / 1e3);
|
|
1724
|
-
upsertProp(ms, entry.call.varsArg, "duration", newDur);
|
|
1725
|
-
}
|
|
1726
|
-
changed = true;
|
|
1727
|
-
}
|
|
1728
|
-
return changed ? ms.toString() : script;
|
|
1771
|
+
return retimeClipTweensInScript(
|
|
1772
|
+
script,
|
|
1773
|
+
[{ kind: "scale", targetSelector, oldStart, oldDuration, newStart, newDuration }],
|
|
1774
|
+
root
|
|
1775
|
+
).script;
|
|
1729
1776
|
}
|
|
1730
1777
|
function addAnimationToScript(script, animation) {
|
|
1731
1778
|
const parsed = parseGsapScriptAcornForWrite(script);
|
|
@@ -1999,7 +2046,7 @@ function updateKeyframeInScript(script, animationId, percentage, properties, eas
|
|
|
1999
2046
|
const parsed = parseGsapScriptAcornForWrite(script);
|
|
2000
2047
|
if (!parsed) return script;
|
|
2001
2048
|
const target = parsed.located.find((l) => l.id === animationId);
|
|
2002
|
-
if (!target) return script;
|
|
2049
|
+
if (!target || target.animation.hasUnresolvedKeyframes) return script;
|
|
2003
2050
|
const kfPropNode = findPropertyNode2(target.call.varsArg, "keyframes");
|
|
2004
2051
|
if (!kfPropNode) {
|
|
2005
2052
|
return updateMotionPathKeyframe(script, target, percentage, properties, ease) ?? script;
|
|
@@ -2067,7 +2114,7 @@ function locateWithKeyframes(script, animationId) {
|
|
|
2067
2114
|
if (!parsed) return null;
|
|
2068
2115
|
const convertedId = animationId.replace(/-from-|-fromTo-/, "-to-");
|
|
2069
2116
|
const target = parsed.located.find((l) => l.id === animationId) ?? parsed.located.find((l) => l.id === convertedId);
|
|
2070
|
-
if (!target) return null;
|
|
2117
|
+
if (!target || target.animation.hasUnresolvedKeyframes) return null;
|
|
2071
2118
|
const kfPropNode = findPropertyNode2(target.call.varsArg, "keyframes");
|
|
2072
2119
|
if (!kfPropNode || kfPropNode.value?.type !== "ObjectExpression") return null;
|
|
2073
2120
|
return { script, parsed, target, kfNode: kfPropNode.value };
|
|
@@ -2091,8 +2138,12 @@ function convertArrayKeyframesToObject(script, target) {
|
|
|
2091
2138
|
return `${JSON.stringify(`${timing.percentages[i]}%`)}: ${recordToCode(record)}`;
|
|
2092
2139
|
});
|
|
2093
2140
|
const ms = new MagicString(script);
|
|
2094
|
-
ms.overwrite(
|
|
2095
|
-
|
|
2141
|
+
ms.overwrite(
|
|
2142
|
+
kfPropNode.value.start,
|
|
2143
|
+
kfPropNode.value.end,
|
|
2144
|
+
`{ ${entries.join(", ")}, easeEach: "none" }`
|
|
2145
|
+
);
|
|
2146
|
+
if (findPropertyNode2(target.call.varsArg, "duration") === void 0) {
|
|
2096
2147
|
upsertProp(ms, target.call.varsArg, "duration", timing.totalDuration);
|
|
2097
2148
|
}
|
|
2098
2149
|
return ms.toString();
|
|
@@ -2102,7 +2153,7 @@ function ensureKeyframesNode(script, animationId) {
|
|
|
2102
2153
|
if (direct) return direct;
|
|
2103
2154
|
const parsed = parseGsapScriptAcornForWrite(script);
|
|
2104
2155
|
const target = parsed?.located.find((l) => l.id === animationId);
|
|
2105
|
-
if (!target) return null;
|
|
2156
|
+
if (!target || target.animation.hasUnresolvedKeyframes) return null;
|
|
2106
2157
|
const kfProp = findPropertyNode2(target.call.varsArg, "keyframes");
|
|
2107
2158
|
if (kfProp?.value?.type === "ArrayExpression") {
|
|
2108
2159
|
const normalized = convertArrayKeyframesToObject(script, target);
|
|
@@ -2204,7 +2255,7 @@ function removeKeyframeFromScript(script, animationId, percentage) {
|
|
|
2204
2255
|
const parsed = parseGsapScriptAcornForWrite(script);
|
|
2205
2256
|
if (!parsed) return script;
|
|
2206
2257
|
const target = parsed.located.find((l) => l.id === animationId);
|
|
2207
|
-
if (!target) return script;
|
|
2258
|
+
if (!target || target.animation.hasUnresolvedKeyframes) return script;
|
|
2208
2259
|
const kfPropNode = findPropertyNode2(target.call.varsArg, "keyframes");
|
|
2209
2260
|
if (!kfPropNode) return script;
|
|
2210
2261
|
if (kfPropNode.value?.type === "ArrayExpression") {
|
|
@@ -2343,7 +2394,7 @@ function convertToKeyframesFromScript(script, animationId, resolvedFromValues, s
|
|
|
2343
2394
|
const target = parsed.located.find((l) => l.id === animationId);
|
|
2344
2395
|
if (!target) return script;
|
|
2345
2396
|
const { animation, call } = target;
|
|
2346
|
-
if (animation
|
|
2397
|
+
if (authorsKeyframes(animation)) return script;
|
|
2347
2398
|
const isSet = call.method === "set";
|
|
2348
2399
|
const { fromProps, toProps } = resolveConversionProps(animation, resolvedFromValues);
|
|
2349
2400
|
const ms = new MagicString(script);
|
|
@@ -2559,6 +2610,7 @@ function splitIntoPropertyGroupsFromScript(script, animationId) {
|
|
|
2559
2610
|
const target = parsed.located.find((l) => l.id === animationId);
|
|
2560
2611
|
if (!target) return { script, ids: [animationId] };
|
|
2561
2612
|
const { animation } = target;
|
|
2613
|
+
if (animation.hasUnresolvedKeyframes) return { script, ids: [animationId] };
|
|
2562
2614
|
const allPropKeys = collectPropertyKeys(animation);
|
|
2563
2615
|
const groupProps = partitionPropertyGroups(allPropKeys);
|
|
2564
2616
|
if (groupProps.size <= 1) return { script, ids: [animationId] };
|
|
@@ -2879,8 +2931,8 @@ function computeForwardBaselines(matching, splitTime) {
|
|
|
2879
2931
|
const pos = typeof anim.position === "number" ? anim.position : 0;
|
|
2880
2932
|
const dur = anim.duration ?? 0;
|
|
2881
2933
|
const animEnd = pos + dur;
|
|
2882
|
-
if (anim
|
|
2883
|
-
const kfs = anim.keyframes
|
|
2934
|
+
if (authorsKeyframes(anim)) {
|
|
2935
|
+
const kfs = anim.keyframes?.keyframes ?? [];
|
|
2884
2936
|
if (pos >= splitTime) {
|
|
2885
2937
|
} else if (animEnd > splitTime) {
|
|
2886
2938
|
for (const kf of kfs) {
|
|
@@ -2941,17 +2993,22 @@ function buildSpanningSplit(result, anim, pos, dur, fromSource, ctx) {
|
|
|
2941
2993
|
extras: anim.extras
|
|
2942
2994
|
}).script;
|
|
2943
2995
|
}
|
|
2996
|
+
function applyKeyframedTweenSplit(result, anim, pos, animEnd, ctx, skippedSelectors) {
|
|
2997
|
+
if (pos >= ctx.splitTime)
|
|
2998
|
+
return updateAnimationSelectorInScript(result, anim.id, ctx.newSelector);
|
|
2999
|
+
if (animEnd > ctx.splitTime) {
|
|
3000
|
+
skippedSelectors.push(`${ctx.originalSelector} (keyframes spanning split)`);
|
|
3001
|
+
} else if (anim.hasUnresolvedKeyframes) {
|
|
3002
|
+
skippedSelectors.push(`${ctx.originalSelector} (unreadable keyframes before split)`);
|
|
3003
|
+
}
|
|
3004
|
+
return result;
|
|
3005
|
+
}
|
|
2944
3006
|
function applyTweenSplit(result, anim, baselineBefore, ctx, skippedSelectors) {
|
|
2945
3007
|
const pos = typeof anim.position === "number" ? anim.position : 0;
|
|
2946
3008
|
const dur = anim.duration ?? 0;
|
|
2947
3009
|
const animEnd = pos + dur;
|
|
2948
|
-
if (anim
|
|
2949
|
-
|
|
2950
|
-
return updateAnimationSelectorInScript(result, anim.id, ctx.newSelector);
|
|
2951
|
-
if (animEnd > ctx.splitTime) {
|
|
2952
|
-
skippedSelectors.push(`${ctx.originalSelector} (keyframes spanning split)`);
|
|
2953
|
-
}
|
|
2954
|
-
return result;
|
|
3010
|
+
if (authorsKeyframes(anim)) {
|
|
3011
|
+
return applyKeyframedTweenSplit(result, anim, pos, animEnd, ctx, skippedSelectors);
|
|
2955
3012
|
}
|
|
2956
3013
|
if (animEnd <= ctx.splitTime) return result;
|
|
2957
3014
|
if (pos >= ctx.splitTime)
|
|
@@ -3180,6 +3237,7 @@ export {
|
|
|
3180
3237
|
removePropertyFromAnimation,
|
|
3181
3238
|
replaceTweenWithKeyframesInScript,
|
|
3182
3239
|
resizeKeyframedTweenInScript,
|
|
3240
|
+
retimeClipTweensInScript,
|
|
3183
3241
|
scalePositionsInScript,
|
|
3184
3242
|
setArcPathInScript,
|
|
3185
3243
|
shiftPositionsInScript,
|