@hyperframes/parsers 0.8.115 → 0.8.117

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.
@@ -15,6 +15,11 @@ type PositionWrite = Pick<GsapAnimation, "propertyGroup" | "properties" | "fromP
15
15
  declare function isXYPositionWrite(a: PositionWrite): boolean;
16
16
  declare function classifyPropertyGroup(prop: string): PropertyGroupName;
17
17
  declare function classifyTweenPropertyGroup(properties: Record<string, unknown>): PropertyGroupName | undefined;
18
+ /**
19
+ * What a Studio hold pins from t=0 before a later keyframed tween: its first keyframe's position props,
20
+ * minus those an earlier timeline tween on the target writes (a global `gsap.set` is a base value).
21
+ */
22
+ declare function positionHoldForAnimation(animation: GsapAnimation, animations: readonly GsapAnimation[]): Record<string, number> | null;
18
23
  declare const SUPPORTED_EASES: string[];
19
24
 
20
25
  /**
@@ -203,4 +208,4 @@ declare function gsapAnimationsToKeyframes(animations: GsapAnimation[], elementS
203
208
  skipBaseSet?: boolean;
204
209
  }): Keyframe[];
205
210
 
206
- export { type ArcPathConfig as A, type GsapAnimation as G, type KeyframeEditability as K, type MotionPathShape as M, PROPERTY_GROUPS as P, SUPPORTED_EASES as S, type ArcPathSegment as a, type GsapKeyframesData as b, type GsapMethod as c, type GsapPercentageKeyframe as d, type GsapProvenance as e, type GsapProvenanceKind as f, type ParsedGsap as g, type PropertyGroupName as h, SUPPORTED_PROPS as i, type SourcedGsapPercentageKeyframe as j, type SplitAnimationsOptions as k, type SplitAnimationsResult as l, classifyPropertyGroup as m, classifyTweenPropertyGroup as n, editabilityForProvenance as o, getAnimationsForElementId as p, gsapAnimationsToKeyframes as q, keyframesToGsapAnimations as r, serializeGsapAnimations as s, buildArcPath as t, type GsapKeyframeFormat as u, validateCompositionGsap as v, isXYPositionWrite as w };
211
+ export { type ArcPathConfig as A, type GsapAnimation as G, type KeyframeEditability as K, type MotionPathShape as M, PROPERTY_GROUPS as P, SUPPORTED_EASES as S, type ArcPathSegment as a, type GsapKeyframesData as b, type GsapMethod as c, type GsapPercentageKeyframe as d, type GsapProvenance as e, type GsapProvenanceKind as f, type ParsedGsap as g, type PropertyGroupName as h, SUPPORTED_PROPS as i, type SourcedGsapPercentageKeyframe as j, type SplitAnimationsOptions as k, type SplitAnimationsResult as l, classifyPropertyGroup as m, classifyTweenPropertyGroup as n, editabilityForProvenance as o, getAnimationsForElementId as p, gsapAnimationsToKeyframes as q, keyframesToGsapAnimations as r, serializeGsapAnimations as s, buildArcPath as t, type GsapKeyframeFormat as u, validateCompositionGsap as v, isXYPositionWrite as w, positionHoldForAnimation as x };
@@ -1,4 +1,4 @@
1
- import { G as GsapAnimation, A as ArcPathConfig, k as SplitAnimationsOptions, l as SplitAnimationsResult, a as ArcPathSegment } from './gsapSerialize-g8oprts9.js';
1
+ import { G as GsapAnimation, A as ArcPathConfig, k as SplitAnimationsOptions, l as SplitAnimationsResult, a as ArcPathSegment } from './gsapSerialize-CVwsMItk.js';
2
2
  import './types-Ejqndkej.js';
3
3
 
4
4
  type TweenTarget = Pick<GsapAnimation, "targetSelector" | "hasPartialSelector">;
@@ -101,6 +101,23 @@ declare function materializeKeyframesFromScript(script: string, animationId: str
101
101
  properties: Record<string, number | string>;
102
102
  ease?: string;
103
103
  }>, easeEach?: string, resolvedSelector?: string): string;
104
+ /**
105
+ * Rewrites a tween as `to()` with these keyframes where it stands: the call keeps its place in the
106
+ * script and its position argument, so a tween placed after it ('>', '<', '+=', none) stays put.
107
+ */
108
+ declare function replaceTweenWithKeyframesInScript(script: string, animationId: string, edit: {
109
+ targetSelector: string;
110
+ position: number;
111
+ duration: number;
112
+ keyframes: Array<{
113
+ percentage: number;
114
+ properties: Record<string, number | string>;
115
+ ease?: string;
116
+ auto?: boolean;
117
+ }>;
118
+ ease?: string;
119
+ easeEach?: string;
120
+ }): string | null;
104
121
  /** Insert a new keyframed `to()` call and return the new animation ID. */
