"use client" import React, { useState, useRef, useEffect } from "react" import { motion, useMotionValue, useTransform, animate, PanInfo } from "framer-motion" import { cn } from "../../lib/utils" export interface GestureDrawerProps { children: React.ReactNode isOpen: boolean onOpenChange: (open: boolean) => void direction?: "up" | "down" | "left" | "right" threshold?: number className?: string overlayClassName?: string enableSwipeToClose?: boolean } export const GestureDrawer = React.forwardRef( ({ children, isOpen, onOpenChange, direction = "up", threshold = 50, className, overlayClassName, enableSwipeToClose = true, ...props }, ref) => { const y = useMotionValue(0) const x = useMotionValue(0) const isVertical = direction === "up" || direction === "down" const motionValue = isVertical ? y : x const opacity = useTransform(motionValue, [0, threshold], [1, 0.5]) const handleDragEnd = (event: any, info: PanInfo) => { if (!enableSwipeToClose) return const offset = isVertical ? info.offset.y : info.offset.x const velocity = isVertical ? info.velocity.y : info.velocity.x let shouldClose = false switch (direction) { case "up": shouldClose = offset > threshold || velocity > 500 break case "down": shouldClose = offset < -threshold || velocity < -500 break case "left": shouldClose = offset > threshold || velocity > 500 break case "right": shouldClose = offset < -threshold || velocity < -500 break } if (shouldClose) { onOpenChange(false) } else { animate(motionValue, 0, { type: "spring", stiffness: 300, damping: 20 }) } } const getInitialPosition = () => { switch (direction) { case "up": return { y: "100%" } case "down": return { y: "-100%" } case "left": return { x: "100%" } case "right": return { x: "-100%" } default: return { y: "100%" } } } const getAnimatePosition = () => { return isVertical ? { y: 0 } : { x: 0 } } if (!isOpen) return null return (
{/* Overlay */} onOpenChange(false)} className={cn("absolute inset-0 bg-black/50", overlayClassName)} /> {/* Drawer */} {/* Drag Handle */} {(direction === "up" || direction === "down") && (
)} {children}
) } ) GestureDrawer.displayName = "GestureDrawer"