Skip to content

Instantly share code, notes, and snippets.

@steveruizok
Last active May 13, 2022 06:35
Show Gist options
  • Save steveruizok/c91232271826e58ea4752f344911f8fe to your computer and use it in GitHub Desktop.
Save steveruizok/c91232271826e58ea4752f344911f8fe to your computer and use it in GitHub Desktop.
Declare a motion value with a value computed from multiple other values.
import { useEffect } from "react"
import { MotionValue, useMotionValue } from "framer"
/**
* UseRelative
* @description Declare a motion value with a value dependent on multiple other values.
* @param parents An array of motion values or values.
* @param transform A function that receives the current values and returns a computed value.
* @example
* ```jsx
* const knobHeight = useRelative(
* [scrollHeight, contentHeight, maskHeight],
* (scrollHeight, contentHeight, maskHeight) => {
* return maskHeight * (scrollHeight / contentHeight)
* }
*)
*```
*/
export function useRelative<T>(
parents: (MotionValue<T> | T)[],
transform: (...parents: T[]) => T
) {
const transformedValue = useMotionValue(transform(...parents.map(toValue)))
useEffect(() => {
const computeValue = () =>
transformedValue.set(transform(...parents.map(toValue)))
computeValue()
const removers = parents
.map(v => isMotionValue(v) && v.onChange(computeValue))
.filter(v => v) as (() => void)[]
return () => removers.forEach(fn => fn())
}, [...parents, transform])
return transformedValue
}
// HELPERS
export const isMotionValue = (value: any): value is MotionValue => {
return value instanceof MotionValue
}
const toValue: <T>(v: MotionValue<T> | T) => T = v =>
isMotionValue(v) ? v.get() : v
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment