diff --git a/src/views/Action/Draggable.js b/src/views/Action/Draggable.js index 696e7e7..7fc955f 100644 --- a/src/views/Action/Draggable.js +++ b/src/views/Action/Draggable.js @@ -1,35 +1,58 @@ -import { useEffect, useMemo, useState } from "react"; +import { useCallback, useEffect, useMemo, useState } from "react"; import { limitNumber } from "../../libs/utils"; import { isMobile } from "../../libs/mobile"; -const getSidePosition = ( +const getEdgePosition = ( + { x: left, y: top, edge }, windowWidth, windowHeight, width, - height, - left, - top + height ) => { - const right = Math.abs(windowWidth - left - width); - const bottom = Math.abs(windowHeight - top - height); - left = Math.abs(left); - top = Math.abs(top); + const right = windowWidth - left - width; + const bottom = windowHeight - top - height; const min = Math.min(left, top, right, bottom); switch (min) { case right: - left = windowWidth - width / 2; + edge = "right"; + left = windowWidth - width; break; case left: - left = -width / 2; + edge = "left"; + left = 0; break; case bottom: + edge = "bottom"; + top = windowHeight - height; + break; + default: + edge = "top"; + top = 0; + } + return { x: left, y: top, edge, hide: false }; +}; + +const getHidePosition = ( + { x: left, y: top, edge }, + windowWidth, + windowHeight, + width, + height +) => { + switch (edge) { + case "right": + left = windowWidth - width / 2; + break; + case "left": + left = -width / 2; + break; + case "bottom": top = windowHeight - height / 2; break; - default: top = -height / 2; } - return { x: left, y: top }; + return { x: left, y: top, edge, hide: true }; }; export default function Draggable({ @@ -39,21 +62,46 @@ export default function Draggable({ left, top, show, - goside, + snapEdge, onStart, onMove, handler, children, }) { - const [origin, setOrigin] = useState(goside ? {} : null); + const [origin, setOrigin] = useState({ + x: left, + y: top, + px: left, + py: top, + }); const [position, setPosition] = useState({ x: left, y: top, + edge: null, + hide: false, }); + const [edgeTimer, setEdgeTimer] = useState(null); + + const goEdge = useCallback(() => { + console.log("goEdge"); + setPosition((pre) => + getEdgePosition(pre, windowSize.w, windowSize.h, width, height) + ); + + setEdgeTimer( + setTimeout(() => { + console.log("goHide"); + setPosition((pre) => + getHidePosition(pre, windowSize.w, windowSize.h, width, height) + ); + }, 2000) + ); + }, [windowSize.w, windowSize.h, width, height]); const handlePointerDown = (e) => { !isMobile && e.target.setPointerCapture(e.pointerId); onStart && onStart(); + edgeTimer && clearTimeout(edgeTimer); const { clientX, clientY } = isMobile ? e.targetTouches[0] : e; setOrigin({ x: position.x, @@ -72,26 +120,48 @@ export default function Draggable({ let x = origin.x + dx; let y = origin.y + dy; const { w, h } = windowSize; - x = limitNumber(x, -width / 2, w - width / 2); - y = limitNumber(y, -height / 2, h - height / 2); - setPosition({ x, y }); + x = limitNumber(x, 0, w - width); + y = limitNumber(y, 0, h - height); + setPosition({ x, y, edge: null, hide: false }); } }; const handlePointerUp = (e) => { + e.stopPropagation(); setOrigin(null); - if (!goside) { + if (!snapEdge) { return; } - setPosition((pre) => - getSidePosition(windowSize.w, windowSize.h, width, height, pre.x, pre.y) - ); + goEdge(); }; const handleClick = (e) => { e.stopPropagation(); }; + const handleMouseEnter = (e) => { + e.stopPropagation(); + if (snapEdge && position.hide) { + edgeTimer && clearTimeout(edgeTimer); + goEdge(); + } + }; + + useEffect(() => { + setOrigin(null); + if (!snapEdge) { + return; + } + goEdge(); + }, [snapEdge, goEdge]); + + const opacity = useMemo(() => { + if (snapEdge) { + return position.hide ? 0.1 : 1; + } + return origin ? 0.8 : 1; + }, [origin, snapEdge, position.hide]); + const touchProps = isMobile ? { onTouchStart: handlePointerDown, @@ -104,23 +174,6 @@ export default function Draggable({ onPointerUp: handlePointerUp, }; - useEffect(() => { - setOrigin(null); - if (!goside) { - return; - } - setPosition((pre) => - getSidePosition(windowSize.w, windowSize.h, width, height, pre.x, pre.y) - ); - }, [goside, windowSize.w, windowSize.h, width, height]); - - const opacity = useMemo(() => { - if (goside) { - return origin ? 1 : 0.3; - } - return origin ? 0.7 : 1; - }, [origin, goside]); - return (
{ setWindowSize({ - w: window.innerWidth, - h: window.innerHeight, + w: document.documentElement.clientWidth, + h: document.documentElement.clientHeight, }); }; @@ -67,8 +67,8 @@ export default function Action({ translator }) { windowSize, width: fabWidth, height: fabWidth, - left: window.innerWidth - fabWidth, - top: window.innerHeight / 2, + left: windowSize.w - fabWidth, + top: windowSize.h / 2, }; return ( @@ -108,13 +108,14 @@ export default function Action({ translator }) { { if (!moved) {