p-stream/src/components/popout/positions/FloatingCardMobilePosition.tsx
Yılmaz ÇABUK 4880d46dc4 style: sort imports according to ESLint rules
This commit updates the import statements in the codebase to comply with ESLint rules for import ordering. All imports have been sorted alphabetically and grouped according to the specified import groups in the ESLint configuration. This improves the codebase's consistency and maintainability.
2023-04-24 18:41:54 +03:00

103 lines
2.7 KiB
TypeScript

import { animated, config, useSpring } from "@react-spring/web";
import { useDrag } from "@use-gesture/react";
import { ReactNode, useEffect, useRef, useState } from "react";
interface MobilePositionProps {
children?: ReactNode;
className?: string;
onClose?: () => void;
}
export function FloatingCardMobilePosition(props: MobilePositionProps) {
const ref = useRef<HTMLDivElement>(null);
const closing = useRef<boolean>(false);
const [cardRect, setCardRect] = useState<DOMRect | null>(null);
const [{ y }, api] = useSpring(() => ({
y: 0,
onRest() {
if (!closing.current) return;
if (props.onClose) props.onClose();
},
}));
const bind = useDrag(
({
last,
velocity: [, vy],
direction: [, dy],
movement: [, my],
...event
}) => {
if (closing.current) return;
const isInScrollable = (event.target as HTMLDivElement).closest(
".overflow-y-auto"
);
if (isInScrollable) return; // Don't attempt to swipe the thing away if it's a scroll area unless the scroll area is at the top and the user is swiping down
const height = cardRect?.height ?? 0;
if (last) {
// if past half height downwards
// OR Y velocity is past 0.5 AND going down AND 20 pixels below start position
if (my > height * 0.5 || (vy > 0.5 && dy > 0 && my > 20)) {
api.start({
y: height * 1.2,
immediate: false,
config: { ...config.wobbly, velocity: vy, clamp: true },
});
closing.current = true;
} else {
api.start({
y: 0,
immediate: false,
config: config.wobbly,
});
}
} else {
api.start({ y: my, immediate: true });
}
},
{
from: () => [0, y.get()],
filterTaps: true,
bounds: { top: 0 },
rubberband: true,
}
);
useEffect(() => {
if (!ref.current) return;
function checkBox() {
const divRect = ref.current?.getBoundingClientRect();
setCardRect(divRect ?? null);
}
checkBox();
const observer = new ResizeObserver(checkBox);
observer.observe(ref.current);
return () => {
observer.disconnect();
};
}, []);
return (
<div
className="is-mobile-view absolute inset-x-0 mx-auto max-w-[400px] origin-bottom-left touch-none"
style={{
transform: `translateY(${
window.innerHeight - (cardRect?.height ?? 0) + 200
}px)`,
}}
>
<animated.div
ref={ref}
className={[props.className ?? "", "touch-none"].join(" ")}
style={{
y,
}}
{...bind()}
>
{props.children}
</animated.div>
</div>
);
}