JavaScript est désactivé. Le code ci-dessous est l’exemple complet.
App.jsx import { useRef, useState } from 'react' ;
import {
Animated ,
dragInput,
input,
useAnimated,
useAnimatedListener,
} from '@kkwaenggwari/animated' ;
import './styles.css' ;
const cards = [
{ id : 1 , title : 'Kyoto' , color : '#2854ff' },
{ id : 2 , title : 'Lisbon' , color : '#8fb0ff' },
{ id : 3 , title : 'Oaxaca' , color : '#5c7cff' },
{ id : 4 , title : 'Tromsø' , color : '#16181d' },
{ id : 5 , title : 'Busan' , color : '#4a6bff' },
];
function TopCard ({ card, threshold, rotation, onGone } ) {
const node = useRef (null );
const gone = useRef (false );
const drag = useAnimated (
{ x : 0 , y : 0 },
(point ) => {
input (
node,
dragInput ({
x : point.x ,
y : point.y ,
settle : ({ projected } ) =>
Math .abs (projected.x ) > threshold
? { x : Math .sign (projected.x ) * 560 , y : projected.y }
: { x : 0 , y : 0 },
}),
);
},
[threshold],
);
useAnimatedListener (drag.x , ({ value } ) => {
if (!gone.current && Math .abs (value) > 540 ) {
gone.current = true ;
onGone (value > 0 ? 'Keep' : 'Skip' );
}
});
const rotate = drag.x .interpolate ({
inputRange : [-300 , 300 ],
outputRange : [`${-rotation} deg` , `${rotation} deg` ],
});
const keep = drag.x .interpolate ({
inputRange : [0 , threshold],
outputRange : [0 , 1 ],
extrapolate : 'clamp' ,
});
const skip = drag.x .interpolate ({
inputRange : [-threshold, 0 ],
outputRange : [1 , 0 ],
extrapolate : 'clamp' ,
});
return (
<div
ref ={node}
className ="card top"
style ={{
background: card.color ,
transform: `translate (calc (${drag.x } * 1px ), calc (${drag.y } * 1px )) rotate (${rotate })`,
}}
>
<strong > {card.title}</strong >
<span className ="stamp keep" style ={{ opacity: keep }}>
Keep
</span >
<span className ="stamp skip" style ={{ opacity: skip }}>
Skip
</span >
</div >
);
}
export default function App ({ threshold = 120 , rotation = 16 } ) {
const [deck, setDeck] = useState (cards);
const [last, setLast] = useState ('Swipe the top card' );
const gone = (verdict ) => {
setLast (`${deck[0 ].title} : ${verdict} ` );
setDeck ((list ) => list.slice (1 ));
};
return (
<div className ="stage" >
<div className ="deck" >
{deck.map((card, depth) => (
<Animated.div
key ={card.id}
className ="slot"
style ={{ zIndex: deck.length - depth }}
pose ={{
opacity: depth < 3 ? 1 : 0 ,
transform: [{ translateY: depth * 16 }, { scale: 1 - depth * 0.06 }],
}}
tempo ={{ spring: { stiffness: 260 , damping: 22 } }}
>
{depth === 0 ? (
<TopCard card ={card} threshold ={threshold} rotation ={rotation} onGone ={gone} />
) : (
<div className ="card" style ={{ background: card.color }}>
<strong > {card.title}</strong >
</div >
)}
</Animated.div >
))}
{deck.length === 0 && (
<button type ="button" className ="reset" onClick ={() => setDeck(cards)}>
Deal again
</button >
)}
</div >
<output > {last}</output >
</div >
);
}