Files
stream.graff.tech-new/client/src/components/PopupWrapper.tsx
T

123 lines
3.6 KiB
TypeScript

/* eslint-disable react-hooks/exhaustive-deps */
import clsx from "clsx";
import PopupHeader from "./PopupHeader";
import { useEffect, useState } from "react";
import { useRef } from "react";
import usePopupStore from "../store/popupStore";
interface PopupWrapperProps {
children: React.ReactNode;
className?: string;
title?: string;
leftButton?: React.ReactNode;
draggable?: boolean;
}
function PopupWrapper({
children,
className,
title,
leftButton,
draggable,
}: PopupWrapperProps) {
const { position, setPosition } = usePopupStore();
const [mouseDown, setMouseDown] = useState(false);
const [mouseDownPosition, setMouseDownPosition] = useState(position);
const wrapperRef = useRef<HTMLDivElement>(null);
const headerRef = useRef<HTMLDivElement>(null);
useEffect(() => {
addEventListener("mouseup", () => setMouseDown(false));
addEventListener("touchend", () => setMouseDown(false));
return () => {
removeEventListener("mouseup", () => setMouseDown(false));
removeEventListener("touchend", () => setMouseDown(false));
};
}, []);
function handleMove(e: MouseEvent | TouchEvent) {
if (draggable && mouseDown && wrapperRef.current) {
e.preventDefault();
const x = "clientX" in e ? e.clientX : e.touches[0].clientX;
const y = "clientY" in e ? e.clientY : e.touches[0].clientY;
setPosition({
x: Math.min(
Math.max(0, position.x + x - mouseDownPosition.x),
innerWidth - wrapperRef.current.clientWidth
),
y: Math.min(
Math.max(0, position.y + y - mouseDownPosition.y),
innerHeight - wrapperRef.current.clientHeight
),
});
setMouseDownPosition({ x, y });
}
}
useEffect(() => {
addEventListener("mousemove", handleMove);
addEventListener("touchmove", handleMove);
return () => {
removeEventListener("mousemove", handleMove);
removeEventListener("touchmove", handleMove);
};
}, [handleMove]);
useEffect(() => {
if (headerRef.current) {
headerRef.current.addEventListener("mousedown", (e) => {
setMouseDown(true);
setMouseDownPosition({ x: e.clientX, y: e.clientY });
});
headerRef.current.addEventListener("touchstart", (e) => {
setMouseDown(true);
setMouseDownPosition({
x: e.touches[0].clientX,
y: e.touches[0].clientY,
});
});
}
return () => {
if (headerRef.current) {
headerRef.current.removeEventListener("mousedown", (e) => {
setMouseDown(true);
setMouseDownPosition({ x: e.clientX, y: e.clientY });
});
headerRef.current.removeEventListener("touchstart", (e) => {
setMouseDown(true);
setMouseDownPosition({
x: e.touches[0].clientX,
y: e.touches[0].clientY,
});
});
}
};
}, []);
return (
<div
ref={wrapperRef}
className={clsx(
"2xl:rounded-[2.222vw] relative bg-white shadow-[0_4px_40px_0_rgba(15,16,17,0.1)] 2xl:w-[21.667vw] sm:rounded-[32px] max-sm:w-screen max-sm:rounded-t-[32px]",
className
)}
>
{/* Полоска-ручка для свайпа на мобильных */}
<div className="hidden max-sm:flex justify-center pt-1 pb-1 absolute -top-3 left-1/2 -translate-x-1/2">
<div className="w-8 h-1 bg-[#141414] rounded-full opacity-50" />
</div>
<PopupHeader
headerRef={headerRef}
title={title}
leftButton={leftButton}
draggable={draggable}
/>
<div className="2xl:p-[1.389vw] p-5">{children}</div>
</div>
);
}
export default PopupWrapper;