@hyperframes/parsers 0.8.132 → 0.8.134

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.
@@ -1,2 +1,2 @@
1
- export { B as BUILTIN_VAR_KEYS, D as DROPPED_VAR_KEYS, E as EXTRAS_KEYS, u as GSAP_DEFAULT_DURATION, j as PROPERTY_GROUPS, k as PropertyGroupName, S as SUPPORTED_EASES, l as SUPPORTED_PROPS, m as classifyPropertyGroup, n as classifyTweenPropertyGroup, x as isTweenConfigKey, y as isXYPositionWrite, z as positionHoldForAnimation } from './gsapSerialize-CfSXM_Ez.js';
1
+ export { B as BUILTIN_VAR_KEYS, D as DROPPED_VAR_KEYS, E as EXTRAS_KEYS, u as GSAP_DEFAULT_DURATION, H as HoldScope, j as PROPERTY_GROUPS, k as PropertyGroupName, S as SUPPORTED_EASES, l as SUPPORTED_PROPS, m as classifyPropertyGroup, n as classifyTweenPropertyGroup, x as holdScope, y as isTweenConfigKey, z as isXYPositionWrite, C as keyframeHoldForAnimation } from './gsapSerialize-_tuK-qvB.js';
2
2
  import './types-Ejqndkej.js';
@@ -94,23 +94,43 @@ function knownStart(animation) {
94
94
  if (animation.resolvedStart !== void 0) return animation.resolvedStart;
95
95
  return typeof animation.position === "number" ? animation.position : void 0;
96
96
  }
