Skip to content

Instantly share code, notes, and snippets.

@mattgperry
Last active May 14, 2020 13:58
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mattgperry/38d7cdd3557f398c2ca4a2c81defed08 to your computer and use it in GitHub Desktop.
Save mattgperry/38d7cdd3557f398c2ca4a2c81defed08 to your computer and use it in GitHub Desktop.
useMotionTemplate: Combine multiple motion values into a new one using a template literal
import { useEffect } from "react";
import sync from "framesync";
import { useMotionValue, MotionValue } from "framer-motion";
/**
* Combine multiple motion values into a new one using a template literal.
*
* Updates in source motion values are batched to once per frame.
*
* ```javascript
* const x = useMotionValue(0)
* const y = useMotionValue(0)
*
* const transform = useMotionTemplate`translate(${x}px ${y}px)`
* ```
*/
export function useMotionTemplate(
fragments: TemplateStringsArray,
...values: MotionValue[]
) {
const numFragments = fragments.length;
function buildValue() {
let output = ``;
for (let i = 0; i < numFragments; i++) {
output += fragments[i];
const value = values[i];
if (value) output += values[i].get();
}
return output;
}
const value = useMotionValue(buildValue());
const updateValue = () => value.set(buildValue());
useSubscriptions(values, () => sync.update(updateValue, false, true));
return value;
}
function useSubscriptions(values: MotionValue[], handler: () => void) {
useEffect(() => {
const subscriptions = values.map(value => value.onChange(handler));
return () => subscriptions.forEach(unsubscribe => unsubscribe());
});
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment