I have a function that changes the isOpen state when the user scrolls the mouse wheel, I need to make content that is initially behind the right side of the screen and looks out a little from there, and when isOpen=true – then in the center of the screen
I already have a working function responsible for changing the isOpen state
const [isOpen, setIsOpen] = useState(false);
const handleWheel = (event: WheelEvent) => {
if (event.deltaY > 0) {
setIsOpen(true);
} else {
setIsOpen(false);
}
};
window.addEventListener("wheel", handleWheel);
return () => {
window.removeEventListener("load", handleLoad);
window.removeEventListener("wheel", handleWheel);
};
And content that should be animated
<motion.div layout transition={{
layout: {
duration: 0.1,
},
}}
>
<motion.div
layout
className={`${
isOpen
? "flex justify-center"
: "absolute right-1"
} h-screen`}
>
<div className="fixed flex-col -rotate-90 z-10 text-center">
content
</div>
</motion.div>
</motion.div>
Animation occurs only to exit the item from the right side of the screen, and back to the right side of the screen without animation (also center the content vertically regardless of isOpen)
If I understand correctly, what you need should be the code below:
function App() {
const { motion } = Motion;
const { useState, useEffect } = React;
const [isOpen, setIsOpen] = useState(false);
useEffect(() => {
const handleWheel = (event: WheelEvent) => {
if (event.deltaY > 0) {
setIsOpen(true);
} else {
setIsOpen(false);
}
};
window.addEventListener("wheel", handleWheel);
return () => {
window.removeEventListener("wheel", handleWheel);
};
}, []);
return (
<div className="overflow-hidden">
<motion.div
className="relative h-dvh"
transition={{ bounce: 0, duration: 0.25 }}
initial={{ x: "100%" }}
animate={
isOpen ? { x: "0%" } : { x: "100%", transition: { duration: 0 } }
}
exit={{ x: "100%" }}
>
<div className="absolute left-0 top-full h-[100vw] w-[100dvh] origin-top-left -rotate-90 bg-amber-200">
<article className="flex h-full items-center justify-center">
content
</article>
</div>
</motion.div>
</div>
);
}
ReactDOM.createRoot(document.getElementById('app')).render(<App/>);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.3.1/umd/react.production.min.js" integrity="sha512-QVs8Lo43F9lSuBykadDb0oSXDL/BbZ588urWVCRwSIoewQv/Ewg1f84mK3U790bZ0FfhFa1YSQUmIhG+pIRKeg==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.3.1/umd/react-dom.production.min.js" integrity="sha512-6a1107rTlA4gYpgHAqbwLAtxmWipBdJFcq8y5S/aTge3Bp+VAklABm2LO+Kg51vOWR9JMZq1Ovjl5tpluNpTeQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script src="https://cdn.tailwindcss.com"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/framer-motion.min.js"></script>
<div id="app"></div>
(👆Run the code snippet and scroll the mouse wheel to see the popup content.)
A few key points:
- In React, use
useEffect
to subscribe and unsubscribe from events for better event management. - Set the popup height to
100vw
and the width to100dvh
, combined with absolute positioning, to ensure that the content doesn’t overflow the viewport after a 90° rotation. - If you want to avoid transitions when closing, you can cancel the animation by setting the
duration
of the closing animation to 0. ({ x: "100%", transition: { duration: 0 } }
)
2