80 lines
3.0 KiB
TypeScript
80 lines
3.0 KiB
TypeScript
/* eslint-disable react-hooks/exhaustive-deps */
|
|
import { AnimatePresence, motion } from "motion/react";
|
|
import { usePopupStore } from "../stores/usePopupStore";
|
|
import clsx from "clsx";
|
|
import Button from "./ui/Button";
|
|
import CloseIcon from "./icons/CloseIcon";
|
|
import { useEffect, useRef } from "react";
|
|
|
|
function PopupContainer() {
|
|
const { position, popup, side, setPopup, setSide } = usePopupStore();
|
|
|
|
const rootRef = useRef<HTMLDivElement>(null);
|
|
|
|
useEffect(() => {
|
|
if (!rootRef.current || !popup) return;
|
|
const { bottom, top, left, right } =
|
|
rootRef.current.getBoundingClientRect();
|
|
if (bottom > innerHeight - 32) setSide("top");
|
|
else if (top < 32) setSide("bottom");
|
|
else if (left < 32) setSide("right");
|
|
else if (right > innerWidth - 32) setSide("left");
|
|
}, [popup, position, rootRef.current]);
|
|
|
|
return (
|
|
<AnimatePresence>
|
|
{popup && (
|
|
<motion.div
|
|
ref={rootRef}
|
|
initial={{ opacity: 0 }}
|
|
animate={{ opacity: 1 }}
|
|
exit={{ opacity: 0 }}
|
|
transition={{ duration: 0.1 }}
|
|
style={
|
|
innerWidth >= 768
|
|
? { top: position.y, left: position.x }
|
|
: { bottom: 0, left: 0 }
|
|
}
|
|
className={clsx(
|
|
"fixed md:absolute 2xl:pointer-events-none z-2 2xl:rounded-[1.111vw] 2xl:p-[1.111vw] p-4 md:max-2xl:rounded-2xl rounded-t-2xl bg-white 2xl:w-[17.222vw] md:max-2xl:w-[248px] w-screen shadow-[0_2px_8px_0_rgba(0,0,0,0.15)]",
|
|
side === "left" &&
|
|
"md:-translate-y-1/2 2xl:-translate-x-[calc(100%+1.25vw)] md:max-2xl:-translate-x-[calc(100%+18px)]",
|
|
side === "right" && "md:-translate-y-1/2 2xl:translate-x-[1.25vw]",
|
|
side === "top" &&
|
|
"md:-translate-x-1/2 2xl:-translate-y-[calc(100%+1.25vw)] md:max-2xl:-translate-y-[calc(100%+18px)]",
|
|
side === "bottom" &&
|
|
"md:-translate-x-1/2 2xl:translate-y-[1.25vw] md:max-2xl:translate-y-[18px]"
|
|
)}
|
|
>
|
|
<Button
|
|
onlyIcon
|
|
variant="secondary"
|
|
size="small"
|
|
className="absolute md:hidden top-4 right-4 !bg-[#F3F3F2]"
|
|
onClick={() => setPopup(null)}
|
|
>
|
|
<span className="size-4">
|
|
<CloseIcon />
|
|
</span>
|
|
</Button>
|
|
{popup}
|
|
<div
|
|
className={clsx(
|
|
"max-md:hidden absolute 2xl:border-[0.556vw_0px_0.486vw_0.556vw] [border-width:8px_0px_7px_8px] [border-color:_transparent_transparent_transparent_#fff]",
|
|
side === "left" && "top-1/2 [y:-50%] left-full [x:1px]",
|
|
side === "right" &&
|
|
"top-1/2 [y:-50%] right-full [x:1px] [rotate:180deg]",
|
|
side === "top" &&
|
|
"left-1/2 [x:100%] top-full [y:1px] [rotate:90deg] origin-top-left",
|
|
side === "bottom" &&
|
|
"left-1/2 [x:100%] bottom-full [y:1px] [rotate:-90deg] origin-bottom-left"
|
|
)}
|
|
/>
|
|
</motion.div>
|
|
)}
|
|
</AnimatePresence>
|
|
);
|
|
}
|
|
|
|
export default PopupContainer;
|