diff --git a/lib/sticky/index.tsx b/lib/sticky/index.tsx new file mode 100644 index 0000000..220bd0c --- /dev/null +++ b/lib/sticky/index.tsx @@ -0,0 +1,100 @@ +"use client"; + +import { + FC, + MouseEventHandler, + PropsWithChildren, + useEffect, + useRef, + useState, +} from "react"; +import { Portal } from "../portal/components"; + +export const Sticky: FC< + PropsWithChildren<{ sidedness: 1 | -1; initialX?: number; initialY?: number }> +> = ( + { children, sidedness, initialX, initialY }, +) => { + const [position, setPosition] = useState({ + x: initialX ?? 10, + y: initialY ?? 10, + }); + const divRef = useRef(null); + const [dragging, setDragging] = useState(false); + const [offset, setOffset] = useState({ x: 0, y: 0 }); + + useEffect(() => { + const handleMouseMove = (e: MouseEvent) => { + if (dragging) { + setPosition({ + x: ((sidedness === -1 ? document.body.clientWidth : 0) - + (e.pageX - offset.x * sidedness)) * -sidedness, + y: e.pageY - offset.y, + }); + } + }; + + const handleMouseUp = () => { + if (dragging) { + setDragging(false); + } + }; + + if (dragging) { + document.addEventListener("mousemove", handleMouseMove); + document.addEventListener("mouseup", handleMouseUp); + } + + return () => { + document.removeEventListener("mousemove", handleMouseMove); + document.removeEventListener("mouseup", handleMouseUp); + }; + }, [dragging, offset, sidedness]); + + const handleMouseDown: MouseEventHandler = (e) => { + e.preventDefault(); + const rect = divRef.current!.getBoundingClientRect(); + const offsetX = e.pageX - rect.left; + const offsetY = e.pageY - rect.top; + setOffset({ x: offsetX, y: offsetY }); + setDragging(true); + }; + + return ( + +
+
+ + + + + + + + + + + + + + + +
+
{children}
+
+
+ ); +};