the-forest/client/src/components/SwipeableDrawer.jsx

115 lines
2.7 KiB
JavaScript

import { useState, useRef } from 'react';
import { Button, IconButton } from '@mui/material';
import MenuIcon from '@mui/icons-material/Menu';
import CloseIcon from '@mui/icons-material/Close';
import './SwipeableDrawer.css';
function SwipeableDrawer({children, anchor="right", hidden=true, className, ...props}) {
const [ open, setOpen ] = useState(!hidden);
const [ distance, setDistance ] = useState(0);
const [ origin, setOrigin ] = useState(0);
const [ inTouch, setInTouch ] = useState(false);
const swipeTargetRef = useRef(null);
function onTouchStart(e) {
setInTouch(true);
setOrigin(e.targetTouches[0].clientX);
}
function onTouchMove(e) {
setDistance(e.targetTouches[0].clientX - origin);
}
function onTouchEnd(e) {
let threshhold = 100;
if (swipeTargetRef.current) {
threshhold = swipeTargetRef.current.getBoundingClientRect().width * 0.5;
}
if (anchor == "right") {
if (distance < -threshhold) {
setOpen(true);
}
if (distance > threshhold) {
setOpen(false);
}
}
if (anchor == "left") {
if (distance > threshhold) {
setOpen(true);
}
if (distance < -threshhold) {
setOpen(false);
}
}
setOrigin(0);
setDistance(0);
setInTouch(false);
}
const dragStyle = {};
if (inTouch) {
dragStyle.transition = "none";
if (open) {
dragStyle.transform = `translateX(${distance}px)`;
} else {
if (anchor == "right") dragStyle.transform = `translateX(calc(30vw + ${distance}px))`;
if (anchor == "left") dragStyle.transform = `translateX(calc(-30vw + ${distance}px))`;
}
}
const drawerClosedClass = open ? "" : `drawerStyle-${anchor}-closed`;
return (<>
<div
ref={swipeTargetRef}
className={`swipeTargetStyle swipeTargetStyle-${anchor}`}
onTouchStart={onTouchStart}
onTouchMove={onTouchMove}
onTouchEnd={onTouchEnd}>
<IconButton
size="large"
variant="contained"
style={{
visible: open,
padding: "2rem",
position: "absolute",
right: anchor == "right" ? 0 : "auto",
left: anchor == "left" ? 0 : "auto",
top: 0
}}
onClick={() => setOpen(true)} >
<MenuIcon />
</IconButton>
</div>
<div
className={`drawerStyle drawerStyle-${anchor} ${drawerClosedClass} ${className}`}
style={dragStyle}
onTouchStart={onTouchStart}
onTouchMove={onTouchMove}
onTouchEnd={onTouchEnd}>
<IconButton
size="large"
variant="contained"
style={{
visible: open,
padding: "2rem",
position: "absolute",
right: anchor == "left" ? 0 : "auto",
left: anchor == "right" ? 0 : "auto",
top: 0
}}
onClick={() => setOpen(false)} >
<CloseIcon />
</IconButton>
{children}
</div>
</>);
}
export default SwipeableDrawer;