Replies: 3 comments
-
|
@mattgperry could you take a look at this |
Beta Was this translation helpful? Give feedback.
0 replies
-
|
|
Beta Was this translation helpful? Give feedback.
0 replies
-
|
@mattgperry import { useRef, useContext, useInsertionEffect } from "react"
import { MotionValue } from "../value"
import { isMotionValue } from "./utils/is-motion-value"
import { useMotionValue } from "./use-motion-value"
import { MotionConfigContext } from "../context/MotionConfigContext"
import { SpringOptions } from "../animation/types"
import { useIsomorphicLayoutEffect } from "../utils/use-isomorphic-effect"
import { frame, frameData } from "../frameloop"
import {
MainThreadAnimation,
animateValue,
} from "../animation/animators/MainThreadAnimation"
function toNumber(v: string | number) {
if (typeof v === "number") return v === -Infinity ? "auto" : v
// 👆
return parseFloat(v)
}
/**
* Creates a `MotionValue` that, when `set`, will use a spring animation to animate to its new state.
*
* It can either work as a stand-alone `MotionValue` by initialising it with a value, or as a subscriber
* to another `MotionValue`.
*
* @remarks
*
* ```jsx
* const x = useSpring(0, { stiffness: 300 })
* const y = useSpring(x, { damping: 10 })
* ```
*
* @param inputValue - `MotionValue` or number. If provided a `MotionValue`, when the input `MotionValue` changes, the created `MotionValue` will spring towards that value.
* @param springConfig - Configuration options for the spring.
* @returns `MotionValue`
*
* @public
*/
export function useSpring(
source: MotionValue<string> | MotionValue<number> | number,
config: SpringOptions = {}
) {
const { isStatic } = useContext(MotionConfigContext)
const activeSpringAnimation = useRef<MainThreadAnimation<number> | null>(
null
)
const value = useMotionValue(
isMotionValue(source) ? toNumber(source.get()) : source
)
const latestValue = useRef<number>(value.get())
const latestSetter = useRef<(v: number) => void>(() => {})
const startAnimation = () => {
/**
* If the previous animation hasn't had the chance to even render a frame, render it now.
*/
const animation = activeSpringAnimation.current
if (animation && animation.time === 0) {
animation.sample(frameData.delta)
}
stopAnimation()
activeSpringAnimation.current = animateValue({
keyframes: [value.get(), latestValue.current].filter(v => Number(v)),
// 👆
velocity: value.getVelocity(),
type: "spring",
restDelta: 0.001,
restSpeed: 0.01,
...config,
onUpdate: latestSetter.current,
})
}
const stopAnimation = () => {
if (activeSpringAnimation.current) {
activeSpringAnimation.current.stop()
}
}
useInsertionEffect(() => {
return value.attach((v, set) => {
/**
* A more hollistic approach to this might be to use isStatic to fix VisualElement animations
* at that level, but this will work for now
*/
if (isStatic) return set(v)
latestValue.current = v
latestSetter.current = set
frame.update(startAnimation)
return value.get()
}, stopAnimation)
}, [JSON.stringify(config)])
useIsomorphicLayoutEffect(() => {
if (isMotionValue(source)) {
return source.on("change", (v) => value.set(toNumber(v)))
}
}, [value])
return value
}I added two changes, and it seems to work I'm not sure what should be considered an invalid value for this change allows us to use let [ref, {height}] = useMeasure();
const springyHeight = useSpring(height, springOptions);instead of what I shared in first message |
Beta Was this translation helpful? Give feedback.
0 replies
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
Hi everyone,
I have a motion value that tracks height, the thing is it starts as
nullwhen I feed this motion value to useSpring, it does not work
something like this
I found a workaround like this
Is this a bug, is useSpring intended to work this way?
Beta Was this translation helpful? Give feedback.
All reactions