import { useEffect, useMemo, useState } from "react"; import { limitNumber } from "../../libs/utils"; import { isMobile } from "../../libs/mobile"; import { putFab } from "../../libs/storage"; import { debounce } from "../../libs/utils"; import Paper from "@mui/material/Paper"; const getEdgePosition = ({ x: left, y: top, width, height, windowWidth, windowHeight, hover, }) => { const right = windowWidth - left - width; const bottom = windowHeight - top - height; const min = Math.min(left, top, right, bottom); switch (min) { case right: left = hover ? windowWidth - width : windowWidth - width / 2; break; case left: left = hover ? 0 : -width / 2; break; case bottom: top = hover ? windowHeight - height : windowHeight - height / 2; break; default: top = hover ? 0 : -height / 2; } return { x: left, y: top }; }; function DraggableWrapper({ children, usePaper, ...props }) { if (usePaper) { return ( {children} ); } return
{children}
; } export default function Draggable({ windowSize: { w: windowWidth, h: windowHeight }, width, height, left, top, show = true, snapEdge, onStart, onMove, handler, children, usePaper, }) { const [hover, setHover] = useState(false); const [origin, setOrigin] = useState(null); const [position, setPosition] = useState({ x: left, y: top }); const setFabPosition = useMemo(() => debounce(putFab, 500), []); const handlePointerDown = (e) => { !isMobile && e.target.setPointerCapture(e.pointerId); onStart && onStart(); const { x, y } = position; const { clientX, clientY } = isMobile ? e.targetTouches[0] : e; setOrigin({ x, y, clientX, clientY }); }; const handlePointerMove = (e) => { onMove && onMove(); const { clientX, clientY } = isMobile ? e.targetTouches[0] : e; if (origin) { const dx = clientX - origin.clientX; const dy = clientY - origin.clientY; let x = origin.x + dx; let y = origin.y + dy; x = limitNumber(x, -width / 2, windowWidth - width / 2); y = limitNumber(y, 0, windowHeight - height / 2); setPosition({ x, y }); } }; const handlePointerUp = (e) => { e.stopPropagation(); setOrigin(null); }; const handleClick = (e) => { e.stopPropagation(); }; const handleMouseEnter = (e) => { e.stopPropagation(); setHover(true); }; const handleMouseLeave = (e) => { e.stopPropagation(); setHover(false); }; useEffect(() => { if (!snapEdge || !!origin) { return; } setPosition((pre) => { const edgePosition = getEdgePosition({ ...pre, width, height, windowWidth, windowHeight, hover, }); setFabPosition(edgePosition); return edgePosition; }); }, [ origin, hover, width, height, windowWidth, windowHeight, snapEdge, setFabPosition, ]); const opacity = useMemo(() => { if (snapEdge) { return hover || origin ? 1 : 0.2; } return origin ? 0.8 : 1; }, [origin, snapEdge, hover]); const touchProps = isMobile ? { onTouchStart: handlePointerDown, onTouchMove: handlePointerMove, onTouchEnd: handlePointerUp, } : { onPointerDown: handlePointerDown, onPointerMove: handlePointerMove, onPointerUp: handlePointerUp, }; return (
{handler}
{children}
); }