@hyperframes/parsers 0.8.126 → 0.8.128

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.
@@ -3,6 +3,7 @@ import * as recast from "recast";
3
3
  import { parse as babelParse } from "@babel/parser";
4
4
 
5
5
  // src/gsapConstants.ts
6
+ var GSAP_DEFAULT_DURATION = 0.5;
6
7
  var SUPPORTED_PROPS = [
7
8
  // 2D Transforms
8
9
  "x",
@@ -43,6 +44,25 @@ var SUPPORTED_PROPS = [
43
44
  // DOM content (number counters, text roll-ups)
44
45
  "innerText"
45
46
  ];
47
+ var BUILTIN_VAR_KEYS = /* @__PURE__ */ new Set(["duration", "ease", "delay"]);
48
+ var DROPPED_VAR_KEYS = /* @__PURE__ */ new Set([
49
+ "onComplete",
50
+ "onStart",
51
+ "onUpdate",
52
+ "onRepeat"
53
+ ]);
54
+ var EXTRAS_KEYS = /* @__PURE__ */ new Set([
55
+ "stagger",
56
+ "yoyo",
57
+ "repeat",
58
+ "repeatDelay",
59
+ "snap",
60
+ "overwrite",
61
+ "immediateRender"
62
+ ]);
63
+ function isTweenConfigKey(key) {
64
+ return BUILTIN_VAR_KEYS.has(key) || DROPPED_VAR_KEYS.has(key) || EXTRAS_KEYS.has(key);
65
+ }
46
66
  var PROPERTY_GROUPS = {
47
67
  position: /* @__PURE__ */ new Set(["x", "y", "xPercent", "yPercent"]),
48
68
  scale: /* @__PURE__ */ new Set(["scale", "scaleX", "scaleY"]),
@@ -82,16 +102,14 @@ function positionHoldForAnimation(animation, animations) {
82
102
  if (!animation.keyframes) return null;
83
103
  const start = knownStart(animation) ?? 0;
84
104
  if (!(start > 1e-3)) return null;
85
- const first = [...animation.keyframes.keyframes].sort(
86
- (left, right) => left.percentage - right.percentage
87
- )[0];
88
- if (!first) return null;
105
+ const atStart = animation.keyframes.keyframes.find((keyframe) => keyframe.percentage === 0);
106
+ if (!atStart) return null;
89
107
  const earlier = animations.filter((other) => {
90
108
  const otherStart = knownStart(other);
91
109
  return other !== animation && !other.global && other.targetSelector === animation.targetSelector && otherStart !== void 0 && otherStart < start - 1e-3;
92
110
  });
93
111
  const position = {};
94
- for (const [property, value] of Object.entries(first.properties)) {
112
+ for (const [property, value] of Object.entries(atStart.properties)) {
95
113
  if (classifyPropertyGroup(property) !== "position" || typeof value !== "number") continue;
96
114
  if (earlier.some((other) => writesProperty(other, property))) continue;
97
115
  position[property] = value;
@@ -137,6 +155,9 @@ var SUPPORTED_EASES = [
137
155
  ];
138
156
 
139
157
  // src/gsapSerialize.ts
158
+ function authorsKeyframes(anim) {
159
+ return anim.keyframes !== void 0 || anim.hasUnresolvedKeyframes === true;
160
+ }
140
161
  function mergePercentageKeyframes(keyframes) {
141
162
  const byPercentage = /* @__PURE__ */ new Map();
142
163
  for (const keyframe of keyframes) {
@@ -382,14 +403,25 @@ function resolveConversionProps(anim, resolvedFromValues) {
382
403
  }
383
404
 
384
405
  // src/clipTweens.ts
385
- function clipTweenMatcher(clipSelectors, root) {
406
+ function clipTweenMatcher(clipSelectors, root, queries = /* @__PURE__ */ new Map()) {
386
407
  const own = typeof clipSelectors === "string" ? [clipSelectors] : clipSelectors;
387
- const clips = root ? own.flatMap((selector) => queryAll(root, selector)) : [];
408
+ if (!root)
409
+ return ({ targetSelector, hasPartialSelector }) => !hasPartialSelector && own.includes(targetSelector);
410
+ const queryAll = (selector) => {
411
+ if (ID_SELECTOR.test(selector)) {
412
+ if (!queries.has(ALL_IDS)) indexIds(root, queries);
413
+ return queries.get(selector) ?? [];
414
+ }
415
+ let found = queries.get(selector);
416
+ if (!found) queries.set(selector, found = queryRoot(root, selector));
417
+ return found;
418
+ };
419
+ const clips = own.flatMap((selector) => queryAll(selector));
388
420
  return ({ targetSelector, hasPartialSelector }) => {
389
421
  if (hasPartialSelector) return false;
390
422
  if (own.includes(targetSelector)) return true;
391
- if (!root || clips.length === 0) return false;
392
- const targets = queryAll(root, targetSelector);
423
+ if (clips.length === 0) return false;
424
+ const targets = queryAll(targetSelector);
393
425
  return targets.length > 0 && targets.every((target) => {
394
426
  const owner = target.closest("[data-start]");
395
427
  return clips.includes(target) || owner !== null && clips.includes(owner);
@@ -399,7 +431,20 @@ function clipTweenMatcher(clipSelectors, root) {
399
431
  function hasExplicitTime(animation) {
400
432
  return typeof animation.position === "number" && !animation.implicitPosition;
401
433
  }
402
- function queryAll(root, selector) {
434
+ var ID_SELECTOR = /^#-?[A-Za-z_][\w-]*$/;
435
+ var ALL_IDS = "[id]";
436
+ function indexIds(root, queries) {
437
+ const all = queryRoot(root, ALL_IDS);
438
+ queries.set(ALL_IDS, all);
439
+ for (const el of all) {
440
+ const key = `#${el.id}`;
441
+ if (!ID_SELECTOR.test(key)) continue;
442
+ const list = queries.get(key);
443
+ if (list) list.push(el);
444
+ else queries.set(key, [el]);
445
+ }
446
+ }
447
+ function queryRoot(root, selector) {
403
448
  try {
404
449
  return Array.from(root.querySelectorAll(selector));
405
450
  } catch {
@@ -411,34 +456,27 @@ function queryAll(root, selector) {
411
456
  var roundPercentage = (percentage) => Math.round(percentage * 10) / 10;
412
457
  var OBJECT_ARRAY_PERCENTAGE_TOLERANCE = 2;
413
458
  function getObjectArrayKeyframeTiming(durations) {
414
- const hasAuthoredDuration = durations.some((duration) => duration !== void 0);
415
- if (hasAuthoredDuration) {
416
- if (!durations.every(
417
- (duration) => typeof duration === "number" && Number.isFinite(duration) && duration > 0
418
- )) {
419
- return null;
420
- }
421
- const totalDuration = durations.reduce((sum, duration) => sum + duration, 0);
422
- let cumulative = 0;
423
- return {
424
- percentages: durations.map((duration) => {
425
- cumulative += duration;
426
- return roundPercentage(cumulative / totalDuration * 100);
427
- }),
428
- totalDuration
429
- };
459
+ const steps = durations.map((duration) => duration ?? GSAP_DEFAULT_DURATION);
460
+ if (!steps.every(
461
+ (duration) => typeof duration === "number" && Number.isFinite(duration) && duration > 0
462
+ )) {
463
+ return null;
430
464
  }
431
- const lastIndex = durations.length - 1;
465
+ const totalDuration = steps.reduce((sum, duration) => sum + duration, 0);
466
+ let cumulative = 0;
432
467
  return {
433
- percentages: durations.map(
434
- (_, index) => lastIndex > 0 ? roundPercentage(index / lastIndex * 100) : 0
435
- )
468
+ percentages: steps.map((duration) => {
469
+ cumulative += duration;
470
+ return roundPercentage(cumulative / totalDuration * 100);
471
+ }),
472
+ totalDuration
436
473
  };
437
474
  }
438
475
  function getCompatibleObjectArrayKeyframeTiming(durations, outerDuration) {
439
476
  const timing = getObjectArrayKeyframeTiming(durations);
440
477
  if (!timing) return null;
441
- if (timing.totalDuration === void 0 || outerDuration === void 0) return timing;
478
+ const stepsAuthorDuration = durations.some((duration) => duration !== void 0);
479
+ if (!stepsAuthorDuration || outerDuration === void 0) return timing;
442
480
  if (typeof outerDuration === "number" && Math.abs(outerDuration - timing.totalDuration) <= Number.EPSILON) {
443
481
  return timing;
444
482
  }
@@ -910,17 +948,6 @@ function findAllTweenCalls(ast, ref, scope, targetBindings, targetHelpers) {
910
948
  });
911
949
  return results;
912
950
  }
913
- var BUILTIN_VAR_KEYS = /* @__PURE__ */ new Set(["duration", "ease", "delay"]);
914
- var DROPPED_VAR_KEYS = /* @__PURE__ */ new Set(["onComplete", "onStart", "onUpdate", "onRepeat"]);
915
- var EXTRAS_KEYS = /* @__PURE__ */ new Set([
916
- "stagger",
917
- "yoyo",
918
- "repeat",
919
- "repeatDelay",
920
- "snap",
921
- "overwrite",
922
- "immediateRender"
923
- ]);
924
951
  function extractRawPropertySource(varsArgNode, key) {
925
952
  const node = findPropertyNode(varsArgNode, key);
926
953
  return node ? recast.print(node).code : void 0;
@@ -1193,7 +1220,7 @@ function tweenCallToAnimation(call, scope) {
1193
1220
  percentage: waypoints.length > 1 ? Math.round(i / (waypoints.length - 1) * 100) : 0,
1194
1221
  properties: { x: wp.x, y: wp.y }
1195
1222
  }));
1196
- keyframesData = { format: "percentage", keyframes: kf };
1223
+ keyframesData = { format: "percentage", keyframes: kf, fromMotionPath: true };
1197
1224
  } else {
1198
1225
  const kfs = keyframesData.keyframes;
1199
1226
  if (kfs.length === waypoints.length) {
@@ -1250,7 +1277,6 @@ function tweenCallToAnimation(call, scope) {
1250
1277
  if (call.selectorPartial) anim.hasPartialSelector = true;
1251
1278
  return anim;
1252
1279
  }
1253
- var GSAP_DEFAULT_DURATION = 0.5;
1254
1280
  function resolvePositionString(pos, cursor, prevStart) {
1255
1281
  const trimmed = pos.trim();
1256
1282
  if (trimmed === "") return cursor;
@@ -1282,7 +1308,7 @@ function applyTimelineDefaults(anims, defaults) {
1282
1308
  if (anim.duration === void 0 && defaults.duration !== void 0) {
1283
1309
  anim.duration = defaults.duration;
1284
1310
  }
1285
- if (anim.ease === void 0 && defaults.ease !== void 0) {
1311
+ if (anim.ease === void 0 && defaults.ease !== void 0 && (!anim.keyframes || anim.keyframes.fromMotionPath)) {
1286
1312
  anim.ease = defaults.ease;
1287
1313
  }
1288
1314
  }
@@ -1391,7 +1417,7 @@ function isObjectProperty(prop) {
1391
1417
  return prop?.type === "ObjectProperty" || prop?.type === "Property";
1392
1418
  }
1393
1419
  function isEditablePropertyKey(key) {
1394
- return !BUILTIN_VAR_KEYS.has(key) && !DROPPED_VAR_KEYS.has(key) && !EXTRAS_KEYS.has(key);
1420
+ return !isTweenConfigKey(key);
1395
1421
  }
1396
1422
  function makeObjectProperty(key, value) {
1397
1423
  const obj = parseExpr(`{ ${safeJsKey(key)}: ${serializeValue(value)} }`);
@@ -1518,7 +1544,7 @@ function updateAnimationInScript(script, animationId, updates) {
1518
1544
  return script;
1519
1545
  }
1520
1546
  const target = parsed.located.find((l) => l.id === animationId);
1521
- if (!target) return script;
1547
+ if (!target || updates.properties && target.animation.hasUnresolvedKeyframes) return script;
1522
1548
  applyUpdatesToCall(target.call, updates);
1523
1549
  return recast.print(parsed.ast).code;
1524
1550
  }
@@ -1788,12 +1814,12 @@ function splitAnimationsInScript(script, opts) {
1788
1814
  const pos = typeof anim.position === "number" ? anim.position : 0;
1789
1815
  const dur = anim.duration ?? 0;
1790
1816
  const animEnd = pos + dur;
1791
- if (anim.keyframes) {
1817
+ if (authorsKeyframes(anim)) {
1792
1818
  if (pos >= opts.splitTime) {
1793
1819
  result = updateAnimationSelector(result, anim.id, newSelector);
1794
1820
  } else if (animEnd > opts.splitTime) {
1795
1821
  skippedSelectors.push(`${originalSelector} (keyframes spanning split)`);
1796
- const kfs = anim.keyframes.keyframes;
1822
+ const kfs = anim.keyframes?.keyframes ?? [];
1797
1823
  for (const kf of kfs) {
1798
1824
  const kfTime = pos + kf.percentage / 100 * dur;
1799
1825
  if (kfTime <= opts.splitTime) {
@@ -1803,7 +1829,10 @@ function splitAnimationsInScript(script, opts) {
1803
1829
  }
1804
1830
  }
1805
1831
  } else {
1806
- const kfs = anim.keyframes.keyframes;
1832
+ if (anim.hasUnresolvedKeyframes) {
1833
+ skippedSelectors.push(`${originalSelector} (unreadable keyframes before split)`);
1834
+ }
1835
+ const kfs = anim.keyframes?.keyframes ?? [];
1807
1836
  if (kfs.length > 0) {
1808
1837
  for (const [k, v] of Object.entries(kfs[kfs.length - 1].properties)) {
1809
1838
  inheritedProps[k] = v;
@@ -1983,7 +2012,7 @@ function convertArrayKeyframesToObjectNode(varsArg, scope) {
1983
2012
  outerDuration
1984
2013
  );
1985
2014
  if (!timing) return null;
1986
- if (timing.totalDuration !== void 0 && findPropertyNode(varsArg, "duration") === void 0) {
2015
+ if (findPropertyNode(varsArg, "duration") === void 0) {
1987
2016
  setVarsKey(varsArg, "duration", timing.totalDuration);
1988
2017
  }
1989
2018
  const entries = els.map((el, i) => {
@@ -1992,7 +2021,7 @@ function convertArrayKeyframesToObjectNode(varsArg, scope) {
1992
2021
  );
1993
2022
  return `${JSON.stringify(`${timing.percentages[i]}%`)}: ${recast.print(el).code}`;
1994
2023
  });
1995
- prop.value = parseExpr(`{ ${entries.join(", ")} }`);
2024
+ prop.value = parseExpr(`{ ${entries.join(", ")}, easeEach: "none" }`);
1996
2025
  return prop.value;
1997
2026
  }
1998
2027
  function filterPercentageProps(kfNode) {
@@ -2292,7 +2321,7 @@ function convertToKeyframesInScript(script, animationId, resolvedFromValues, set
2292
2321
  let loc = locateAnimationWithFallback(script, animationId);
2293
2322
  if (!loc) return script;
2294
2323
  const anim = loc.target.animation;
2295
- if (anim.keyframes) return script;
2324
+ if (authorsKeyframes(anim)) return script;
2296
2325
  const { fromProps, toProps } = resolveConversionProps(anim, resolvedFromValues);
2297
2326
  const varsArg = loc.target.call.varsArg;
2298
2327
  const originalEase = anim.ease;
@@ -2627,6 +2656,7 @@ function splitIntoPropertyGroups(script, animationId) {
2627
2656
  let loc = locateAnimationWithFallback(script, animationId);
2628
2657
  if (!loc) return { script, ids: [animationId] };
2629
2658
  const anim = loc.target.animation;
2659
+ if (anim.hasUnresolvedKeyframes) return { script, ids: [animationId] };
2630
2660
  const allPropKeys = /* @__PURE__ */ new Set();
2631
2661
  if (anim.keyframes) {
2632
2662
  for (const kf of anim.keyframes.keyframes) {