diff --git a/components/examples-hooks.js b/components/examples-hooks.js index aab0a3d..09559f2 100644 --- a/components/examples-hooks.js +++ b/components/examples-hooks.js @@ -74,6 +74,16 @@ return `, link: 'https://codesandbox.io/embed/r5qmj8m6lq', tags: ['useSprings'], }, + { + name: 'hooks/inertia', + title: 'Inertia', + tags: ['useSprings'], + }, + { + name: 'hooks/clamp-bounce', + title: 'Clamp bounce', + tags: ['useSprings'], + }, { name: 'hooks/mouse-parallax', title: 'Mouse parallax', @@ -246,4 +256,10 @@ return items.map(i => link: 'https://codesandbox.io/embed/rloj7nw3pn', tags: ['useSpring'], }, + { + name: 'hooks/sorted-clicks', + title: 'Sort items by number of clicks', + link: 'https://codesandbox.io/embed/rloj7nw3pn', + tags: ['useSprings'], + }, ] diff --git a/components/examples-tests.js b/components/examples-tests.js index 76edd43..5e71492 100644 --- a/components/examples-tests.js +++ b/components/examples-tests.js @@ -1,4 +1,9 @@ export default [ + { + name: 'tests/parallax', + title: 'Parallax', + tags: ['Parallax'], + }, { name: 'tests/freshtilledsoil', title: 'Freshtilledsoil stresstest', @@ -6,43 +11,53 @@ export default [ tags: ['useChain', 'useTransition'], }, { - name: 'tests/remove_multiple_items', - title: 'Remove multiple items', - tags: ['useTransition'], + name: 'tests/issue-707', + title: 'Issue #707 - Parallax', + tags: ['Parallax'], }, { - name: 'tests/issue-436', - title: 'useTransition with "reset" prop', + name: 'tests/issue-827', + title: 'Issue #827 - Linear gradient', tags: ['useTransition'], }, { - name: 'tests/issue-631', - title: '', - tags: ['useChain'], - }, - { - name: 'tests/issue-634', - title: '', - tags: ['useChain'], - }, - { - name: 'tests/issue-639', - title: '', + name: 'tests/issue-461', + title: 'Issue #461 - Remove multiple items', tags: ['useTransition'], }, { - name: 'tests/issue-645', - title: '', - tags: ['useSprings', 'useGesture'], + name: 'tests/issue-657', + title: 'Issue #657', + tags: ['useSprings'], }, { - name: 'tests/issue-650', - title: '', + name: 'tests/issue-436', + title: 'Issue #436 - useTransition with "reset" prop', tags: ['useTransition'], }, - { - name: 'tests/issue-657', - title: '', - tags: ['useSprings'], - }, + // { + // name: 'tests/issue-631', + // title: 'Issue #631', + // tags: ['useChain'], + // }, + // { + // name: 'tests/issue-634', + // title: 'Issue #634', + // tags: ['useChain'], + // }, + // { + // name: 'tests/issue-639', + // title: 'Issue #639', + // tags: ['useTransition'], + // }, + // { + // name: 'tests/issue-645', + // title: 'Issue #645', + // tags: ['useSprings', 'useGesture'], + // }, + // { + // name: 'tests/issue-650', + // title: 'Issue #650', + // tags: ['useTransition'], + // }, ] diff --git a/demos/hooks/blackflag/index.js b/demos/hooks/blackflag/index.js index caaa2e7..c2de99f 100644 --- a/demos/hooks/blackflag/index.js +++ b/demos/hooks/blackflag/index.js @@ -15,7 +15,6 @@ export default function App() { } }, from: { radians: 0 }, - reset: true, config: { duration: 3500 }, }) return ( diff --git a/demos/hooks/card-flick/index.js b/demos/hooks/card-flick/index.js index 3cf93f7..5633a51 100644 --- a/demos/hooks/card-flick/index.js +++ b/demos/hooks/card-flick/index.js @@ -1,6 +1,6 @@ import React, { useState } from 'react' import { useSprings, animated, to } from 'react-spring' -import { useGesture } from 'react-with-gesture' +import { useDrag } from 'react-use-gesture' import './styles.css' const cards = [ @@ -36,12 +36,11 @@ export default function Deck() { })) // Create a gesture, we're interested in down-state, delta (current-pos - click-pos), direction and velocity - const bind = useGesture( + const bind = useDrag( ({ args: [index], down, - delta: [xDelta], - distance, + movement: [xMove], direction: [xDir], velocity, }) => { @@ -57,9 +56,9 @@ export default function Deck() { if (index !== i) return const isGone = gone.has(index) // When a card is gone it flys out left or right, otherwise it's either dragged to delta, or goes back to zero - const x = isGone ? (200 + window.innerWidth) * dir : down ? xDelta : 0 + const x = isGone ? (200 + window.innerWidth) * dir : down ? xMove : 0 // How much the card tilts, flicking it harder makes it rotate faster - const rot = xDelta / 100 + (isGone ? dir * 10 * velocity : 0) + const rot = xMove / 100 + (isGone ? dir * 10 * velocity : 0) // Active cards lift up a bit const scale = down ? 1.1 : 1 return { diff --git a/demos/hooks/chain-animation/index.tsx b/demos/hooks/chain-animation/index.js similarity index 88% rename from demos/hooks/chain-animation/index.tsx rename to demos/hooks/chain-animation/index.js index 6b96f6c..940aeeb 100644 --- a/demos/hooks/chain-animation/index.tsx +++ b/demos/hooks/chain-animation/index.js @@ -24,14 +24,12 @@ export default function App() { // 2. create transition-refs const transRef = useRef() - const transitions = useTransition(open ? data : [], item => item.name, { + const transition = useTransition(open ? data : [], { from: { opacity: 0, transform: 'scale(0)' }, enter: { opacity: 1, transform: 'scale(1)' }, leave: { opacity: 0, transform: 'scale(0)' }, trail: 400 / data.length, config: { ...config.stiff, precision: 0.01 }, - unique: true, - //reset: true, ref: transRef, }) @@ -43,8 +41,8 @@ export default function App() { set(open => !open)}> - {transitions.map(({ item, key, props }) => ( - + {transition((values, item) => ( + ))} diff --git a/demos/hooks/clamp-bounce/index.js b/demos/hooks/clamp-bounce/index.js new file mode 100644 index 0000000..52fa472 --- /dev/null +++ b/demos/hooks/clamp-bounce/index.js @@ -0,0 +1,18 @@ +import React from 'react' +import { useSpring, animated } from 'react-spring' +import './styles.css' + +export default function ClampBounce() { + const [toggle, setToggle] = React.useState(false) + const { y } = useSpring({ + y: toggle ? 250 : -250, + config: { tension: 120, friction: 12, clamp: 2 }, + onAnimate: console.log, + }) + + return ( +
+ setToggle(t => !t)} style={{ y }} /> +
+ ) +} diff --git a/demos/hooks/clamp-bounce/styles.css b/demos/hooks/clamp-bounce/styles.css new file mode 100644 index 0000000..1eb0731 --- /dev/null +++ b/demos/hooks/clamp-bounce/styles.css @@ -0,0 +1,14 @@ +.clamp-bounce { + display: flex; + align-items: center; + justify-content: center; + background: #ecede7; + height: 100%; +} + +.clamp-bounce > div { + width: 80px; + height: 80px; + background: hotpink; + border-radius: 16px; +} diff --git a/demos/hooks/draggable-list/index.js b/demos/hooks/draggable-list/index.js index 6b69781..d5d6cd8 100644 --- a/demos/hooks/draggable-list/index.js +++ b/demos/hooks/draggable-list/index.js @@ -1,6 +1,6 @@ import React, { useRef } from 'react' import clamp from 'lodash/clamp' -import { useGesture } from 'react-with-gesture' +import { useDrag } from 'react-use-gesture' import { useSprings, animated, to } from 'react-spring' import './styles.css' @@ -35,7 +35,7 @@ export default function DraggableList({ const [springs, setSprings] = useSprings(items.length, fn(order.current)) // Preps a gesture handler which returns drag-deltas, touched/clicked state, etc. - const bind = useGesture(({ args: [originalIndex], down, delta: [, y] }) => { + const bind = useDrag(({ args: [originalIndex], down, movement: [, y] }) => { // Bunch of math to calculate current row and new order, it's unavoidable ¯\_(ツ)_/¯ const curIndex = order.current.indexOf(originalIndex) const curRow = clamp( @@ -60,10 +60,8 @@ export default function DraggableList({ boxShadow: shadow.to( s => `rgba(0, 0, 0, 0.2) 0px ${s}px ${2 * s}px 0px` ), - transform: to( - [y, scale], - (y, s) => `translate3d(0,${y}px,0) scale(${s})` - ), + y, + scale, }} children={items[i]} {...bind(i)} diff --git a/demos/hooks/gestures-pager/index.js b/demos/hooks/gestures-pager/index.js index 058340c..0848281 100644 --- a/demos/hooks/gestures-pager/index.js +++ b/demos/hooks/gestures-pager/index.js @@ -1,7 +1,7 @@ import React, { useRef, useEffect } from 'react' import clamp from 'lodash-es/clamp' import { useSprings, animated } from 'react-spring' -import { useGesture } from 'react-with-gesture' +import { useDrag } from 'react-use-gesture' import './styles.css' const pages = [ @@ -25,8 +25,8 @@ export default function Viewpager() { set(i => ({ x: i * width.current, sc: 1, display: 'block' })) }, []) - const bind = useGesture( - ({ down, delta: [xDelta], direction: [xDir], distance, cancel }) => { + const bind = useDrag( + ({ down, movement: [xMovement], direction: [xDir], distance, cancel }) => { if (down && distance > width.current / 2) cancel( (index.current = clamp( @@ -38,7 +38,7 @@ export default function Viewpager() { set(i => { if (i < index.current - 1 && i > index.current + 1) return { display: 'none' } - const x = (i - index.current) * width.current + (down ? xDelta : 0) + const x = (i - index.current) * width.current + (down ? xMovement : 0) const sc = down ? 1 - distance / width.current / 2 : 1 return { x, sc, display: 'block' } }) @@ -49,13 +49,7 @@ export default function Viewpager() { ref={r => r && (width.current = r.getBoundingClientRect().width)} className="viewpager-main"> {props.map(({ x, display, sc }, i) => ( - `translate3d(${x}px,0,0)`), - }}> + `scale(${s})`), diff --git a/demos/hooks/gestures-pull/index.js b/demos/hooks/gestures-pull/index.js index 5656c1f..6aff214 100644 --- a/demos/hooks/gestures-pull/index.js +++ b/demos/hooks/gestures-pull/index.js @@ -1,28 +1,21 @@ import React, { useState, useRef, useEffect } from 'react' import clamp from 'lodash-es/clamp' -import { useGesture } from 'react-with-gesture' +import { useDrag } from 'react-use-gesture' import { useSpring, animated } from 'react-spring' import { add, scale } from 'vec-la' import './styles.css' function Pull() { - const [{ xy }, set] = useSpring(() => ({ xy: [0, 0] })) - const bind = useGesture(({ down, delta, velocity }) => { + const [{ x, y }, set] = useSpring(() => ({ x: 0, y: 0 })) + const bind = useDrag(({ down, movement: [mx, my], velocity }) => { velocity = Math.max(1, velocity) - console.log(delta, velocity) set({ - xy: down ? delta : [0, 0], + x: down ? mx : 0, + y: down ? my : 0, config: { mass: velocity, tension: 500 * velocity, friction: 50 }, }) }) - return ( - `translate3d(${x}px,${y}px,0)`), - }} - /> - ) + return } export default function App() { diff --git a/demos/hooks/goo/index.js b/demos/hooks/goo/index.js index 3bacd61..c9c92a3 100644 --- a/demos/hooks/goo/index.js +++ b/demos/hooks/goo/index.js @@ -8,9 +8,11 @@ const trans = (x, y) => `translate3d(${x}px,${y}px,0) translate3d(-50%,-50%,0)` export default function Goo() { const ref = useRef(null) - const [trail, set] = useTrail(3, () => ({ + const [trail, set] = useTrail(3, i => ({ xy: [0, 0], - config: i => (i === 0 ? fast : slow), + // Make "x" fast and "y" slow + config: i => (i == 0 ? fast : slow), + immediate: i == 0, })) return ( diff --git a/demos/hooks/image-fade/index.js b/demos/hooks/image-fade/index.js index 928ef0f..30912e5 100644 --- a/demos/hooks/image-fade/index.js +++ b/demos/hooks/image-fade/index.js @@ -28,10 +28,17 @@ const slides = [ export default function App() { const [index, set] = useState(0) - const transitions = useTransition(slides[index], item => item.id, { + const transition = useTransition(slides[index], { from: { opacity: 0 }, - enter: { opacity: 1 }, - leave: { opacity: 0 }, + enter: [ + { zIndex: 1, immediate: true, onChange: console.log }, + { opacity: 1, onStart: () => console.log('onEnter(%O)', index) }, + ], + leave: [ + { zIndex: 0, immediate: true, onChange: console.log }, + { opacity: 0, onStart: () => console.log('onLeave(%O)', index) }, + ], + expires: Infinity, config: config.molasses, }) @@ -40,11 +47,10 @@ export default function App() { return () => clearInterval(id) }, []) - return transitions.map(({ item, props, key }) => ( + return transition((props, { url }) => ( )) } diff --git a/demos/hooks/inertia/index.js b/demos/hooks/inertia/index.js new file mode 100644 index 0000000..86a9883 --- /dev/null +++ b/demos/hooks/inertia/index.js @@ -0,0 +1,65 @@ +import React from 'react' +import { useSpring, animated } from 'react-spring' +import { useDrag } from 'react-use-gesture' +import './styles.css' + +const modes = { + pong: 0, // The min/max values deflect the decay animation + bounce: 0, // The animation bounces instead of overshooting. Try both directions + skipFinish: 0, // This demonstrates "from !== to" when truthy, else "from === to" (it should work either way) +} + +const [min, max] = [-250, 250] +const clamp = value => Math.max(min, Math.min(max, value)) + +export default function Inertia() { + const { y } = useSpring({ y: 0 }) + + const bind = useDrag( + ({ down, movement: [, dy], vxvy: [, vy], memo = y.get() }) => { + if (down) y.set(clamp(dy + memo)) + else inertia(dy + memo + 1, vy) + return memo + } + ) + + const springBounce = velocity => + y.start({ + to: velocity > 0 ? max : min, + config: { + velocity: velocity, + tension: 30, + friction: 2, + clamp: modes.bounce ? 0.7 : false, + precision: 0.005, + }, + onRest: () => console.log('BOUNCE END'), + }) + + const inertia = (position, velocity) => + y.start({ + y: position, + onChange: async val => { + const vel = y.velocity + if ((val > max && vel > 0) || (val < min && vel < 0)) { + if (modes.pong) { + inertia(y.get(), -vel) + } else { + if (!modes.skipFinish) { + y.finish(vel > 0 ? max : min) + } + springBounce(vel) + } + } + }, + config: { decay: true, velocity }, + onRest: () => console.log('INERTIA END'), + }) + + // Now we're just mapping the animated values to our view, that's it. Btw, this component only renders once. :-) + return ( +
+ +
+ ) +} diff --git a/demos/hooks/inertia/styles.css b/demos/hooks/inertia/styles.css new file mode 100644 index 0000000..c8dbb7d --- /dev/null +++ b/demos/hooks/inertia/styles.css @@ -0,0 +1,14 @@ +.inertia { + display: flex; + align-items: center; + justify-content: center; + background: #ecede7; + height: 100%; +} + +.inertia > div { + width: 80px; + height: 80px; + background: hotpink; + border-radius: 16px; +} diff --git a/demos/hooks/list-reordering/data.js b/demos/hooks/list-reordering/data.js index 928fec1..c76a350 100644 --- a/demos/hooks/list-reordering/data.js +++ b/demos/hooks/list-reordering/data.js @@ -3,54 +3,54 @@ export default [ name: 'Rare Wind', description: '#a8edea → #fed6e3', css: 'linear-gradient(120deg, #a8edea 0%, #fed6e3 60%)', - width: 80, + height: 80, }, { name: 'Saint Petersburg', description: '#f5f7fa → #c3cfe2', css: 'linear-gradient(120deg, #c3cfe2 0%, #c3cfe2 60%)', - width: 80, + height: 80, }, { name: 'Deep Blue', description: '#e0c3fc → #8ec5fc', css: 'linear-gradient(120deg, #e0c3fc 0%, #8ec5fc 60%)', - width: 120, + height: 120, }, { name: 'Ripe Malinka', description: '#f093fb → #f5576c', css: 'linear-gradient(120deg, #f093fb 0%, #f5576c 60%)', - width: 80, + height: 80, }, { name: 'Near Moon', description: '#5ee7df → #b490ca', css: 'linear-gradient(120deg, #5ee7df 0%, #b490ca 60%)', - width: 60, + height: 60, }, { name: 'Wild Apple', description: '#d299c2 → #fef9d7', css: 'linear-gradient(120deg, #d299c2 0%, #fef9d7 60%)', - width: 80, + height: 80, }, { name: 'Ladoga Bottom', description: '#ebc0fd → #d9ded8', css: 'linear-gradient(120deg, #ebc0fd 0%, #d9ded8 60%)', - width: 60, + height: 60, }, { name: 'Sunny Morning', description: '#f6d365 → #fda085', css: 'linear-gradient(120deg, #f6d365 0%, #fda085 60%)', - width: 80, + height: 80, }, { name: 'Lemon Gate', description: '#96fbc4 → #f9f586', css: 'linear-gradient(120deg, #96fbc4 0%, #f9f586 60%)', - width: 60, + height: 60, }, ] diff --git a/demos/hooks/list-reordering/index.js b/demos/hooks/list-reordering/index.js index 10f2596..f3428d7 100644 --- a/demos/hooks/list-reordering/index.js +++ b/demos/hooks/list-reordering/index.js @@ -8,30 +8,25 @@ export default function App() { const [rows, set] = useState(data) useEffect(() => void setInterval(() => set(shuffle), 3000), []) - let width = 0 - const transitions = useTransition( - rows.map(data => ({ ...data, y: (width += data.width) - data.width })), - d => d.name, - { - from: { width: 0, opacity: 0 }, - leave: { width: 0, opacity: 0 }, - enter: ({ y, width }) => ({ y, width, opacity: 1 }), - update: ({ y, width }) => ({ y, width }), - config: { mass: 5, tension: 500, friction: 150 }, - } - ) + let height = 0 + rows.forEach(row => { + row.y = height + height += row.height + }) + + const transition = useTransition(rows, { + from: { height: 0, opacity: 0 }, + leave: { height: 0, opacity: 0 }, + enter: ({ y, height }) => ({ y, height, opacity: 1 }), + update: ({ y, height }) => ({ y, height }), + config: { mass: 5, tension: 500, friction: 150 }, + }) return (
-
- {transitions.map(({ item, props: { y, ...rest }, key }, index) => ( - `translate3d(${y}px,0,0)`), - ...rest, - }}> +
+ {transition((style, item) => ( +
item.css, { + const transition = useTransition(gridItems, { + key: item => item.css, from: ({ xy, width, height }) => ({ xy, width, @@ -55,9 +56,8 @@ export default function App() { set(items.length ? [] : data) }}>
- {transitions.map(({ item, props: { xy, scale, ...rest }, key }) => ( + {transition(({ xy, scale, ...rest }, item) => (
- {transitions.map(({ item, props: { innerHeight, ...rest }, key }) => ( + {transition(({ innerHeight, ...style }, item) => ( {item} diff --git a/demos/hooks/notification-hub/index.js b/demos/hooks/notification-hub/index.js index 849413c..87f390d 100644 --- a/demos/hooks/notification-hub/index.js +++ b/demos/hooks/notification-hub/index.js @@ -17,7 +17,8 @@ function MessageHub({ const [cancelMap] = useState(() => new WeakMap()) const [items, setItems] = useState([]) - const transitions = useTransition(items, item => item.key, { + const transition = useTransition(items, { + key: item => item.key, from: { opacity: 0, height: 0, life: '100%' }, enter: item => async (next, stop) => { if (DEBUG) console.log(` Entering:`, item.key) @@ -49,8 +50,8 @@ function MessageHub({ return ( - {transitions.map(({ key, item, props: { life, ...style } }) => ( - + {transition(({ life, ...style }, item) => ( + ref && refMap.set(item, ref)}>

{item.msg}

diff --git a/demos/hooks/simple-transition/index.js b/demos/hooks/simple-transition/index.js index a9601c0..332b3cf 100644 --- a/demos/hooks/simple-transition/index.js +++ b/demos/hooks/simple-transition/index.js @@ -1,18 +1,12 @@ -import React, { useState, useCallback, useEffect } from 'react' -import { useSprings, useTransition, animated } from 'react-spring' +import React, { useState, useEffect } from 'react' +import { useSprings, useTransition, a } from 'react-spring' import './styles.css' const pages = [ + ({ style }) => A, + ({ style }) => B, ({ style }) => ( - A - ), - ({ style }) => ( - B - ), - ({ style }) => ( - - C - + C ), ] @@ -22,24 +16,18 @@ export default function App() { //useEffect(() => void setInterval(fU, 100), []) const [index, set] = useState(0) - const onClick = useCallback( - () => set(state => (state === 2 ? 0 : state + 1)), - [] - ) - const transitions = useTransition(index, null, { + const transition = useTransition(index, { from: { opacity: 0, transform: 'translate3d(100%,0,0)' }, initial: { opacity: 1, transform: 'translate3d(0%,0,0)' }, enter: { opacity: 1, transform: 'translate3d(0%,0,0)' }, leave: { opacity: 0, transform: 'translate3d(-50%,0,0)' }, - //unique: true, - //reset: true, }) return ( -
- {transitions.map(({ item, props, key }) => { - const Page = pages[item] - return +
set(state => state + 1)}> + {transition((props, item) => { + const Page = pages[item % 3] + return })}
) diff --git a/demos/hooks/slider/index.js b/demos/hooks/slider/index.js index e170644..0479920 100644 --- a/demos/hooks/slider/index.js +++ b/demos/hooks/slider/index.js @@ -2,48 +2,44 @@ import React from 'react' import { useSpring, animated, to } from 'react-spring' -import { useGesture } from 'react-with-gesture' +import { useDrag } from 'react-use-gesture' import './styles.css' export default function Slider({ children }) { - // See: https://github.com/drcmda/react-with-gesture - // Gives access to: down, x, y, xDelta, yDelta, xInitial, yInitial - const [handlers, { delta, down }] = useGesture() - const { x, bg, size } = useSpring({ - x: down ? delta[0] : 0, - bg: `linear-gradient(120deg, ${ - delta[0] < 0 ? '#f093fb 0%, #f5576c' : '#96fbc4 0%, #f9f586' - } 100%)`, - size: down ? 1.1 : 1, - immediate: name => down && name === 'x', - }) + const [{ x, bg, size, justifySelf }, set] = useSpring(() => ({ + x: 0, + bg: `linear-gradient(120deg, ${'#96fbc4 0%, #f9f586'} 100%)`, + size: 1, + justifySelf: 'start', + })) const avSize = x.to({ map: Math.abs, range: [50, 300], output: ['scale(0.5)', 'scale(1)'], extrapolate: 'clamp', }) + const bind = useDrag(({ down, movement: [x] }) => + set({ + x: down ? x : 0, + bg: `linear-gradient(120deg, ${ + x < 0 ? '#f093fb 0%, #f5576c' : '#96fbc4 0%, #f9f586' + } 100%)`, + size: down ? 1.1 : 1, + justifySelf: x < 0 ? 'end' : 'start', + immediate: name => down && name === 'x', + }) + ) return (
- `translate3d(${x}px,0,0) scale(${s})` - ), - }}> + Slide diff --git a/demos/hooks/sorted-clicks/index.js b/demos/hooks/sorted-clicks/index.js new file mode 100644 index 0000000..6d048d1 --- /dev/null +++ b/demos/hooks/sorted-clicks/index.js @@ -0,0 +1,81 @@ +import React, { useState } from 'react' +import { a, useSprings } from 'react-spring' + +const items = ['A', 'B', 'C'] +const colors = ['#8d8741', '#659dbd', '#bc986a'] + +const itemMargin = 10 +const itemSize = 100 +const itemStyle = { + width: itemSize, + height: itemSize, + color: 'white', + fontSize: 30, + fontWeight: 500, + fontFamily: 'Roboto Condensed', + borderRadius: 18, + display: 'flex', + justifyContent: 'center', + alignItems: 'center', + userSelect: 'none', +} + +export default function App() { + const [counts, setCounts] = useState(() => items.map(() => 0)) + + // The ordered item indices + const order = items.map((_, i) => i).sort((a, b) => counts[b] - counts[a]) + + // The animated Y-positions + const springs = useSprings( + items.length, + items.map((_, i) => ({ + y: order.indexOf(i) * (itemSize + itemMargin), + })) + ) + + return ( +
+ + {springs.map(({ y }, i) => ( + { + setCounts(counts => { + counts = [...counts] + counts[i]++ + return counts + }) + }} + style={{ + // The "style.y" prop is specially supported by react-spring since v9. + y, + + // An absolute position is needed for all boxes to have the same origin. + position: 'absolute', + + // Ensure the higher count is always on top. + zIndex: order.length - order.indexOf(i), + + // Aesthetics + background: colors[i], + ...itemStyle, + }}> + {items[i] + counts[i]} + + ))} +
+ ) +} + +function Instructions() { + return ( +
+ Click a box to increment its count! +
+ ) +} diff --git a/demos/hooks/sorted-clicks/styles.css b/demos/hooks/sorted-clicks/styles.css new file mode 100644 index 0000000..2a69a0e --- /dev/null +++ b/demos/hooks/sorted-clicks/styles.css @@ -0,0 +1,67 @@ +.slider-main { + position: relative; + width: 100%; + height: 100%; + display: flex; + align-items: center; + justify-content: center; + overflow: hidden; +} + +.slider-item { + position: relative; + width: 250px; + height: 70px; + pointer-events: auto; + transform-origin: 50% 50% 0px; + padding-left: 32px; + padding-right: 32px; + box-sizing: border-box; + display: grid; + align-items: center; + text-align: center; + border-radius: 5px; + box-shadow: 0px 10px 10px -5px rgba(0, 0, 0, 0.05); +} + +.slider-fg { + cursor: -webkit-grab; + background-color: lightblue; + color: white; + position: absolute; + height: 100%; + width: 100%; + display: grid; + align-items: center; + text-align: center; + border-radius: 5px; + box-shadow: 0px 10px 30px -5px rgba(0, 0, 0, 0.05); + font-size: 2em; + font-weight: 400; + transition: box-shadow 0.75s; + font-family: 'Chinese Quote', -apple-system, system-ui, 'Segoe UI', + 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei', 'Helvetica Neue', + Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', + 'Segoe UI Symbol'; + text-transform: uppercase; + color: rgba(255, 255, 255, 0.85); + font-size: 19.9px; + font-weight: 500; + line-height: 19.9px; +} + +.slider-fg:active { + cursor: -webkit-grabbing; + box-shadow: 0px 15px 30px -5px rgba(0, 0, 0, 0.05); +} + +.slider-fg > * { + pointer-events: none; +} + +.slider-av { + width: 40px; + height: 40px; + border-radius: 50%; + background-color: white; +} diff --git a/demos/renderprops/areas/index.js b/demos/renderprops/areas/index.js index f134cef..78515ae 100644 --- a/demos/renderprops/areas/index.js +++ b/demos/renderprops/areas/index.js @@ -5,7 +5,9 @@ import { scaleTime, scaleLinear } from '@vx/scale' import { ParentSize } from '@vx/responsive' import { GradientPurpleTeal } from '@vx/gradient' import { extent, max } from 'd3-array' -import { Spring } from 'react-spring/renderprops' +import { Spring } from 'react-spring' + +// TODO: fix const data = [ { date: new Date('2018-04-08T12:33:40.624Z'), value: 2110 }, diff --git a/demos/renderprops/auto/index.js b/demos/renderprops/auto/index.js index fdbb11b..2b714ae 100644 --- a/demos/renderprops/auto/index.js +++ b/demos/renderprops/auto/index.js @@ -1,7 +1,9 @@ import React from 'react' -import { Spring, animated } from 'react-spring/renderprops' +import { Spring, animated } from 'react-spring' import './styles.css' +// TODO: fix or remove + const LOREM = `Hello world` export default class App extends React.Component { diff --git a/demos/renderprops/chat/index.js b/demos/renderprops/chat/index.js index a2a6d8e..d3359cf 100644 --- a/demos/renderprops/chat/index.js +++ b/demos/renderprops/chat/index.js @@ -1,10 +1,12 @@ import React from 'react' -import { Transition, animated } from 'react-spring/renderprops' +import { Transition, animated } from 'react-spring' import lorem from 'lorem-ipsum' import emoji from 'random-unicode-emoji' import classnames from 'classnames' import './styles.css' +// TODO: fix or remove + function addItem(state) { const items = [...state.items] const previous = state.items[state.items.length - 1] diff --git a/demos/renderprops/dashoffset/index.js b/demos/renderprops/dashoffset/index.js index 612b6d4..75dc549 100644 --- a/demos/renderprops/dashoffset/index.js +++ b/demos/renderprops/dashoffset/index.js @@ -1,57 +1,49 @@ -import React from 'react' -import { Spring, animated } from 'react-spring/renderprops' +import React, { useState, useEffect, useRef, useReducer } from 'react' +import { Spring, animated } from 'react-spring' import { GradientPinkRed as Gradient } from '@vx/gradient' import * as easings from 'd3-ease' -console.log(easings) - -export default class App extends React.Component { - state = { offset: 0 } - path = React.createRef() - componentDidMount() { - this.setState({ offset: this.path.current.getTotalLength() }) - } - render() { - const { offset } = this.state - return ( -
this.forceUpdate()}> - - - - - {props => ( - - )} - - - -
- ) - } +export default function() { + const [, forceUpdate] = useReducer(x => x + 1, 0) + const [offset, setOffset] = useState(0) + const path = useRef(null) + useEffect(() => { + setOffset(path.current.getTotalLength()) + }) + return ( +
forceUpdate()}> + + + + + {props => ( + + )} + + + +
+ ) } diff --git a/demos/renderprops/gestures/index.js b/demos/renderprops/gestures/index.js index 5806d24..aa6bd38 100644 --- a/demos/renderprops/gestures/index.js +++ b/demos/renderprops/gestures/index.js @@ -1,52 +1,41 @@ // Inpired by: https://codepen.io/popmotion/pen/xWrbNm?editors=0010 -import React from 'react' -import { withGesture } from 'react-with-gesture' -import { Spring, animated } from 'react-spring/renderprops' +import React, { useState } from 'react' +import { useDrag } from 'react-use-gesture' +import { Spring, animated } from 'react-spring' import './styles.css' -class GesturesExample extends React.Component { - render() { - const { - delta: [xDelta], - down, - } = this.props - const to = { x: down ? xDelta : 0 } - return ( -
- down && n === 'x'}> - {({ x }) => ( +export default function GesturesExample() { + const [{ down, mx }, setProps] = useState({ down: false, movement: 0 }) + const bind = useDrag(({ down, movement: [mx] }) => setProps({ down, mx })) + const to = { x: down ? mx : 0 } + + return ( +
+ down && n === 'x'}> + {({ x }) => ( + - `scale(${x})`), - justifySelf: xDelta < 0 ? 'end' : 'start', - }} - /> - `translate3d(${x}px,0,0)`), - }}> - Slide me - + className="gestures-bubble" + style={{ + scale: x.to({ + map: Math.abs, + range: [50, 300], + output: [0.5, 1], + extrapolate: 'clamp', + }), + justifySelf: mx < 0 ? 'end' : 'start', + }} + /> + + Slide me - )} - -
- ) - } + + )} +
+
+ ) } - -// https://github.com/drcmda/react-with-gesture -export default withGesture()(GesturesExample) diff --git a/demos/renderprops/grid/Grid.js b/demos/renderprops/grid/Grid.js index 5774650..6454eb9 100644 --- a/demos/renderprops/grid/Grid.js +++ b/demos/renderprops/grid/Grid.js @@ -3,6 +3,9 @@ import PropTypes from 'prop-types' import Measure from 'react-measure' import { Transition, animated, interpolate } from 'react-spring/renderprops' +// TODO: convert to functional? +// IMO it's not a particularly great demo but that's just IMO - David + const styles = { outer: { position: 'relative', width: '100%', height: '100%' }, inner: { diff --git a/demos/renderprops/grid/index.js b/demos/renderprops/grid/index.js index 8742ed5..7ec37eb 100644 --- a/demos/renderprops/grid/index.js +++ b/demos/renderprops/grid/index.js @@ -1,5 +1,5 @@ import React, { Component } from 'react' -import { config } from 'react-spring/renderprops' +import { config } from 'react-spring' import Grid from './Grid' import { Slug, Fade } from './Primitives' import data from './data' diff --git a/demos/renderprops/keyframes/index.js b/demos/renderprops/keyframes/index.js index c11afd7..c4e1177 100644 --- a/demos/renderprops/keyframes/index.js +++ b/demos/renderprops/keyframes/index.js @@ -1,10 +1,12 @@ import 'antd/dist/antd.css' import './styles.css' import React, { Fragment } from 'react' -import { Keyframes, animated } from 'react-spring/renderprops' +import { Keyframes, animated } from 'react-spring' import { Avatar, Form, Icon, Input, Button, Checkbox } from 'antd' import delay from 'delay' +// TODO: fix + // Creates a spring with predefined animation slots const Sidebar = Keyframes.Spring({ // Slots can take arrays/chains, diff --git a/demos/renderprops/list/List.js b/demos/renderprops/list/List.js index 904a081..0f5b91e 100644 --- a/demos/renderprops/list/List.js +++ b/demos/renderprops/list/List.js @@ -1,6 +1,8 @@ import React from 'react' import PropTypes from 'prop-types' -import { Transition, animated } from 'react-spring/renderprops' +import { Transition, animated } from 'react-spring' + +// TODO: fix const styles = { outer: { position: 'relative', width: '100%', height: '100%' }, diff --git a/demos/renderprops/messages/index.js b/demos/renderprops/messages/index.js index f9da572..2beb672 100644 --- a/demos/renderprops/messages/index.js +++ b/demos/renderprops/messages/index.js @@ -1,9 +1,11 @@ import React from 'react' -import { Transition, config } from 'react-spring/renderprops' +import { Transition, config } from 'react-spring' import lorem from 'lorem-ipsum' import { X } from 'react-feather' import { Main, Container, Message, Button, Content, Life } from './styles.js' +// TODO: fix (wasn't properly working before this commit) + let id = 0 let spring = { ...config.default, precision: 0.1 } let generateMsg = () => ({ key: id++, msg: lorem() }) diff --git a/demos/renderprops/morph/index.js b/demos/renderprops/morph/index.js index 07fb5a6..961809e 100644 --- a/demos/renderprops/morph/index.js +++ b/demos/renderprops/morph/index.js @@ -1,8 +1,10 @@ import React from 'react' -import { Spring, animated } from 'react-spring/renderprops' +import { Spring, animated } from 'react-spring' import { interpolate } from 'flubber' import { GradientPinkRed as Gradient } from '@vx/gradient' +// TODO: fix glitches + const paths = [ 'M12 17.27L18.18 21l-1.64-7.03L22 9.24l-7.19-.61L12 2 9.19 8.63 2 9.24l5.46 4.73L5.82 21z', 'M12 21.35l-1.45-1.32C5.4 15.36 2 12.28 2 8.5 2 5.42 4.42 3 7.5 3c1.74 0 3.41.81 4.5 2.09C13.09 3.81 14.76 3 16.5 3 19.58 3 22 5.42 22 8.5c0 3.78-3.4 6.86-8.55 11.54L12 21.35z', @@ -46,7 +48,7 @@ export default class App extends React.Component { from={{ t: 0 }} to={{ t: 1 }} onRest={this.goNext}> - {({ t }) => } + {({ t }) => } diff --git a/demos/renderprops/nativespring/index.js b/demos/renderprops/nativespring/index.js index 3980863..794b615 100644 --- a/demos/renderprops/nativespring/index.js +++ b/demos/renderprops/nativespring/index.js @@ -1,5 +1,5 @@ -import React from 'react' -import { Spring, animated, interpolate } from 'react-spring/renderprops' +import React, { useState, useCallback } from 'react' +import { Spring, animated } from 'react-spring' const TRIANGLE = 'M20,380 L380,380 L380,380 L200,20 L20,380 Z' const RECTANGLE = 'M20,20 L20,380 L380,380 L380,20 L20,20 Z' @@ -14,50 +14,41 @@ const styles = { shape: { width: 300, height: 300, willChange: 'transform' }, } -export default class NativeSpringExample extends React.Component { - state = { toggle: true } - toggle = () => this.setState(state => ({ toggle: !state.toggle })) - componentDidMount() { - //setInterval(() => this.forceUpdate(), 1000) - } - render() { - const toggle = this.state.toggle - return ( - console.log('done')}> - {({ toggle, backgroundColor, fill, rotate, scale, shape }) => ( - - `rotate3d(0,1,0,${r}) scale(${s})` - ), - }} - version="1.1" - viewBox="0 0 400 400"> - - - - - - )} - - ) - } +export default function() { + const [flag, setFlag] = useState(true) + const toggle = useCallback(() => setFlag(f => !f), []) + + return ( + + {({ backgroundColor, fill, rotate, scale, shape }) => ( + + + + + + + + )} + + ) } diff --git a/demos/renderprops/pagetransitions/index.js b/demos/renderprops/pagetransitions/index.js index 679d1a7..9df82ee 100644 --- a/demos/renderprops/pagetransitions/index.js +++ b/demos/renderprops/pagetransitions/index.js @@ -1,7 +1,9 @@ import React from 'react' -import { Transition, animated } from 'react-spring/renderprops' +import { Transition, animated } from 'react-spring' import './styles.css' +// TODO: fix + const pages = [ style => ( A diff --git a/demos/renderprops/parallax/index.js b/demos/renderprops/parallax/index.js index 882b299..76699f7 100644 --- a/demos/renderprops/parallax/index.js +++ b/demos/renderprops/parallax/index.js @@ -2,9 +2,11 @@ // https://dribbble.com/shots/4138489-Screeners import React from 'react' -import { Parallax, ParallaxLayer } from 'react-spring/renderprops-addons' +import { Parallax, ParallaxLayer } from 'react-spring' import './styles.css' +// TODO: fix + const Page = ({ offset, gradient, onClick }) => ( diff --git a/demos/renderprops/parallaxvert/index.js b/demos/renderprops/parallaxvert/index.js index 19fafa6..54f9306 100644 --- a/demos/renderprops/parallaxvert/index.js +++ b/demos/renderprops/parallaxvert/index.js @@ -1,5 +1,7 @@ import React from 'react' -import { Parallax, ParallaxLayer } from 'react-spring/renderprops-addons' +import { Parallax, ParallaxLayer } from 'react-spring' + +// TODO: fix or remove // Little helpers ... const url = (name, wrap = false) => diff --git a/demos/renderprops/reveals/index.js b/demos/renderprops/reveals/index.js index 33acc74..d1dc546 100644 --- a/demos/renderprops/reveals/index.js +++ b/demos/renderprops/reveals/index.js @@ -1,7 +1,9 @@ import React from 'react' -import { Transition, animated } from 'react-spring/renderprops' +import { Transition, animated } from 'react-spring' import './styles.css' +// TODO: fix + export default class App extends React.PureComponent { state = { show: true } toggle = e => this.setState(state => ({ show: !state.show })) diff --git a/demos/renderprops/router/index.js b/demos/renderprops/router/index.js index ad6de42..e99fc44 100644 --- a/demos/renderprops/router/index.js +++ b/demos/renderprops/router/index.js @@ -1,5 +1,5 @@ import React from 'react' -import { Transition, animated } from 'react-spring/renderprops' +import { Transition, animated } from 'react-spring' import { HashRouter as Router, Switch, @@ -9,6 +9,8 @@ import { } from 'react-router-dom' import './styles.css' +// TODO: fix + const App = () => ( { // None of this will cause React to render, the component renders only once :-) while (true) { diff --git a/demos/renderprops/scroll/index.js b/demos/renderprops/scroll/index.js index b62d65e..cd9a94a 100644 --- a/demos/renderprops/scroll/index.js +++ b/demos/renderprops/scroll/index.js @@ -1,7 +1,9 @@ import React from 'react' -import { Spring, animated, config } from 'react-spring/renderprops' +import { Spring, animated, config } from 'react-spring' import './styles.css' +// TODO: fix (wasn't working prior to this commit: no errors but nothing happened) + const COLORS = [ 'crimson', 'teal', diff --git a/demos/renderprops/simple-spring/index.js b/demos/renderprops/simple-spring/index.js index 8a16ed4..9bca7e4 100644 --- a/demos/renderprops/simple-spring/index.js +++ b/demos/renderprops/simple-spring/index.js @@ -1,5 +1,9 @@ import React from 'react' -import { Spring } from 'react-spring/renderprops' +import { Spring } from 'react-spring' + +// TODO: fix or remove +// I would advise to remove this example it feels like a duplicate of nativespring +// - David const TRIANGLE = 'M20,380 L380,380 L380,380 L200,20 L20,380 Z' const RECTANGLE = 'M20,20 L20,380 L380,380 L380,20 L20,20 Z' @@ -63,7 +67,7 @@ export default class SpringExample extends React.Component { fill={color} fillRule="evenodd" onClick={this.toggle}> - +
diff --git a/demos/renderprops/sunburst/index.js b/demos/renderprops/sunburst/index.js index 8fc2577..58fbfde 100644 --- a/demos/renderprops/sunburst/index.js +++ b/demos/renderprops/sunburst/index.js @@ -5,11 +5,13 @@ import { ParentSize } from '@vx/responsive' import { arc as d3arc } from 'd3-shape' import { scaleLinear, scaleSqrt, scaleOrdinal } from 'd3-scale' import { interpolate as d3interpolate } from 'd3-interpolate' -import { Spring, animated } from 'react-spring/renderprops' +import { Spring, animated } from 'react-spring' import Partition from './Partition' import data from './data' import './styles.css' +// TODO: move to functional components + var color = scaleOrdinal().range([ '#FE938C', '#E6B89C', diff --git a/demos/renderprops/timing/index.js b/demos/renderprops/timing/index.js index 64e67af..da75223 100644 --- a/demos/renderprops/timing/index.js +++ b/demos/renderprops/timing/index.js @@ -1,7 +1,9 @@ import React from 'react' -import { Keyframes, animated } from 'react-spring/renderprops' +import { Keyframes, animated } from 'react-spring' //import { TimingAnimation, Easing } from '../../../src/addons' +// TODO: fix + const Container = Keyframes.Spring(async next => { while (true) { await next({ diff --git a/demos/renderprops/trails/index.js b/demos/renderprops/trails/index.js index dbebd3f..4bcc37e 100644 --- a/demos/renderprops/trails/index.js +++ b/demos/renderprops/trails/index.js @@ -1,39 +1,39 @@ -import React from 'react' -import { Trail, animated } from 'react-spring/renderprops' +import React, { useState } from 'react' +import { Trail, animated } from 'react-spring' import './styles.css' -export default class TrailsExample extends React.PureComponent { - state = { toggle: true, items: ['item1', 'item2', 'item3', 'item4', 'item5'] } - toggle = () => this.setState(state => ({ toggle: !state.toggle })) - render() { - const { toggle, items } = this.state - return ( -
- - {item => ({ x, opacity }) => ( - `translate3d(${x}%,0,0)`), - }} - /> - )} - -
- ) - } +// TODO: fix (animation is broken) + +const items = ['item1', 'item2', 'item3', 'item4', 'item5'] + +export default function TrailsExample() { + const [toggle, setToggle] = useState(true) + return ( +
+ + {item => ({ x, opacity }) => ( + setToggle(t => !t)} + style={{ + opacity, + transform: x.to(x => `translate3d(${x}%,0,0)`), + }} + /> + )} + +
+ ) } diff --git a/demos/renderprops/transitiongroup/index.js b/demos/renderprops/transitiongroup/index.js index a3e7753..4254b71 100644 --- a/demos/renderprops/transitiongroup/index.js +++ b/demos/renderprops/transitiongroup/index.js @@ -1,7 +1,9 @@ import React from 'react' -import { Transition, animated } from 'react-spring/renderprops' +import { Transition, animated } from 'react-spring' import './styles.css' +// TODO: fix + export default class App extends React.PureComponent { state = { items: [] } diff --git a/demos/renderprops/transitions/index.js b/demos/renderprops/transitions/index.js index 0c0846e..182a282 100644 --- a/demos/renderprops/transitions/index.js +++ b/demos/renderprops/transitions/index.js @@ -1,5 +1,7 @@ import React from 'react' -import { Transition, animated } from 'react-spring/renderprops' +import { Transition, animated } from 'react-spring' + +// TODO: fix const defaultStyles = { overflow: 'hidden', diff --git a/demos/renderprops/tree/LinksMove.js b/demos/renderprops/tree/LinksMove.js index d9877eb..85b2913 100644 --- a/demos/renderprops/tree/LinksMove.js +++ b/demos/renderprops/tree/LinksMove.js @@ -1,10 +1,12 @@ import React from 'react' import { Group } from '@vx/group' -import { Transition } from 'react-spring/renderprops' +import { Transition } from 'react-spring' import Link from './Link' import { findCollapsedParent } from './utils' +// TODO: fix + function Links({ links, linkType, layout, orientation, stepPercent }) { return ( diff --git a/demos/renderprops/treeview/Tree.js b/demos/renderprops/treeview/Tree.js index 9c91279..3e6a0d4 100644 --- a/demos/renderprops/treeview/Tree.js +++ b/demos/renderprops/treeview/Tree.js @@ -1,8 +1,11 @@ import React from 'react' import PropTypes from 'prop-types' -import { Spring, config, animated } from 'react-spring/renderprops' +import { Spring, config, animated } from 'react-spring' import * as Icons from './icons' +// TODO: fix +// works but some animations are missing + const styles = { tree: { position: 'relative', @@ -103,7 +106,7 @@ export default class Tree extends React.PureComponent { opacity: open ? 1 : 0, transform: open ? 'translate3d(0px,0,0)' : 'translate3d(20px,0,0)', }} - {...springConfig && springConfig(open)}> + {...(springConfig && springConfig(open))}> {style => ( {children} diff --git a/demos/tests/freshtilledsoil/index.js b/demos/tests/freshtilledsoil/index.js index 48fedda..c14fbba 100644 --- a/demos/tests/freshtilledsoil/index.js +++ b/demos/tests/freshtilledsoil/index.js @@ -56,8 +56,8 @@ export default function Container() { const TransitionGrid = ({ visible, items, removeItem }) => { const containerRef = useRef() - const containerTransition = useTransition(visible, null, { - config: { ...config.stiff, precision: 0.01 }, + const containerTransition = useTransition(visible, { + config: config.stiff, from: { opacity: 0, x: -500 }, enter: { opacity: 1, x: 0 }, leave: { opacity: 0, x: 500 }, @@ -67,7 +67,7 @@ const TransitionGrid = ({ visible, items, removeItem }) => { }) const itemsRef = useRef() - const itemsTransition = useTransition(visible ? items : [], null, { + const itemsTransition = useTransition(visible ? items : [], { config: { ...config.stiff, precision: 0.01 }, from: { opacity: 0, scale: 0 }, enter: { opacity: 1, scale: 1 }, @@ -88,11 +88,10 @@ const TransitionGrid = ({ visible, items, removeItem }) => { return (
- {containerTransition.map( - ({ item, key, props: { x, opacity } }) => + {containerTransition( + ({ x, opacity }, item) => item && ( { transform: x.interpolate(x => `translateX(${x}px)`), }} className="fts-grid fts-animated-grid"> - {itemsTransition.map( - ({ item, key, props: { scale, opacity } }) => ( - `scale(${s})`), - }} - onClick={() => removeItem(item)}> -
-
{item}
-
- ) - )} + {itemsTransition(({ scale, opacity }, item) => ( + `scale(${s})`), + }} + onClick={() => removeItem(item)}> +
+
{item}
+
+ ))}
) )} diff --git a/demos/tests/issue-436/index.js b/demos/tests/issue-436/index.js index 0a89cf3..98d86d5 100644 --- a/demos/tests/issue-436/index.js +++ b/demos/tests/issue-436/index.js @@ -12,24 +12,22 @@ import { useTransition, animated as a } from 'react-spring' export default function App() { const [reset, setReset] = useState(false) const [item, setItem] = useState(0) - const t = useTransition(item, null, { - keys: i => i, + const t = useTransition(item, { initial: null, reset, from: { transform: 'translate(-100%)' }, enter: { transform: 'translate(0%)' }, leave: { transform: 'translate(100%)' }, }) - const items = t.map(({ item, key, props }) => ( + const items = t((style, item) => ( { setItem(i => i + 1) diff --git a/demos/tests/remove_multiple_items/index.js b/demos/tests/issue-461/index.js similarity index 81% rename from demos/tests/remove_multiple_items/index.js rename to demos/tests/issue-461/index.js index 1161720..6fb2a30 100644 --- a/demos/tests/remove_multiple_items/index.js +++ b/demos/tests/issue-461/index.js @@ -9,7 +9,7 @@ export default function Container() { const addItems = useCallback(() => setItems(range(10))) - const transitions = useTransition(items, null, { + const transition = useTransition(items, { from: { transform: 'translate3d(0,40px,0)', opacity: 0 }, enter: { transform: 'translate3d(0,0px,0)', opacity: 1 }, leave: { transform: 'translate3d(0,40px,0)', opacity: 0 }, @@ -24,10 +24,8 @@ export default function Container() { Add
- {transitions.map(({ item, key, props }) => ( - - {item} - + {transition((style, item) => ( + {item} ))}
diff --git a/demos/tests/issue-639/index.js b/demos/tests/issue-639/index.js index f4244e9..975abc1 100644 --- a/demos/tests/issue-639/index.js +++ b/demos/tests/issue-639/index.js @@ -6,7 +6,12 @@ import './styles.css' export default function App() { const [index, set] = useState(0) - const conf = + useEffect(() => { + setInterval(() => set(state => (state + 1) % 4), 2000) + }, []) + + const transition = useTransition( + slides[index], index % 2 ? { leave: { transform: `translateX(100%)` }, @@ -19,20 +24,14 @@ export default function App() { from: { transform: `rotateX(40deg) translateY(-20%)` }, config: config.molasses, } - const transitions = useTransition(slides[index], item => item.id, conf) - useEffect( - () => void setInterval(() => set(state => (state + 1) % 4), 2000), - [] ) - return transitions.map(({ item, props, key }) => ( + + return transition((style, item) => ( )) diff --git a/demos/tests/issue-645/index.js b/demos/tests/issue-645/index.js index 24b2e64..4720926 100644 --- a/demos/tests/issue-645/index.js +++ b/demos/tests/issue-645/index.js @@ -11,15 +11,22 @@ export default function App() { // this way we can inject the springs current coordinates on the initial event and // add delta to it for convenience const bind = useGesture( - ({ down, delta, velocity, direction, temp = xy.getValue() }) => { - console.log('gesture.isDown ==', down) + ({ down, delta, velocity, direction, memo = xy.get() }) => { + console.log( + '(down: %O, delta: %O, velocity: %O, direction: %O, memo: %O)', + down, + delta, + velocity, + direction, + memo + ) set({ - xy: add(delta, temp), + xy: add(delta, memo), immediate: down, config: { velocity: scale(direction, velocity), decay: true }, reset: !down, }) - return temp + return memo } ) return ( diff --git a/demos/tests/issue-650/index.js b/demos/tests/issue-650/index.js index 80eba33..b4728ba 100644 --- a/demos/tests/issue-650/index.js +++ b/demos/tests/issue-650/index.js @@ -17,9 +17,8 @@ export default function App() { from={{ opacity: 0 }} enter={{ opacity: 1 }} leave={{ opacity: 0 }}> - {show => - show && - (props => Hello world) + {(style, show) => + show && Hello world } ) diff --git a/demos/tests/issue-657/index.js b/demos/tests/issue-657/index.js index 37fe8fb..cc063aa 100644 --- a/demos/tests/issue-657/index.js +++ b/demos/tests/issue-657/index.js @@ -18,7 +18,7 @@ export default function App() { return ( <> - +
{props.map(({ x }, i) => ( (this.parallax = ref)} pages={2}> + +
+ + +
+ + +
+ + +
+ + + ) + } +} diff --git a/demos/tests/issue-827/index.js b/demos/tests/issue-827/index.js new file mode 100644 index 0000000..acf48d0 --- /dev/null +++ b/demos/tests/issue-827/index.js @@ -0,0 +1,44 @@ +import React, { useCallback } from 'react' +import ReactDOM from 'react-dom' +import { useSpring, animated, config } from 'react-spring' + +function linearGradient(deg, startColor, startPosition, endColor, endPosition) { + return `linear-gradient(${deg}deg, ${startColor} ${startPosition}, ${endColor} ${endPosition})` +} + +function useLinearGradient(from, to) { + return useSpring(() => ({ + from: { background: from }, + to: async next => { + let i = 500 + let reverse = false + while (--i > 0) { + reverse = !reverse + await next({ + to: { background: to }, + from: { background: from }, + reverse, + config: config.slow, + }) + } + }, + })) +} + +export default function App() { + // The background gradient + const [gradient] = useLinearGradient( + linearGradient(135, 'rgb(185, 198, 109)', '0%', 'rgb(34, 48, 17)', '100%'), + linearGradient(45, 'rgb(85, 69, 47)', '0%', 'rgb(218, 102, 92)', '100%') + ) + + return ( + + ) +} diff --git a/demos/tests/parallax/index.js b/demos/tests/parallax/index.js new file mode 100644 index 0000000..25f3a32 --- /dev/null +++ b/demos/tests/parallax/index.js @@ -0,0 +1,163 @@ +import React from 'react' +import { Parallax, ParallaxLayer } from '@react-spring/parallax' + +const url = (name, wrap = false) => + (wrap ? 'url(' : '') + + `https://awv3node-homepage.surge.sh/build/assets/${name}.svg` + + (wrap ? ')' : '') + +export default class App extends React.Component { + render() { + return ( + (this.parallax = ref)} pages={3}> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + this.parallax.scrollTo(1)} + style={{ + display: 'flex', + alignItems: 'center', + justifyContent: 'center', + }}> + + + + this.parallax.scrollTo(2)} + style={{ + display: 'flex', + alignItems: 'center', + justifyContent: 'center', + }}> + + + + this.parallax.scrollTo(0)}> + + + + ) + } +} diff --git a/index.js b/index.js index 7771661..a15bc1c 100644 --- a/index.js +++ b/index.js @@ -2,12 +2,12 @@ import React from 'react' import ReactDOM from 'react-dom' import DemoGrid from './components/DemoGrid' import Demo from './components/Demo' -import examples from './components/examples-hooks' +import examples from './components/examples-renderprops' // import examples from './components/examples-tests' import './styles.css' -const DEBUG = false -//const DEBUG = 'tree' +let DEBUG = false +DEBUG = 'chathead' ReactDOM.render( diff --git a/package.json b/package.json index 53a2037..53f986e 100644 --- a/package.json +++ b/package.json @@ -63,6 +63,7 @@ }, "dependencies": { "@babel/runtime": "^7.3.1", + "@react-spring/parallax": "latest", "@react-spring/web": "latest", "@types/react": "^16.8.14", "@types/styled-components": "^4.1.14", @@ -75,6 +76,7 @@ "react-feather": "^1.1.6", "react-loadable": "^5.5.0", "react-spring": "^8.0.5", + "react-use-gesture": "^6.0.14", "react-with-gesture": "^4.0.2", "resize-observer-polyfill": "^1.5.1", "styled-components": "^4.1.3", diff --git a/template.html b/template.html index bde0ab3..b344b9b 100644 --- a/template.html +++ b/template.html @@ -1,11 +1,18 @@ - - + + react-spring examples - - - + + + +
- - \ No newline at end of file + + diff --git a/tsconfig.json b/tsconfig.json index e0d080e..68047a0 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -3,13 +3,6 @@ "jsx": "react", "lib": ["es2017", "dom"], "target": "es2017", - "baseUrl": ".", - "paths": { - "react-spring": [ - "../targets/web/src/index.ts", - "./node_modules/@react-spring/web/index.js" - ] - }, "noEmitOnError": true, "preserveSymlinks": true, "allowSyntheticDefaultImports": true, diff --git a/webpack.config.js b/webpack.config.js index 6369ee3..2dc3de4 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -1,7 +1,5 @@ const path = require('path') const HtmlWebpackPlugin = require('html-webpack-plugin') -const { CheckerPlugin } = require('awesome-typescript-loader') -// const CheckerPlugin = require('fork-ts-checker-webpack-plugin') const webpack = require('webpack') const fs = require('fs') @@ -62,7 +60,6 @@ module.exports = mode => { { test: /\.tsx?$/, use: { - // loader: 'ts-loader', loader: 'awesome-typescript-loader', options: { transpileOnly: true, @@ -103,14 +100,16 @@ module.exports = mode => { extensions: ['.js', '.jsx', '.ts', '.tsx'], alias: buildAliases(), }, - plugins: [ - new CheckerPlugin(), - new HtmlWebpackPlugin({ template: 'template.html' }), - ], + plugins: [new HtmlWebpackPlugin({ template: 'template.html' })], devServer: { hot: false, contentBase: path.resolve('./'), - stats: 'errors-only', + stats: { + assets: false, + children: false, + chunks: false, + entrypoints: false, + }, }, devtool: 'inline-source-map', performance: { hints: false }, diff --git a/yarn.lock b/yarn.lock index 637b479..c648462 100644 --- a/yarn.lock +++ b/yarn.lock @@ -767,6 +767,14 @@ resolved "https://registry.yarnpkg.com/@emotion/unitless/-/unitless-0.7.4.tgz#a87b4b04e5ae14a88d48ebef15015f6b7d1f5677" integrity sha512-kBa+cDHOR9jpRJ+kcGMsysrls0leukrm68DmFQoMIWQcXdr2cZvyvypWuGYT7U+9kAExUE7+T7r6G3C3A6L8MQ== +"@react-spring/animated@9.0.0-canary.808.5.5cdf687": + version "9.0.0-canary.808.5.5cdf687" + resolved "https://registry.npmjs.org/@react-spring/animated/-/animated-9.0.0-canary.808.5.5cdf687.tgz#9afea910ea8e66b481ee1fadb8a058ccd7c7b658" + integrity sha512-araRTypVfa4oRuK4+o/9s33IwUIMy8qFcNO9igJBQQrg7jEBtzFuB2PiRZIjdQT0nkEEMwcQ/upOBs0vKhApJA== + dependencies: + "@babel/runtime" "^7.3.1" + "@react-spring/shared" "9.0.0-canary.808.5.5cdf687" + "@react-spring/animated@^9.0.0-beta.29": version "9.0.0-beta.29" resolved "https://registry.yarnpkg.com/@react-spring/animated/-/animated-9.0.0-beta.29.tgz#0730748014b8ff43bdff486e68f4511ff8853f86" @@ -775,6 +783,16 @@ "@babel/runtime" "^7.3.1" "@react-spring/shared" "^9.0.0-beta.29" +"@react-spring/core@9.0.0-canary.808.5.5cdf687": + version "9.0.0-canary.808.5.5cdf687" + resolved "https://registry.npmjs.org/@react-spring/core/-/core-9.0.0-canary.808.5.5cdf687.tgz#03b4dd0de008cff227e052c897cac27c98c2ce80" + integrity sha512-P3FxQ/7t0r5xmFXo1PEZE161kgYundjCYyNG0QU3Z37ad3bMAOx81I5N6W8stmkE4EVkX3QXl7cChCq6aYtK7g== + dependencies: + "@babel/runtime" "^7.3.1" + "@react-spring/animated" "9.0.0-canary.808.5.5cdf687" + "@react-spring/shared" "9.0.0-canary.808.5.5cdf687" + use-memo-one "^1.1.0" + "@react-spring/core@^9.0.0-beta.29": version "9.0.0-beta.29" resolved "https://registry.yarnpkg.com/@react-spring/core/-/core-9.0.0-beta.29.tgz#dc0463725bdedd662b580b8b594e9b7818acf7ce" @@ -785,6 +803,24 @@ "@react-spring/shared" "^9.0.0-beta.29" use-memo-one "^1.1.0" +"@react-spring/parallax@latest": + version "9.0.0-canary.808.5.5cdf687" + resolved "https://registry.npmjs.org/@react-spring/parallax/-/parallax-9.0.0-canary.808.5.5cdf687.tgz#6cf7743eed94b1a0cc2b0131c500db1a8dfa35ad" + integrity sha512-47b+EuyeukDQuFVobSh5ouM8u4UQSAfvnSXd6YqK/atrjZdxVpiIoTpo3tGCxmH5DVnFXb0zBnansDNt8r5gbA== + dependencies: + "@babel/runtime" "^7.3.1" + "@react-spring/shared" "9.0.0-canary.808.5.5cdf687" + "@react-spring/web" "9.0.0-canary.808.5.5cdf687" + use-memo-one "^1.1.0" + +"@react-spring/shared@9.0.0-canary.808.5.5cdf687": + version "9.0.0-canary.808.5.5cdf687" + resolved "https://registry.npmjs.org/@react-spring/shared/-/shared-9.0.0-canary.808.5.5cdf687.tgz#020e3193639a8fe15c7816ed3e6cc1f7ea9fb11b" + integrity sha512-D8ZsZ0xCMhnR8CzNibb/fYB4q6B2uwum5p31k0Fcnx0UQpXTgIJn+loSaKbp3TKnbp1MFLYnoc5Im0BbCNF+7w== + dependencies: + "@babel/runtime" "^7.3.1" + fluids "^0.1.0" + "@react-spring/shared@^9.0.0-beta.29": version "9.0.0-beta.29" resolved "https://registry.yarnpkg.com/@react-spring/shared/-/shared-9.0.0-beta.29.tgz#5b2bb43b20369ea921a9eb53bfe11c46fa3e8593" @@ -793,6 +829,16 @@ "@babel/runtime" "^7.3.1" tiny-invariant "^1.0.4" +"@react-spring/web@9.0.0-canary.808.5.5cdf687": + version "9.0.0-canary.808.5.5cdf687" + resolved "https://registry.npmjs.org/@react-spring/web/-/web-9.0.0-canary.808.5.5cdf687.tgz#ea6e4700d4c29342dd8fc6230938600ac8d0e6e7" + integrity sha512-5OUGRzwS0oaUR+3LlFdFzQ9SbjPoEU16+8ZXLjjlTmwtmuLrxu9w6qWvOtwsQ+6KlNiy1HeVjZIVY/Z3+LaVFw== + dependencies: + "@babel/runtime" "^7.3.1" + "@react-spring/animated" "9.0.0-canary.808.5.5cdf687" + "@react-spring/core" "9.0.0-canary.808.5.5cdf687" + "@react-spring/shared" "9.0.0-canary.808.5.5cdf687" + "@react-spring/web@latest": version "9.0.0-beta.29" resolved "https://registry.yarnpkg.com/@react-spring/web/-/web-9.0.0-beta.29.tgz#9476285e0d56a5e4bae938ffd5044ac5812ed2c0" @@ -3168,6 +3214,11 @@ flubber@^0.4.2: svgpath "^2.2.1" topojson-client "^3.0.0" +fluids@^0.1.0: + version "0.1.3" + resolved "https://registry.npmjs.org/fluids/-/fluids-0.1.3.tgz#00887a206927d4aca38cfb0b0c7bd62758a85b0d" + integrity sha512-MyvtLf3QCMm5MYkAptXJrzOz8e4tMxOz+g0BlT3GVE5glqovO2ZMZj0DvJPpo9Lk9Y8+Llwt4KsmhHbPc2GeVg== + flush-write-stream@^1.0.0: version "1.1.1" resolved "https://registry.yarnpkg.com/flush-write-stream/-/flush-write-stream-1.1.1.tgz#8dd7d873a1babc207d94ead0c2e0e44276ebf2e8" @@ -6277,6 +6328,11 @@ react-spring@^8.0.5: "@babel/runtime" "^7.3.1" prop-types "^15.5.8" +react-use-gesture@^6.0.14: + version "6.0.14" + resolved "https://registry.yarnpkg.com/react-use-gesture/-/react-use-gesture-6.0.14.tgz#ab2d35ef72a5fb6060a6160eb12568c276f8a4b1" + integrity sha512-d9cnZJ0DOFd3FIO76J776DyhtbODgbxGKu19lvc1aSNTnRV5EKr9V4Uda188l2Qh0Va3pqWGxEQlw72r2cmnFQ== + react-with-gesture@^4.0.2: version "4.0.8" resolved "https://registry.yarnpkg.com/react-with-gesture/-/react-with-gesture-4.0.8.tgz#ce6db9e667ef13120797e641f1a00f934aed6c36"