105
122
  declare function addAnimationWithKeyframesToScript(script: string, targetSelector: string, position: number, duration: number, keyframes: Array<{
106
123
  percentage: number;
@@ -160,4 +177,4 @@ type UnrollElement = {
160
177
  */
161
178
  declare function unrollDynamicAnimations(script: string, animationId: string, elements: UnrollElement[]): string;
162
179
 
163
- export { type UnrollElement, addAnimationToScript, addAnimationWithKeyframesToScript, addKeyframeToScript, addLabelToScript, addMotionPathPointInScript, addMotionPathToScript, clipQueryRoot, clipTweenMatcher, convertToKeyframesFromScript, copyAnimationsInScript, dedupePositionWritesInScript, hasExplicitTime, materializeKeyframesFromScript, moveKeyframeInScript, removeAllKeyframesFromScript, removeAnimationFromScript, removeArcPathFromScript, removeKeyframeFromScript, removeLabelFromScript, removeMotionPathPointInScript, removePropertyFromAnimation, resizeKeyframedTweenInScript, scalePositionsInScript, setArcPathInScript, shiftPositionsInScript, splitAnimationsInScript, splitIntoPropertyGroupsFromScript, syncPositionHoldsBeforeKeyframes, unrollDynamicAnimations, updateAnimationInScript, updateArcSegmentInScript, updateKeyframeInScript, updateMotionPathPointInScript };
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 };
@@ -14,9 +14,11 @@ var PROP_TO_GROUP = /* @__PURE__ */ new Map();
14
14
  for (const [group, props] of Object.entries(PROPERTY_GROUPS)) {
15
15
  for (const p of props) PROP_TO_GROUP.set(p, group);
16
16
  }
17
+ function writesProperty(animation, property) {
18
+ return property in animation.properties || !!animation.fromProperties && property in animation.fromProperties || !!animation.keyframes?.keyframes.some((k) => property in k.properties);
19
+ }
17
20
  function isXYPositionWrite(a) {
18
- const xy = (props) => !!props && ("x" in props || "y" in props);
19
- return a.propertyGroup === "position" && (xy(a.properties) || xy(a.fromProperties) || !!a.keyframes?.keyframes.some((k) => xy(k.properties)));
21
+ return a.propertyGroup === "position" && (writesProperty(a, "x") || writesProperty(a, "y"));
20
22
  }
21
23
  function classifyPropertyGroup(prop) {
22
24
  return PROP_TO_GROUP.get(prop) ?? "other";
@@ -31,6 +33,30 @@ function classifyTweenPropertyGroup(properties) {
31
33
  if (groups.size === 1) return groups.values().next().value;
32
34
  return void 0;
33
35
  }
36
+ function knownStart(animation) {
37
+ if (animation.resolvedStart !== void 0) return animation.resolvedStart;
38
+ return typeof animation.position === "number" ? animation.position : void 0;
39
+ }
40
+ function positionHoldForAnimation(animation, animations) {
41
+ if (!animation.keyframes) return null;
42
+ const start = knownStart(animation) ?? 0;
43
+ if (!(start > 1e-3)) return null;
44
+ const first = [...animation.keyframes.keyframes].sort(
45
+ (left, right) => left.percentage - right.percentage
46
+ )[0];
47
+ if (!first) return null;
48
+ const earlier = animations.filter((other) => {
49
+ const otherStart = knownStart(other);
50
+ return other !== animation && !other.global && other.targetSelector === animation.targetSelector && otherStart !== void 0 && otherStart < start - 1e-3;
51
+ });
52
+ const position = {};
53
+ for (const [property, value] of Object.entries(first.properties)) {
54
+ if (classifyPropertyGroup(property) !== "position" || typeof value !== "number") continue;
55
+ if (earlier.some((other) => writesProperty(other, property))) continue;
56
+ position[property] = value;
57
+ }
58
+ return Object.keys(position).length > 0 ? position : null;
59
+ }
34
60
 
35
61
  // src/gsapSerialize.ts
36
62
  function mergePercentageKeyframes(keyframes) {
@@ -1219,6 +1245,41 @@ function resolveTimelinePositions(anims, labelDefs = []) {
1219
1245
  });
1220
1246
  while (labelIdx < sortedLabels.length) defineLabel(sortedLabels[labelIdx++]);
1221
1247
  }
1248
+ function collectAddLabelDefs(ast, ref, scope, sortedCalls) {
1249
+ const callKeys = sortedCalls.map((c) => ({
1250
+ site: callSiteStart(c),
1251
+ order: c.node.__hfOrder
1252
+ }));
1253
+ const comesAfter = (site, order, labelSite, labelOrder) => {
1254
+ if (site === void 0) return false;
1255
+ if (site !== labelSite) return site > labelSite;
1256
+ return (order ?? -Infinity) > (labelOrder ?? -Infinity);
1257
+ };
1258
+ const defs = [];
1259
+ acornWalk.simple(ast, {
1260
+ // fallow-ignore-next-line complexity
1261
+ CallExpression(node) {
1262
+ const callee = node.callee;
1263
+ const objMatches = ref.kind === "identifier" ? callee.object?.type === "Identifier" && callee.object.name === ref.name : sameMemberAccess(callee.object, ref.node);
1264
+ if (callee?.type !== "MemberExpression" || !objMatches || callee.property?.name !== "addLabel")
1265
+ return;
1266
+ const nameNode = node.arguments?.[0];
1267
+ const name = typeof nameNode?.value === "string" ? nameNode.value : void 0;
1268
+ if (!name) return;
1269
+ const posVal = resolveNode(node.arguments?.[1], scope);
1270
+ const position = typeof posVal === "number" || typeof posVal === "string" ? posVal : void 0;
1271
+ const labelStart = node.__hfSiteStart ?? callee.property?.start;
1272
+ const labelOrder = node.__hfOrder;
1273
+ let order = sortedCalls.length;
1274
+ if (labelStart !== void 0) {
1275
+ order = callKeys.findIndex((k) => comesAfter(k.site, k.order, labelStart, labelOrder));
1276
+ if (order === -1) order = sortedCalls.length;
1277
+ }
1278
+ defs.push({ name, position, order });
1279
+ }
1280
+ });
1281
+ return defs;
1282
+ }
1222
1283
  function compareByLoc(a, b) {
1223
1284
  const aLoc = a.node.callee?.property?.loc?.start;
1224
1285
  const bLoc = b.node.callee?.property?.loc?.start;
@@ -1271,7 +1332,7 @@ function parseGsapScriptAcornForWrite(script) {
1271
1332
  (call) => tweenCallToAnimation(call, scope, script, identifierBindings)
1272
1333
  );
1273
1334
  applyTimelineDefaults(rawAnims, detection.defaults);
1274
- resolveTimelinePositions(rawAnims);
1335
+ resolveTimelinePositions(rawAnims, collectAddLabelDefs(ast, ref, scope, calls));
1275
1336
  const animations = assignStableIds(rawAnims);
1276
1337
  const located = calls.map((call, i) => ({
1277
1338
  id: animations[i].id,
@@ -1559,7 +1620,8 @@ function overwritePosition(ms, call, position) {
1559
1620
  if (call.positionArg) {
1560
1621
  ms.overwrite(call.positionArg.start, call.positionArg.end, valueToCode(position));
1561
1622
  } else {
1562
- ms.appendLeft(call.node.end - 1, `, ${valueToCode(position)}`);
1623
+ const last = call.node.arguments.at(-1);
1624
+ ms.appendLeft(last ? last.end : call.node.end - 1, `, ${valueToCode(position)}`);
1563
1625
  }
1564
1626
  }
1565
1627
  function shiftPositionsInScript(script, targetSelector, delta, root) {
@@ -2362,6 +2424,33 @@ function materializeKeyframesFromScript(script, animationId, keyframes, easeEach
2362
2424
  }
2363
2425
  return ms.toString();
2364
2426
  }
2427
+ function replaceTweenWithKeyframesInScript(script, animationId, edit) {
2428
+ const parsed = parseGsapScriptAcornForWrite(script);
2429
+ const target = parsed?.located.find((l) => l.id === animationId);
2430
+ const call = target?.call;
2431
+ if (!target || call?.varsArg?.type !== "ObjectExpression") return null;
2432
+ const { animation } = target;
2433
+ if (animation.method !== "to" && animation.method !== "from" && animation.method !== "fromTo")
2434
+ return null;
2435
+ const ms = new MagicString(script);
2436
+ const start = animation.resolvedStart ?? animation.position;
2437
+ const moved = typeof start !== "number" || Math.abs(start - edit.position) > 5e-4;
2438
+ const kept = preservedVarsEntries(call.varsArg, script).filter(
2439
+ (e) => !/^\s*duration\s*:/.test(e) && !(moved && /^\s*delay\s*:/.test(e))
2440
+ );
2441
+ const sorted = [...edit.keyframes].sort((a, b) => a.percentage - b.percentage);
2442
+ const parts = [`keyframes: ${buildKeyframeObjectCode(sorted, edit.easeEach)}`, ...kept];
2443
+ parts.push(`duration: ${valueToCode(edit.duration)}`);
2444
+ if (edit.ease) parts.push(`ease: ${JSON.stringify(edit.ease)}`);
2445
+ if (animation.hasUnresolvedSelector || animation.targetSelector !== edit.targetSelector) {
2446
+ const selectorArg = call.node.arguments[0];
2447
+ ms.overwrite(selectorArg.start, selectorArg.end, JSON.stringify(edit.targetSelector));
2448
+ }
2449
+ convertMethodToTo(ms, animation, call, call.varsArg);
2450
+ overwriteVarsArg(ms, call, `{ ${parts.join(", ")} }`);
2451
+ if (moved) overwritePosition(ms, call, edit.position);
2452
+ return ms.toString();
2453
+ }
2365
2454
  function addAnimationWithKeyframesToScript(script, targetSelector, position, duration, keyframes, ease, easeEach) {
2366
2455
  const parsed = parseGsapScriptAcornForWrite(script);
2367
2456
  if (!parsed) return { script, id: "" };
@@ -2746,7 +2835,8 @@ function insertInheritedStateSetInScript(script, selector, position, properties)
2746
2835
  const tlDecl = findTimelineDeclarationStatement(parsed.ast, parsed.timelineVar);
2747
2836
  const firstLocated = parsed.located[0];
2748
2837
  if (tlDecl) {
2749
- ms.appendLeft(tlDecl.end, "\n" + code);
2838
+ const ownLineEnd = script[tlDecl.end] === "\n" ? "" : "\n";
2839
+ ms.appendLeft(tlDecl.end, "\n" + code + ownLineEnd);
2750
2840
  } else if (firstLocated) {
2751
2841
  const firstCall = firstLocated.call;
2752
2842
  const exprStmt = findEnclosingExpressionStatement(firstCall.ancestors);
@@ -2768,38 +2858,15 @@ function removeStudioHoldSets(script, parsed) {
2768
2858
  for (const hold of staleHolds) removeCallFromMagicString(ms, hold.call, script);
2769
2859
  return ms.toString();
2770
2860
  }
2771
- function animationStart(animation) {
2772
- if (animation.resolvedStart !== void 0) return animation.resolvedStart;
2773
- return typeof animation.position === "number" ? animation.position : 0;
2774
- }
2775
- function positionProperties(properties) {
2776
- const position = {};
2777
- for (const [property, value] of Object.entries(properties)) {
2778
- if (classifyPropertyGroup(property) === "position" && typeof value === "number") {
2779
- position[property] = value;
2780
- }
2781
- }
2782
- return position;
2783
- }
2784
- function positionHoldForAnimation(animation) {
2785
- if (!animation.keyframes) return null;
2786
- if (!(animationStart(animation) > 1e-3)) return null;
2787
- const first = [...animation.keyframes.keyframes].sort(
2788
- (left, right) => left.percentage - right.percentage
2789
- )[0];
2790
- if (!first) return null;
2791
- const position = positionProperties(first.properties);
2792
- return Object.keys(position).length > 0 ? position : null;
2793
- }
2794
2861
  function syncPositionHoldsBeforeKeyframes(script) {
2795
2862
  const parsed = parseGsapScriptAcornForWrite(script);
2796
2863
  if (!parsed) return script;
2797
2864
  let result = removeStudioHoldSets(script, parsed);
2798
2865
  const current = parseGsapScriptAcornForWrite(result);
2799
2866
  if (!current) return result;
2800
- for (const entry of current.located) {
2801
- const animation = entry.animation;
2802
- const position = positionHoldForAnimation(animation);
2867
+ const animations = current.located.map((entry) => entry.animation);
2868
+ for (const animation of animations) {
2869
+ const position = positionHoldForAnimation(animation, animations);
2803
2870
  if (!position) continue;
2804
2871
  result = insertInheritedStateSetInScript(result, animation.targetSelector, 0, {
2805
2872
  ...position,
@@ -3115,6 +3182,7 @@ export {
3115
3182
  removeLabelFromScript,
3116
3183
  removeMotionPathPointInScript,
3117
3184
  removePropertyFromAnimation,
3185
+ replaceTweenWithKeyframesInScript,
3118
3186
  resizeKeyframedTweenInScript,
3119
3187
  scalePositionsInScript,
3120
3188
  setArcPathInScript,