optimize fab

This commit is contained in:
Gabe Yuan
2023-08-16 17:36:22 +08:00
parent f1f15c7eb1
commit 21fcc11ac1
2 changed files with 102 additions and 50 deletions

View File

@@ -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

View File

@@ -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) {