97
- function positionHoldForAnimation(animation, animations) {
97
+ var tweenSignature = (a) => JSON.stringify([a.targetSelector, a.method, a.position, a.duration, a.properties, a.keyframes]);
98
+ function holdScope(before, previous) {
99
+ const kept = new Set(previous?.map(tweenSignature));
100
+ const held = /* @__PURE__ */ new Map();
101
+ for (const a of before.filter((b) => b.method === "set" && b.properties?.data === "hf-hold")) {
102
+ const props = held.get(a.targetSelector) ?? /* @__PURE__ */ new Map();
103
+ for (const [property, value] of Object.entries(a.properties)) props.set(property, value);
104
+ held.set(a.targetSelector, props);
105
+ }
106
+ return {
107
+ touched: (a) => previous !== null && !kept.has(tweenSignature(a)),
108
+ held: (selector) => held.get(selector) ?? /* @__PURE__ */ new Map()
109
+ };
110
+ }
111
+ function keyframeHoldForAnimation(animation, animations, scope) {
98
112
  if (!animation.keyframes) return null;
99
- const start = knownStart(animation) ?? 0;
100
- if (!(start > 1e-3)) return null;
113
+ const start = knownStart(animation);
114
+ const lone = animation.keyframes.keyframes.length === 1;
115
+ if (start === void 0 || !(start > 1e-3) && !lone) return null;
101
116
  const atStart = animation.keyframes.keyframes.find((keyframe) => keyframe.percentage === 0);
102
117
  if (!atStart) return null;
103
118
  const earlier = animations.filter((other) => {
104
119
  const otherStart = knownStart(other);
105
120
  return other !== animation && !other.global && other.targetSelector === animation.targetSelector && otherStart !== void 0 && otherStart < start - 1e-3;
106
121
  });
107
- const position = {};
122
+ const touched = scope.touched(animation);
123
+ const pinned = scope.held(animation.targetSelector);
124
+ const kept = (property, value) => touched ? pinned.has(property) : pinned.get(property) === value;
125
+ const pins = (group, property, value) => group === "position" && start > 1e-3 || (group === "position" || group === "size") && (lone && touched || kept(property, value));
126
+ const hold = {};
108
127
  for (const [property, value] of Object.entries(atStart.properties)) {
109
- if (classifyPropertyGroup(property) !== "position" || typeof value !== "number") continue;
128
+ if (!pins(classifyPropertyGroup(property), property, value) || typeof value !== "number")
129
+ continue;
110
130
  if (earlier.some((other) => writesProperty(other, property))) continue;
111
- position[property] = value;
131
+ hold[property] = value;
112
132
  }
113
- return Object.keys(position).length > 0 ? position : null;
133
+ return Object.keys(hold).length > 0 ? hold : null;
114
134
  }
115
135
  var SUPPORTED_EASES = [
116
136
  "none",
@@ -159,8 +179,9 @@ export {
159
179
  SUPPORTED_PROPS,
160
180
  classifyPropertyGroup,
161
181
  classifyTweenPropertyGroup,
182
+ holdScope,
162
183
  isTweenConfigKey,
163
184
  isXYPositionWrite,
164
- positionHoldForAnimation
185
+ keyframeHoldForAnimation
165
186
  };
166
187
  //# sourceMappingURL=gsapConstants.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/gsapConstants.ts"],"sourcesContent":["/**\n * GSAP property and ease constants.\n *\n * Extracted into a standalone module so browser code can import them\n * without pulling in gsapParser (which depends on recast / @babel/parser).\n */\n\nimport type { GsapAnimation } from \"./gsapSerialize.js\";\n\nexport const GSAP_DEFAULT_DURATION = 0.5;\n\nexport const SUPPORTED_PROPS = [\n // 2D Transforms\n \"x\",\n \"y\",\n \"scale\",\n \"scaleX\",\n \"scaleY\",\n \"rotation\",\n \"skewX\",\n \"skewY\",\n // 3D Transforms\n \"z\",\n \"rotationX\",\n \"rotationY\",\n \"rotationZ\",\n \"perspective\",\n \"transformPerspective\",\n \"transformOrigin\",\n // Visibility\n \"opacity\",\n \"visibility\",\n \"autoAlpha\",\n // Dimensions\n \"width\",\n \"height\",\n // Colors\n \"color\",\n \"backgroundColor\",\n \"borderColor\",\n // Box model\n \"borderRadius\",\n // Typography\n \"fontSize\",\n \"letterSpacing\",\n // Filter & Clipping\n \"filter\",\n \"clipPath\",\n // DOM content (number counters, text roll-ups)\n \"innerText\",\n];\n\n/** Keys stored on dedicated GsapAnimation fields (not in properties/extras). */\nexport const BUILTIN_VAR_KEYS: ReadonlySet<string> = new Set([\"duration\", \"ease\", \"delay\"]);\nexport const DROPPED_VAR_KEYS: ReadonlySet<string> = new Set([\n \"onComplete\",\n \"onStart\",\n \"onUpdate\",\n \"onRepeat\",\n]);\n/** Keys that go in `extras`: non-editable GSAP config that must survive round-trips. */\nexport const EXTRAS_KEYS: ReadonlySet<string> = new Set([\n \"stagger\",\n \"yoyo\",\n \"repeat\",\n \"repeatDelay\",\n \"snap\",\n \"overwrite\",\n \"immediateRender\",\n]);\n\nexport function isTweenConfigKey(key: string): boolean {\n return BUILTIN_VAR_KEYS.has(key) || DROPPED_VAR_KEYS.has(key) || EXTRAS_KEYS.has(key);\n}\n\n// ── Property Groups ─────────────────────────────────────────────────────────\n// Each group maps to an independent GSAP tween so editing one property\n// (e.g. drag → x/y) never contaminates another (e.g. scale, rotation).\n\nexport type PropertyGroupName = \"position\" | \"scale\" | \"size\" | \"rotation\" | \"visual\" | \"other\";\n\nexport const PROPERTY_GROUPS: Record<PropertyGroupName, ReadonlySet<string>> = {\n position: new Set([\"x\", \"y\", \"xPercent\", \"yPercent\"]),\n scale: new Set([\"scale\", \"scaleX\", \"scaleY\"]),\n size: new Set([\"width\", \"height\"]),\n rotation: new Set([\"rotation\", \"skewX\", \"skewY\"]),\n visual: new Set([\"opacity\", \"autoAlpha\"]),\n other: new Set<string>(),\n};\n\nconst PROP_TO_GROUP = new Map<string, PropertyGroupName>();\nfor (const [group, props] of Object.entries(PROPERTY_GROUPS) as [\n PropertyGroupName,\n ReadonlySet<string>,\n][]) {\n for (const p of props) PROP_TO_GROUP.set(p, group);\n}\n\ntype PositionWrite = Pick<\n GsapAnimation,\n \"propertyGroup\" | \"properties\" | \"fromProperties\" | \"keyframes\"\n>;\n\nfunction writesProperty(animation: PositionWrite, property: string): boolean {\n return (\n property in animation.properties ||\n (!!animation.fromProperties && property in animation.fromProperties) ||\n !!animation.keyframes?.keyframes.some((k) => property in k.properties)\n );\n}\n\n/** A position write that sets x or y. An xPercent/yPercent centring set never duplicates one. */\nexport function isXYPositionWrite(a: PositionWrite): boolean {\n return a.propertyGroup === \"position\" && (writesProperty(a, \"x\") || writesProperty(a, \"y\"));\n}\n\nexport function classifyPropertyGroup(prop: string): PropertyGroupName {\n return PROP_TO_GROUP.get(prop) ?? \"other\";\n}\n\nexport function classifyTweenPropertyGroup(\n properties: Record<string, unknown>,\n): PropertyGroupName | undefined {\n const groups = new Set<PropertyGroupName>();\n for (const key of Object.keys(properties)) {\n // transformOrigin is a modifier; `_auto` is Studio's internal endpoint marker;\n // `data` is GSAP-reserved (carries the Studio hold-set tag). None is an animated\n // property, so none should affect the group.\n if (key === \"transformOrigin\" || key === \"_auto\" || key === \"data\") continue;\n const g = classifyPropertyGroup(key);\n groups.add(g);\n }\n if (groups.size === 1) return groups.values().next().value;\n return undefined;\n}\n\nfunction knownStart(animation: GsapAnimation): number | undefined {\n if (animation.resolvedStart !== undefined) return animation.resolvedStart;\n return typeof animation.position === \"number\" ? animation.position : undefined;\n}\n\n/**\n * What a Studio hold pins from t=0 before a later keyframed tween: its 0% keyframe's position props,\n * minus those an earlier timeline tween on the target writes (a global `gsap.set` is a base value).\n */\nexport function positionHoldForAnimation(\n animation: GsapAnimation,\n animations: readonly GsapAnimation[],\n): Record<string, number> | null {\n if (!animation.keyframes) return null;\n const start = knownStart(animation) ?? 0;\n if (!(start > 0.001)) return null;\n const atStart = animation.keyframes.keyframes.find((keyframe) => keyframe.percentage === 0);\n if (!atStart) return null;\n // A tween whose start the parser could not resolve (a label, say) is not known to come first.\n const earlier = animations.filter((other) => {\n const otherStart = knownStart(other);\n return (\n other !== animation &&\n !other.global &&\n other.targetSelector === animation.targetSelector &&\n otherStart !== undefined &&\n otherStart < start - 0.001\n );\n });\n const position: Record<string, number> = {};\n for (const [property, value] of Object.entries(atStart.properties)) {\n if (classifyPropertyGroup(property) !== \"position\" || typeof value !== \"number\") continue;\n if (earlier.some((other) => writesProperty(other, property))) continue;\n position[property] = value;\n }\n return Object.keys(position).length > 0 ? position : null;\n}\n\nexport const SUPPORTED_EASES = [\n \"none\",\n \"power1.in\",\n \"power1.out\",\n \"power1.inOut\",\n \"power2.in\",\n \"power2.out\",\n \"power2.inOut\",\n \"power3.in\",\n \"power3.out\",\n \"power3.inOut\",\n \"power4.in\",\n \"power4.out\",\n \"power4.inOut\",\n \"back.in\",\n \"back.out\",\n \"back.inOut\",\n \"elastic.in\",\n \"elastic.out\",\n \"elastic.inOut\",\n \"bounce.in\",\n \"bounce.out\",\n \"bounce.inOut\",\n \"circ.inOut\",\n \"expo.in\",\n \"expo.out\",\n \"expo.inOut\",\n \"elastic.out(1,0.3)\",\n \"elastic.inOut(1,0.3)\",\n \"spring-gentle\",\n \"spring-bouncy\",\n \"spring-stiff\",\n \"spring-wobbly\",\n \"spring-heavy\",\n \"hold\",\n \"steps(1)\",\n];\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/gsapConstants.ts"],"sourcesContent":["/**\n * GSAP property and ease constants.\n *\n * Extracted into a standalone module so browser code can import them\n * without pulling in gsapParser (which depends on recast / @babel/parser).\n */\n\nimport type { GsapAnimation } from \"./gsapSerialize.js\";\n\nexport const GSAP_DEFAULT_DURATION = 0.5;\n\nexport const SUPPORTED_PROPS = [\n // 2D Transforms\n \"x\",\n \"y\",\n \"scale\",\n \"scaleX\",\n \"scaleY\",\n \"rotation\",\n \"skewX\",\n \"skewY\",\n // 3D Transforms\n \"z\",\n \"rotationX\",\n \"rotationY\",\n \"rotationZ\",\n \"perspective\",\n \"transformPerspective\",\n \"transformOrigin\",\n // Visibility\n \"opacity\",\n \"visibility\",\n \"autoAlpha\",\n // Dimensions\n \"width\",\n \"height\",\n // Colors\n \"color\",\n \"backgroundColor\",\n \"borderColor\",\n // Box model\n \"borderRadius\",\n // Typography\n \"fontSize\",\n \"letterSpacing\",\n // Filter & Clipping\n \"filter\",\n \"clipPath\",\n // DOM content (number counters, text roll-ups)\n \"innerText\",\n];\n\n/** Keys stored on dedicated GsapAnimation fields (not in properties/extras). */\nexport const BUILTIN_VAR_KEYS: ReadonlySet<string> = new Set([\"duration\", \"ease\", \"delay\"]);\nexport const DROPPED_VAR_KEYS: ReadonlySet<string> = new Set([\n \"onComplete\",\n \"onStart\",\n \"onUpdate\",\n \"onRepeat\",\n]);\n/** Keys that go in `extras`: non-editable GSAP config that must survive round-trips. */\nexport const EXTRAS_KEYS: ReadonlySet<string> = new Set([\n \"stagger\",\n \"yoyo\",\n \"repeat\",\n \"repeatDelay\",\n \"snap\",\n \"overwrite\",\n \"immediateRender\",\n]);\n\nexport function isTweenConfigKey(key: string): boolean {\n return BUILTIN_VAR_KEYS.has(key) || DROPPED_VAR_KEYS.has(key) || EXTRAS_KEYS.has(key);\n}\n\n// ── Property Groups ─────────────────────────────────────────────────────────\n// Each group maps to an independent GSAP tween so editing one property\n// (e.g. drag → x/y) never contaminates another (e.g. scale, rotation).\n\nexport type PropertyGroupName = \"position\" | \"scale\" | \"size\" | \"rotation\" | \"visual\" | \"other\";\n\nexport const PROPERTY_GROUPS: Record<PropertyGroupName, ReadonlySet<string>> = {\n position: new Set([\"x\", \"y\", \"xPercent\", \"yPercent\"]),\n scale: new Set([\"scale\", \"scaleX\", \"scaleY\"]),\n size: new Set([\"width\", \"height\"]),\n rotation: new Set([\"rotation\", \"skewX\", \"skewY\"]),\n visual: new Set([\"opacity\", \"autoAlpha\"]),\n other: new Set<string>(),\n};\n\nconst PROP_TO_GROUP = new Map<string, PropertyGroupName>();\nfor (const [group, props] of Object.entries(PROPERTY_GROUPS) as [\n PropertyGroupName,\n ReadonlySet<string>,\n][]) {\n for (const p of props) PROP_TO_GROUP.set(p, group);\n}\n\ntype PositionWrite = Pick<\n GsapAnimation,\n \"propertyGroup\" | \"properties\" | \"fromProperties\" | \"keyframes\"\n>;\n\nfunction writesProperty(animation: PositionWrite, property: string): boolean {\n return (\n property in animation.properties ||\n (!!animation.fromProperties && property in animation.fromProperties) ||\n !!animation.keyframes?.keyframes.some((k) => property in k.properties)\n );\n}\n\n/** A position write that sets x or y. An xPercent/yPercent centring set never duplicates one. */\nexport function isXYPositionWrite(a: PositionWrite): boolean {\n return a.propertyGroup === \"position\" && (writesProperty(a, \"x\") || writesProperty(a, \"y\"));\n}\n\nexport function classifyPropertyGroup(prop: string): PropertyGroupName {\n return PROP_TO_GROUP.get(prop) ?? \"other\";\n}\n\nexport function classifyTweenPropertyGroup(\n properties: Record<string, unknown>,\n): PropertyGroupName | undefined {\n const groups = new Set<PropertyGroupName>();\n for (const key of Object.keys(properties)) {\n // transformOrigin is a modifier; `_auto` is Studio's internal endpoint marker;\n // `data` is GSAP-reserved (carries the Studio hold-set tag). None is an animated\n // property, so none should affect the group.\n if (key === \"transformOrigin\" || key === \"_auto\" || key === \"data\") continue;\n const g = classifyPropertyGroup(key);\n groups.add(g);\n }\n if (groups.size === 1) return groups.values().next().value;\n return undefined;\n}\n\nfunction knownStart(animation: GsapAnimation): number | undefined {\n if (animation.resolvedStart !== undefined) return animation.resolvedStart;\n return typeof animation.position === \"number\" ? animation.position : undefined;\n}\n\nexport interface HoldScope {\n touched: (animation: GsapAnimation) => boolean;\n held: (selector: string) => ReadonlyMap<string, unknown>;\n}\n\nconst tweenSignature = (a: GsapAnimation) =>\n JSON.stringify([a.targetSelector, a.method, a.position, a.duration, a.properties, a.keyframes]);\n\n/** The tweens an edit touched (not in `previous`; none without it), and what the script's holds already pin. */\nexport function holdScope(\n before: readonly GsapAnimation[],\n previous: readonly GsapAnimation[] | null,\n): HoldScope {\n const kept = new Set(previous?.map(tweenSignature));\n const held = new Map<string, Map<string, unknown>>();\n for (const a of before.filter((b) => b.method === \"set\" && b.properties?.data === \"hf-hold\")) {\n const props = held.get(a.targetSelector) ?? new Map<string, unknown>();\n for (const [property, value] of Object.entries(a.properties)) props.set(property, value);\n held.set(a.targetSelector, props);\n }\n return {\n touched: (a) => previous !== null && !kept.has(tweenSignature(a)),\n held: (selector) => held.get(selector) ?? new Map(),\n };\n}\n\n/**\n * What a Studio hold pins from t=0: a keyframed tween's 0% position props before a later start, and the position and\n * size of a lone key (GSAP renders none) only where this edit made it or a hold already pins it, minus earlier tweens.\n */\nexport function keyframeHoldForAnimation(\n animation: GsapAnimation,\n animations: readonly GsapAnimation[],\n scope: HoldScope,\n): Record<string, number> | null {\n if (!animation.keyframes) return null;\n const start = knownStart(animation);\n const lone = animation.keyframes.keyframes.length === 1;\n if (start === undefined || (!(start > 0.001) && !lone)) return null;\n const atStart = animation.keyframes.keyframes.find((keyframe) => keyframe.percentage === 0);\n if (!atStart) return null;\n // A tween whose start the parser could not resolve (a label, say) is not known to come first.\n const earlier = animations.filter((other) => {\n const otherStart = knownStart(other);\n return (\n other !== animation &&\n !other.global &&\n other.targetSelector === animation.targetSelector &&\n otherStart !== undefined &&\n otherStart < start - 0.001\n );\n });\n const touched = scope.touched(animation);\n const pinned = scope.held(animation.targetSelector);\n // An untouched tween keeps only the hold it made: one with its own first value.\n const kept = (property: string, value: unknown) =>\n touched ? pinned.has(property) : pinned.get(property) === value;\n const pins = (group: PropertyGroupName, property: string, value: unknown) =>\n (group === \"position\" && start > 0.001) ||\n ((group === \"position\" || group === \"size\") && ((lone && touched) || kept(property, value)));\n const hold: Record<string, number> = {};\n for (const [property, value] of Object.entries(atStart.properties)) {\n if (!pins(classifyPropertyGroup(property), property, value) || typeof value !== \"number\")\n continue;\n if (earlier.some((other) => writesProperty(other, property))) continue;\n hold[property] = value;\n }\n return Object.keys(hold).length > 0 ? hold : null;\n}\n\nexport const SUPPORTED_EASES = [\n \"none\",\n \"power1.in\",\n \"power1.out\",\n \"power1.inOut\",\n \"power2.in\",\n \"power2.out\",\n \"power2.inOut\",\n \"power3.in\",\n \"power3.out\",\n \"power3.inOut\",\n \"power4.in\",\n \"power4.out\",\n \"power4.inOut\",\n \"back.in\",\n \"back.out\",\n \"back.inOut\",\n \"elastic.in\",\n \"elastic.out\",\n \"elastic.inOut\",\n \"bounce.in\",\n \"bounce.out\",\n \"bounce.inOut\",\n \"circ.inOut\",\n \"expo.in\",\n \"expo.out\",\n \"expo.inOut\",\n \"elastic.out(1,0.3)\",\n \"elastic.inOut(1,0.3)\",\n \"spring-gentle\",\n \"spring-bouncy\",\n \"spring-stiff\",\n \"spring-wobbly\",\n \"spring-heavy\",\n \"hold\",\n \"steps(1)\",\n];\n"],"mappings":"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","names":[]}
@@ -1,5 +1,5 @@
1
- import { a as GsapAnimation, P as ParsedGsap, A as ArcPathConfig, b as ArcPathSegment } from './gsapSerialize-CfSXM_Ez.js';
2
- export { g as GsapKeyframeFormat, h as GsapKeyframesData, G as GsapMethod, i as GsapPercentageKeyframe, j as PROPERTY_GROUPS, k as PropertyGroupName, S as SUPPORTED_EASES, l as SUPPORTED_PROPS, m as classifyPropertyGroup, n as classifyTweenPropertyGroup, o as getAnimationsForElementId, p as gsapAnimationsToKeyframes, q as keyframesToGsapAnimations, s as serializeGsapAnimations, v as validateCompositionGsap } from './gsapSerialize-CfSXM_Ez.js';
1
+ import { a as GsapAnimation, P as ParsedGsap, A as ArcPathConfig, b as ArcPathSegment } from './gsapSerialize-_tuK-qvB.js';
2
+ export { g as GsapKeyframeFormat, h as GsapKeyframesData, G as GsapMethod, i as GsapPercentageKeyframe, j as PROPERTY_GROUPS, k as PropertyGroupName, S as SUPPORTED_EASES, l as SUPPORTED_PROPS, m as classifyPropertyGroup, n as classifyTweenPropertyGroup, o as getAnimationsForElementId, p as gsapAnimationsToKeyframes, q as keyframesToGsapAnimations, s as serializeGsapAnimations, v as validateCompositionGsap } from './gsapSerialize-_tuK-qvB.js';
3
3
  export { SPRING_PRESETS, SpringPreset, generateSpringEaseData } from './springEase.js';
4
4
  import './types-Ejqndkej.js';
5
5
 
@@ -36,19 +36,7 @@ declare function dedupePositionWritesInScript(script: string, selector: string,
36
36
  /** True for a `tl.set(...)` this module emitted to hold a keyframe before its tween.
37
37
  * The Studio filters these out so they never appear as user keyframes/diamonds. */
38
38
  declare function isStudioHoldSet(anim: GsapAnimation): boolean;
39
- /**
40
- * Keep a `tl.set(selector, {x,y}, 0)` "hold" in front of every position-keyframed
41
- * tween that starts after t=0, so the element holds its first keyframe's position
42
- * BEFORE the tween plays instead of snapping to its CSS base (the universal NLE
43
- * "hold before first keyframe" behavior). The set is tagged with `data: "hf-hold"`
44
- * so this pass owns it: every call wipes the prior holds and recomputes from the
45
- * current keyframes, keeping them in sync as keyframes are added/moved/deleted.
46
- *
47
- * Idempotent. Only position props (x/y/xPercent/yPercent) are held — opacity/scale
48
- * keep their authored pre-tween behavior. A tween already starting at 0 needs no
49
- * hold (no gap before it).
50
- */
51
- declare function syncPositionHoldsBeforeKeyframes(script: string): string;
39
+ declare function syncPositionHoldsBeforeKeyframes(script: string, previous?: string): string;
52
40
  interface SplitAnimationsOptions {
53
41
  originalId: string;
54
42
  newId: string;
@@ -98,23 +98,43 @@ function knownStart(animation) {
98
98
  if (animation.resolvedStart !== void 0) return animation.resolvedStart;
99
99
  return typeof animation.position === "number" ? animation.position : void 0;
100
100
  }
101
- function positionHoldForAnimation(animation, animations) {
101
+ var tweenSignature = (a) => JSON.stringify([a.targetSelector, a.method, a.position, a.duration, a.properties, a.keyframes]);
102
+ function holdScope(before, previous) {
103
+ const kept = new Set(previous?.map(tweenSignature));
104
+ const held = /* @__PURE__ */ new Map();
105
+ for (const a of before.filter((b) => b.method === "set" && b.properties?.data === "hf-hold")) {
106
+ const props = held.get(a.targetSelector) ?? /* @__PURE__ */ new Map();
107
+ for (const [property, value] of Object.entries(a.properties)) props.set(property, value);
108
+ held.set(a.targetSelector, props);
109
+ }
110
+ return {
111
+ touched: (a) => previous !== null && !kept.has(tweenSignature(a)),
112
+ held: (selector) => held.get(selector) ?? /* @__PURE__ */ new Map()
113
+ };
114
+ }
115
+ function keyframeHoldForAnimation(animation, animations, scope) {
102
116
  if (!animation.keyframes) return null;
103
- const start = knownStart(animation) ?? 0;
104
- if (!(start > 1e-3)) return null;
117
+ const start = knownStart(animation);
118
+ const lone = animation.keyframes.keyframes.length === 1;
119
+ if (start === void 0 || !(start > 1e-3) && !lone) return null;
105
120
  const atStart = animation.keyframes.keyframes.find((keyframe) => keyframe.percentage === 0);
106
121
  if (!atStart) return null;
107
122
  const earlier = animations.filter((other) => {
108
123
  const otherStart = knownStart(other);
109
124
  return other !== animation && !other.global && other.targetSelector === animation.targetSelector && otherStart !== void 0 && otherStart < start - 1e-3;
110
125
  });
111
- const position = {};
126
+ const touched = scope.touched(animation);
127
+ const pinned = scope.held(animation.targetSelector);
128
+ const kept = (property, value) => touched ? pinned.has(property) : pinned.get(property) === value;
129
+ const pins = (group, property, value) => group === "position" && start > 1e-3 || (group === "position" || group === "size") && (lone && touched || kept(property, value));
130
+ const hold = {};
112
131
  for (const [property, value] of Object.entries(atStart.properties)) {
113
- if (classifyPropertyGroup(property) !== "position" || typeof value !== "number") continue;
132
+ if (!pins(classifyPropertyGroup(property), property, value) || typeof value !== "number")
133
+ continue;
114
134
  if (earlier.some((other) => writesProperty(other, property))) continue;
115
- position[property] = value;
135
+ hold[property] = value;
116
136
  }
117
- return Object.keys(position).length > 0 ? position : null;
137
+ return Object.keys(hold).length > 0 ? hold : null;
118
138
  }
119
139
  var SUPPORTED_EASES = [
120
140
  "none",
@@ -1768,7 +1788,14 @@ var STUDIO_HOLD_MARKER = "hf-hold";
1768
1788
  function isStudioHoldSet(anim) {
1769
1789
  return anim.method === "set" && anim.properties?.data === STUDIO_HOLD_MARKER;
1770
1790
  }
1771
- function syncPositionHoldsBeforeKeyframes(script) {
1791
+ function animationsOf(script) {
1792
+ try {
1793
+ return parseGsapScript(script).animations;
1794
+ } catch {
1795
+ return null;
1796
+ }
1797
+ }
1798
+ function syncPositionHoldsBeforeKeyframes(script, previous) {
1772
1799
  let parsed;
1773
1800
  try {
1774
1801
  parsed = parseGsapScript(script);
@@ -1784,8 +1811,12 @@ function syncPositionHoldsBeforeKeyframes(script) {
1784
1811
  } catch {
1785
1812
  return result;
1786
1813
  }
1814
+ const scope = holdScope(
1815
+ parsed.animations,
1816
+ previous === void 0 ? null : animationsOf(previous)
1817
+ );
1787
1818
  for (const anim of reparsed.animations) {
1788
- const posProps = positionHoldForAnimation(anim, reparsed.animations);
1819
+ const posProps = keyframeHoldForAnimation(anim, reparsed.animations, scope);
1789
1820
  if (!posProps) continue;
1790
1821
  result = insertInheritedStateSet(result, anim.targetSelector, 0, {
1791
1822
  ...posProps,