{"version":3,"file":"attach-animation.mjs","sources":["../../../../../src/render/dom/scroll/attach-animation.ts"],"sourcesContent":["import { AnimationPlaybackControls, resize } from \"motion-dom\"\nimport { scrollInfo } from \"./track\"\nimport { ScrollOptionsWithDefaults } from \"./types\"\nimport { canUseNativeTimeline } from \"./utils/can-use-native-timeline\"\nimport { getTimeline } from \"./utils/get-timeline\"\nimport { offsetToViewTimelineRange } from \"./utils/offset-to-range\"\n\nexport function attachToAnimation(\n animation: AnimationPlaybackControls,\n options: ScrollOptionsWithDefaults\n) {\n const { target, container, axis } = options\n const range = target && offsetToViewTimelineRange(options.offset)\n\n /**\n * Use native timeline when:\n * - No target and no offset: ScrollTimeline\n * - Target with mappable offset: ViewTimeline with named range\n * - Otherwise: fall back to JS observe. A ScrollTimeline has no offset,\n * so page offsets are applied by the JS timeline.\n */\n const native =\n canUseNativeTimeline(target) && (target ? !!range : !options.offset)\n const animations = new Map()\n const observed = new Set()\n let stopObserving: VoidFunction | undefined\n let reverse = false\n\n /**\n * When an offset's second point comes first, its range is swapped and\n * the animation played backwards. The range is set after the direction,\n * as that's what realigns a running animation with its timeline. Chrome\n * skips that realignment when the range changes in the frame the\n * animation starts, leaving it offset for good, so it's replayed too.\n */\n const apply = (direction: PlaybackDirection, waapi: Animation) => {\n const [start, end] = range!.points\n waapi.effect!.updateTiming({\n direction: reverse\n ? direction === \"normal\"\n ? \"reverse\"\n : \"alternate-reverse\"\n : direction,\n })\n Object.assign(waapi, {\n rangeStart: reverse ? end : start,\n rangeEnd: reverse ? start : end,\n })\n waapi.play()\n }\n\n const stops = [\n animation.attachTimeline({\n /**\n * Read only by WAAPI animations, so values driven from JS don't\n * create a native timeline they won't use.\n */\n get timeline() {\n return native ? getTimeline(options) : undefined\n },\n onAttach:\n range &&\n ((waapi) => {\n const direction = waapi.effect!.getTiming().direction!\n animations.set(waapi, direction)\n apply(direction, waapi)\n }),\n /**\n * Values driven from JS all track the offset with scrollInfo,\n * which measures once per frame for all of them.\n */\n observe: (valueAnimation) => {\n valueAnimation.pause()\n observed.add(valueAnimation)\n\n stopObserving ||= scrollInfo((info) => {\n observed.forEach((observedAnimation) => {\n observedAnimation.time =\n observedAnimation.iterationDuration *\n info[axis].progress\n })\n }, options)\n\n return () => observed.delete(valueAnimation)\n },\n }),\n ]\n\n if (native && range) {\n const { a, b } = range\n const length = axis === \"y\" ? \"clientHeight\" : \"clientWidth\"\n\n /**\n * Offsets like All only run forwards when the target is longer than\n * the container, so their direction is remeasured on resize.\n */\n const update = () => {\n if (\n reverse !==\n (reverse = a * target![length] + b * container[length] < 0)\n ) {\n animations.forEach(apply)\n }\n }\n update()\n\n if (a * b < 0) {\n stops.push(resize(update), resize([target!, container], update))\n }\n }\n\n return () => {\n stops.forEach((stop) => stop())\n stopObserving?.()\n }\n}\n"],"names":[],"mappings":"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"}