React - Product Fly to cart animation using framer-motion - reactjs

i want an animation that takes the product Card and put it on the card like a fly animation and i want to use the framer-motion the problem that i have is when i set the x,y of the animation all of them goes to the same place
i tried the GSAP library but i didn't know how to manage it.
if there's any other libraries that i can use with explaination feel free to share
Here's my code :
const [xValue, setxValue] = useState(0);
const [yValue, setyValue] = useState(0);
const handleClick = async (p) => {
await set_order({
...order,
products: {
...order?.products,
[order?.products?.length]: { ...p, qte: 1 },
},
});
setxValue(45);
setyValue(45);
<motion.div
initial={{ opacity: 0 }}
animate={{ opacity: 1, x : xValue , y : yValue }}
transition={{ duration: 1 }}
exit={{ opacity: 0 }}
>
<Card
// ref={ref_card}
onClick={() => handleClick(product)}
i tried the gsap library and now im trying the framer motion
couldn't find that much resources that have this kinda of animation
i only found one that uses the gsap and i couldn't apply it
thank you for sharing any informations regarding this issue

Related

Best way to make a custom smooth scroll and scrollto coexist (ReactJs - Framer motion)

Made a smoothscroll component using framer motion that's working well :
export default function SmoothScroll({ children }: Props) {
const { width } = useWindowSize();
const scrollContainer = useRef() as RefObject<HTMLDivElement>;
const [pageHeight, setPageHeight] = useState(0);
useEffect(() => {
setTimeout(() => {
// added a setTimeout so the page has the time to load and it still fits
const scrollContainerSize =
scrollContainer.current?.getBoundingClientRect();
scrollContainerSize && setPageHeight(scrollContainerSize.height);
}, 500);
}, [width]);
const { scrollY } = useScroll(); // measures how many pixels user has scrolled vertically
// as scrollY changes between 0px and the scrollable height, create a negative scroll value...
// ... based on current scroll position to translateY
const transform = useTransform(scrollY, [0, pageHeight], [0, -pageHeight]);
const physics = { damping: 15, mass: 0.17, stiffness: 55 }; // easing of smooth scroll
const spring = useSpring(transform, physics); // apply easing to the negative scroll value
return (
<>
<motion.div
ref={scrollContainer}
style={{ y: spring }} // translateY of scroll container using negative scroll value
className="app fixed overflow-hidden w-screen"
>
{children}
</motion.div>
<motion.div style={{ height: pageHeight }} />
</>
);
}
The thing is, I'd like to scrollTo sections of my page upon click on the navbar but don't really know how to implement it without removing the smoothScroll ...
Tried the following logic but obviously it did not work as the vanilla scroll has been hijacked :
const scrollToSection = (
e: React.MouseEvent<HTMLLIElement, globalThis.MouseEvent>,
anchor?: string
) => {
e.preventDefault();
if (!anchor) return;
const section = document.querySelector(anchor);
section?.scrollIntoView({ behavior: "smooth" });
};
Is it doable ?

React - Framer motion: prevent initial prop from triggering

I have a basic CRUD application where I'm able to add and remove items on a list, which is animated. This works well with framer-motion, but I'm having troubles with the following:
Whenever I delete an item from the list, the following function is called:
const handleDeleteFormation = async (id) => {
await axios({
method: "DELETE",
url: `http://localhost:1337/formations/${id}`
})
getFormations()
}
As you can clearly see, I'm calling the getFormations() function after the deletion to re-render the updated list:
async function getFormations() {
const res = await axios.get('http://localhost:1337/formations')
setFormations(res.data)
console.log(res.data)
}
This will results in a re-render of the list, which is good. But... right after the re-render, the initial prop of the motion.div will be triggered again which results in conflicting visuals.
<AnimatePresence exitBeforeEnter initial={false}>
{formations && formations.map((formation, index) =>
<motion.div
key={formation.id}
initial={{ opacity: 0, x: -10 }}
animate={{ opacity: 1, x: 0 }}
exit={{ opacity: 0, x: -10 }}
transition={{ type: "tween", ease: 'easeOut', duration: 0.2 }}
>
...
My question: is it possible to prevent the initial prop from triggering right after the list-update?
You're looking for <AnimatePresence initial={false}>.
From the docs:
Suppressing initial animations
By setting initial={false} on AnimatePresence, components present when
AnimatePresence first loads will start in their animate state. Only
components that enter after this initial render will animate in.

How to add animations between pages in gartsby with Gsap

I want to add animation between pages in gatsby using Gsap.
Im trying to follow their docs: https://www.gatsbyjs.com/docs/how-to/adding-common-features/adding-page-transitions-with-plugin-transition-link/
At some point they say: Finally, import the TransitionLink component wherever you want to use it...
https://www.gatsbyjs.com/docs/how-to/adding-common-features/adding-page-transitions-with-plugin-transition-link/#getting-started
But I dont know where to use, should it be used in the actual pages components or in the Layout component?(I want to have disfferent animations for each page though)
I want to use the trigger function:
https://www.gatsbyjs.com/docs/how-to/adding-common-features/adding-page-transitions-with-plugin-transition-link/#using-the-trigger-function
Because I want to use Gsap.
But then they just write in the code "someCustomDefinedAnimation" but I dont know where is that coming from, how do i create one and how do I pass it through props.
<TransitionLink
exit={{
length: length,
trigger: ({ exit, node }) =>
this.someCustomDefinedAnimation({ exit, node, direction: "out" }),
}}
entry={{
length: 0,
trigger: ({ exit, node }) =>
this.someCustomDefinedAnimation({ exit, node, direction: "in" }),
}}
{...props}
>
{props.children}
</TransitionLink>
So my questions are:
Where should I add the TransitionLink component?
How do I create a custom Gsap animation?
Where and how do i pass animation this as props so that TransitionLink can use it?
But then they just write in the code someCustomDefinedAnimation but
I dont know where is that coming from, how do i create one and how do
I pass it through props.
Well, someCustomDefinedAnimation is just a defined function that contains the animation. For example:
verticalAnimation = ({ length, direction}) => {
const directionTo = direction === 'up' ? '-100%' : '100%'
const directionFrom = direction === 'up' ? '100%' : '-100%'
// convert ms to s for gsap
const seconds = length
return gsap.timeline()
.set(this.transitionCover, { y: directionFrom })
.to(this.transitionCover, {
y: '0%',
ease: "power1.easeInOut",
duration: seconds / 2,
})
.set(this.layoutContents, { opacity: 0 })
.to(this.transitionCover, {
y: directionTo,
ease: "power1.easeIn",
duration: seconds / 2,
})
}
Then you'll need to use it as:
<TransitionLink
exit={{
length: length,
trigger: ({ exit, node }) =>
this.verticalAnimation({length: 100, direction: 'up'}),
}}
entry={{
length: 0,
trigger: ({ exit, node }) =>
this.verticalAnimation({length: 100, direction: "down" }),
}}
{...props}
>
{props.children}
</TransitionLink>
Basically, it allows you to fully customize the function triggered in each page transition
You can find a detailed explanation and walkthrough in TransitionLink docs and an implementation example at their GitHub repository.

odd behavior with framer motion animate on presence

I'm working ona project management application , and I'm developing this feature where the project header can go into editing state where user can edit project title , this header has two child components HeaderContent and EditProjectForm :
>ProjectHeader
-->HeaderContent
-->EditProjectForm
my problem now is that when I fade out the HeaderContent the faded In EditProjectForm is intially pushed down then it jumps to its place , it seems that this happens because even though HeaderContent was faded out it still was affecting the dom structure
here is a short screen recording I just uploaded to further make things clear https://www.youtube.com/watch?v=UerYDuEcUWQ
Header component
const ProjectHeader=()=>{
const [isEditingState, setisEditingProject] = useState({value:false,triggerFrom:"PANEL_HEADER"})
return <div>
<HeaderContent {...{isEditingProject, setisEditingProject}} />
<EditProjectForm {...{isEditingProject, setisEditingProject}} />
</div>
}
HeaderContent
const HeaderContent =({isEditingProject, setisEditingProject})=>{
const [render, setrender] = useState(true)
useEffect(() => {
let ref=null
// if(isEditingProject.triggerFrom =="EDIT_PROJECT_FORM") if I have don this whenever I change isEditingProject.value from this component this setTimeout below will be fired and I want to only be fired when this compoent is unmounted
if(isEditingProject.triggerFrom =="EDIT_PROJECT_FORM"){
ref= setTimeout(() => {
setrender(!isEditingProject.value)
}, 200);//wait until edit form finishes its fade_out animtion
}
return ()=>ref && clearTimeout(ref)
}, [isEditingProject])
return <AnimatePresence initial={false} >
{
render
&&(<motion.div
animate={{opacity:1 ,y:0}}
initial={{opacity:1 ,y:0}}
exit ={{opacity:0 ,y:10}}
transition={{
duration:.2,
opacity: { type: "spring", stiffness: 100 },
}}>
//.. header links and buttons and the title
<button onClick={e=>{
setrender(false)
setisEditingProject({...isEditingProject,value:true,triggerFrom:"PANEL_HEADER"})
}} >edit</button>
}
</AnimatePresence >
}
EditProjectForm
const EditProjectForm =({isEditingProject, setisEditingProject})=>{
const [render, setrender] = useState(true)
useEffect(() => {
let ref =null
// if(isEditingProject.triggerFrom =="PANEL_HEADER") if I haven't don this whenever I change isEditingProject.value from this component this setTimeout below will be fired and I want to only be fired when this compoent is unmounted
if(isEditingProject.triggerFrom =="PANEL_HEADER"){
ref=setTimeout(() => {
setrender(isEditingProject.value)
}, 200);
}
return ()=>ref && clearTimeout(ref)
}, [isEditingProject.value])
return <AnimatePresence>
{
render && <motion.form
animate={{ opacity:1 ,y:0 }}
initial={{ opacity:1 ,y:10 }}
exit ={{ opacity:0 ,y:-10}}
transition={{
duration:.2,
opacity: { type: "spring", stiffness: 100 },
}}
>
/.. title input
<button onClick={e=>{
setrender(false)
setisEditingProject({...isEditingProject,value:true,triggerFrom:"EDIT_PROJECT_FORM"})
}} >edit</button>
</motion.form>
}
</AnimatePresence>
}
It's problem with css, not with framer. My advise is to wrap your component with div absolute position, where top:0;
Maybe, you have some flex divs which trigger this "strange" behaviour

Snapping to position onDragEnd with motionValues using Framer Motion and React

I'm using framer motion to create a swipe interaction in my project. I'm trying to make it so that when the user is done dragging the child, it will 'snap' back into a set position.
I've seen from the docs that you can use a spring to animate a motion value: const y = useSpring(x, { damping: 10 }), but I guess I'm not doing it correctly? Heres my code:
export default function SwipeContainer(props) {
const x = useMotionValue(0);
const m = useSpring(x, { damping: 10 });
const handleDragEnd = (evt) => {
console.log(evt);
m.set(200);
}
return (
<div className={styles.swipeContainer}>
<motion.div
style= {{ x, m }}
className={styles.motionDiv}
drag="x"
onDragEnd={handleDragEnd}
>
{props.children}
</motion.div>
</div>
);
}
I'm expecting that when the dragEnd event happens, the child will animate to x:200, but thats not happening. Am I setting the value incorrectly, or perhaps its how I'm applying the motion values to the motion.div?
I didn't experiment with useSpring yet, but you can get it to work with useAnimation.
Here's a CodeSandbox with a similar situation: https://codesandbox.io/s/framer-motion-bottom-sheet-fixed-m2vls.
Hope this helps!

Resources