A small web app for watching movies and shows easily
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

91 lines
2.4 KiB

import { useSpring, animated, config } 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] }) => {
if (closing.current) return;
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="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>
);
}