optimize fab
This commit is contained in:
@@ -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 (
|
||||
<div
|
||||
style={{
|
||||
@@ -130,10 +183,8 @@ export default function Draggable({
|
||||
top: position.y,
|
||||
zIndex: 2147483647,
|
||||
display: show ? "block" : "none",
|
||||
transitionProperty: origin ? "none" : "all",
|
||||
transitionDuration: "0.5s",
|
||||
transitionDelay: "0.5s",
|
||||
}}
|
||||
onMouseEnter={handleMouseEnter}
|
||||
onClick={handleClick}
|
||||
>
|
||||
<div
|
||||
|
||||
@@ -12,18 +12,18 @@ import { StoragesProvider } from "../../hooks/Storage";
|
||||
import Popup from "../Popup";
|
||||
|
||||
export default function Action({ translator }) {
|
||||
const fabWidth = 56;
|
||||
const fabWidth = 40;
|
||||
const [showPopup, setShowPopup] = useState(false);
|
||||
const [windowSize, setWindowSize] = useState({
|
||||
w: window.innerWidth,
|
||||
h: window.innerHeight,
|
||||
w: document.documentElement.clientWidth,
|
||||
h: document.documentElement.clientHeight,
|
||||
});
|
||||
const [moved, setMoved] = useState(false);
|
||||
|
||||
const handleWindowResize = (e) => {
|
||||
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 }) {
|
||||
</Draggable>
|
||||
<Draggable
|
||||
key="fab"
|
||||
goside
|
||||
snapEdge
|
||||
{...fabProps}
|
||||
show={!showPopup}
|
||||
onStart={handleStart}
|
||||
onMove={handleMove}
|
||||
handler={
|
||||
<Fab
|
||||
size="small"
|
||||
color="primary"
|
||||
onClick={(e) => {
|
||||
if (!moved) {
|
||||
|
||||
Reference in New Issue
Block a user