diff --git a/dev/examples/viewport-scroll.tsx b/dev/examples/viewport-scroll.tsx new file mode 100644 index 0000000000..9f2529c45a --- /dev/null +++ b/dev/examples/viewport-scroll.tsx @@ -0,0 +1,34 @@ +import * as React from "react" +import { motion, useViewportScroll, useTransform } from "@framer" + +const Item = motion.div({ + default: { + width: 100, + height: 100, + marginBottom: 100, + }, +}) + +const ItemColor = ({ i, scrollY }) => { + const base = -500 + i * 200 + + const backgroundColor = useTransform( + scrollY, + [base, base + 100, base + 200, base + 300], + ["rgba(255, 255, 255, 0.2)", "rgba(255, 255, 255, 1)", "rgba(255, 255, 255, 1)", "rgba(255, 0, 0, 0.2)"] + ) + + return +} + +export const App = () => { + const viewportScroll = useViewportScroll() + + return ( +
+ {Array.from(new Array(100), (x, i) => ( + + ))} +
+ ) +} diff --git a/package.json b/package.json index d3d4a2b0f7..a481a1cb48 100644 --- a/package.json +++ b/package.json @@ -54,7 +54,7 @@ "webpack-dev-server": "^3.1.10" }, "dependencies": { - "@popmotion/popcorn": "^0.2.0", + "@popmotion/popcorn": "^0.3.0", "hey-listen": "^1.0.5", "popmotion": "8.5.3", "style-value-types": "^3.0.7", diff --git a/src/hooks/use-transform.ts b/src/hooks/use-transform.ts index 391f925b30..8a2fe27278 100644 --- a/src/hooks/use-transform.ts +++ b/src/hooks/use-transform.ts @@ -46,8 +46,6 @@ import { interpolate } from "@popmotion/popcorn" * }; * ``` * - * - * * @param {MotionValue} value - The `MotionValue` to transform * @param {number[]} from - A linear numerical sequence. * @param {string[] | number[]} to - A series of numbers, colors or @@ -58,9 +56,9 @@ export const useTransform = (value: MotionValue, from: number[], to: string[] | return useMemo( () => { if (transformedValue.current) transformedValue.current.destroy() - transformedValue.current = value.addChild({ - transformer: interpolate(from, to), - }) + + const transformer = interpolate(from, to) + transformedValue.current = value.addChild({ transformer }) return transformedValue.current }, [value, ...from, ...to] diff --git a/src/hooks/use-viewport-scroll.ts b/src/hooks/use-viewport-scroll.ts new file mode 100644 index 0000000000..3e00ff5c80 --- /dev/null +++ b/src/hooks/use-viewport-scroll.ts @@ -0,0 +1,25 @@ +import { useMotionValue } from "../motion-value/use-motion-value" +import { useEvent } from "../events/use-event" + +/** + * `useViewportScroll` provides `MotionValue`s that update when the viewport scrolls. + * + * This makes it possible to transform viewport scroll into other values. + * + * For instance, highlighting different table of contents items to correspond with page scroll. + */ +const useViewportScroll = () => { + const x = useMotionValue(0) + const y = useMotionValue(0) + + const onScroll = () => { + x.set(window.pageXOffset) + y.set(window.pageYOffset) + } + + useEvent("scroll", window, onScroll, { passive: true }) + + return { x, y } +} + +export { useViewportScroll } diff --git a/src/index.ts b/src/index.ts index 62c5a01b7e..911059b2c2 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,9 +1,10 @@ import { motion } from "./motion" -import { useMotionValue } from "./hooks/use-motion-value" +import { useMotionValue } from "./motion-value/use-motion-value" import { useTransform } from "./hooks/use-transform" import { usePose } from "./hooks/use-pose" +import { useViewportScroll } from "./hooks/use-viewport-scroll" -export { motion, useMotionValue, useTransform, usePose } +export { motion, useMotionValue, useTransform, usePose, useViewportScroll } export { useMouseEvents, useTouchEvents, usePointerEvents } from "./events" export { usePanGesture } from "./gestures" diff --git a/src/hooks/use-motion-value.ts b/src/motion-value/use-motion-value.ts similarity index 95% rename from src/hooks/use-motion-value.ts rename to src/motion-value/use-motion-value.ts index 4bede2a6a1..468d407835 100644 --- a/src/hooks/use-motion-value.ts +++ b/src/motion-value/use-motion-value.ts @@ -1,5 +1,5 @@ import { useMemo } from "react" -import { motionValue } from "../motion-value" +import { motionValue } from "." /** * For advanced use-cases, you can assume external control of the motion values used by `motion` components. diff --git a/src/motion/__tests__/component.test.tsx b/src/motion/__tests__/component.test.tsx index 4bd3a0a7be..18fbe7ec5f 100644 --- a/src/motion/__tests__/component.test.tsx +++ b/src/motion/__tests__/component.test.tsx @@ -1,7 +1,7 @@ import { fireEvent, render } from "react-testing-library" import { motion } from "../" import * as React from "react" -import { useMotionValue } from "../../hooks/use-motion-value" +import { useMotionValue } from "../../motion-value/use-motion-value" import { useTransform } from "../../hooks/use-transform" import { usePose } from "../../hooks/use-pose" import styled from "styled-components" diff --git a/yarn.lock b/yarn.lock index d1113013dc..604017eb8b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -79,6 +79,16 @@ hey-listen "^1.0.5" style-value-types "^3.0.7" +"@popmotion/popcorn@^0.3.0": + version "0.3.0" + resolved "https://registry.yarnpkg.com/@popmotion/popcorn/-/popcorn-0.3.0.tgz#d75da7a0def2a949016d1cd3794f36514d69019f" + integrity sha512-iTPnu07k8mGBuJEt9NhAJ132sd0dNG9/AwqzJeKHjZA9aqtxnP9X0AFbklJrGc18HdPtdzwvGufpcJerSMGdvQ== + dependencies: + "@popmotion/easing" "^1.0.1" + framesync "^4.0.1" + hey-listen "^1.0.5" + style-value-types "^3.0.7" + "@samverschueren/stream-to-observable@^0.3.0": version "0.3.0" resolved "https://registry.yarnpkg.com/@samverschueren/stream-to-observable/-/stream-to-observable-0.3.0.tgz#ecdf48d532c58ea477acfcab80348424f8d0662f"