(target: () => number, options?: Opt | (() => Opt), snapKey?: () => unknown)
| 12 | a?.velocity === b?.velocity |
| 13 | |
| 14 | export function useSpring(target: () => number, options?: Opt | (() => Opt), snapKey?: () => unknown) { |
| 15 | const read = () => (typeof options === "function" ? options() : options) |
| 16 | const [value, setValue] = createSignal(target()) |
| 17 | const source = motionValue(value()) |
| 18 | const spring = motionValue(value()) |
| 19 | let config = read() |
| 20 | let snapValue = snapKey?.() |
| 21 | let stop = attachSpring(spring, source, config) |
| 22 | let off = spring.on("change", (next: number) => setValue(next)) |
| 23 | |
| 24 | createComputed(() => { |
| 25 | const next = target() |
| 26 | const nextSnap = snapKey?.() |
| 27 | if (snapKey && nextSnap !== snapValue) { |
| 28 | // State boundaries should adopt their target without animating from the previous context. |
| 29 | snapValue = nextSnap |
| 30 | stop() |
| 31 | spring.jump(next) |
| 32 | source.jump(next) |
| 33 | stop = attachSpring(spring, source, config) |
| 34 | setValue(next) |
| 35 | return |
| 36 | } |
| 37 | source.set(next) |
| 38 | }) |
| 39 | |
| 40 | createEffect(() => { |
| 41 | if (!options) return |
| 42 | const next = read() |
| 43 | if (eq(config, next)) return |
| 44 | config = next |
| 45 | stop() |
| 46 | stop = attachSpring(spring, source, next) |
| 47 | setValue(spring.get()) |
| 48 | }) |
| 49 | |
| 50 | onCleanup(() => { |
| 51 | off() |
| 52 | stop() |
| 53 | spring.destroy() |
| 54 | source.destroy() |
| 55 | }) |
| 56 | |
| 57 | return value |
| 58 | } |
no test coverage detected