{ "$schema": "https://ui.shadcn.com/schema/registry-item.json", "name": "slide-to-unlock", "type": "registry:component", "title": "Slide to Unlock", "author": "ncdai ", "description": "A sleek, interactive slider inspired by the classic iPhone OS 'slide to unlock' gesture.", "dependencies": [ "motion" ], "registryDependencies": [ "@ncdai/utils", "@ncdai/shimmering-text" ], "files": [ { "path": "src/registry/slide-to-unlock/slide-to-unlock.tsx", "content": "\"use client\";\n\nimport {\n animate,\n motion,\n type MotionValue,\n useMotionValue,\n useTransform,\n} from \"motion/react\";\nimport {\n type ComponentPropsWithoutRef,\n createContext,\n useCallback,\n useContext,\n useRef,\n useState,\n} from \"react\";\n\nimport { cn } from \"@/lib/utils\";\n\ntype SlideToUnlockContextValue = {\n x: MotionValue;\n trackRef: React.RefObject;\n isDragging: boolean;\n handleWidth: number;\n textOpacity: MotionValue;\n onDragStart: () => void;\n onDragEnd: () => void;\n};\n\nconst SlideToUnlockContext = createContext(\n null\n);\n\nfunction useSlideToUnlock() {\n const context = useContext(SlideToUnlockContext);\n if (!context) {\n throw new Error(\n `SlideToUnlock components must be used within SlideToUnlock`\n );\n }\n return context;\n}\n\nexport type SlideToUnlockRootProps = React.ComponentProps<\"div\"> & {\n handleWidth?: number;\n onUnlock?: () => void;\n};\n\nexport function SlideToUnlock({\n className,\n handleWidth = 56,\n children,\n onUnlock,\n ...props\n}: SlideToUnlockRootProps) {\n const trackRef = useRef(null);\n const [isDragging, setIsDragging] = useState(false);\n const x = useMotionValue(0);\n\n const fadeDistance = handleWidth;\n const textOpacity = useTransform(x, [0, fadeDistance], [1, 0]);\n\n const handleDragStart = useCallback(() => {\n setIsDragging(true);\n }, []);\n\n const handleDragEnd = useCallback(() => {\n setIsDragging(false);\n\n const trackWidth = trackRef.current?.offsetWidth || 0;\n const maxX = trackWidth - handleWidth;\n\n if (x.get() >= maxX) {\n onUnlock?.();\n } else {\n animate(x, 0, { type: \"spring\", bounce: 0, duration: 0.25 });\n }\n }, [x, onUnlock, handleWidth]);\n\n return (\n \n \n {children}\n \n \n );\n}\n\nexport type SlideToUnlockTrackProps = React.ComponentProps<\"div\">;\n\nexport function SlideToUnlockTrack({\n className,\n children,\n ...props\n}: SlideToUnlockTrackProps) {\n const { trackRef } = useSlideToUnlock();\n\n return (\n \n {children}\n \n );\n}\n\nexport type SlideToUnlockTextProps = Omit<\n ComponentPropsWithoutRef,\n \"children\"\n> & {\n children:\n | React.ReactNode\n | ((props: { isDragging: boolean }) => React.ReactNode);\n};\n\nexport function SlideToUnlockText({\n className,\n children,\n style,\n ...props\n}: SlideToUnlockTextProps) {\n const { handleWidth, textOpacity, isDragging } = useSlideToUnlock();\n\n return (\n \n {typeof children === \"function\" ? children({ isDragging }) : children}\n \n );\n}\n\nexport type SlideToUnlockHandleProps = ComponentPropsWithoutRef<\n typeof motion.div\n>;\n\nexport function SlideToUnlockHandle({\n className,\n children,\n style,\n ...props\n}: SlideToUnlockHandleProps) {\n const {\n x,\n trackRef,\n onDragStart,\n onDragEnd,\n handleWidth: width,\n } = useSlideToUnlock();\n\n return (\n \n {children ?? (\n \n \n \n )}\n \n );\n}\n", "type": "registry:component" } ], "docs": "https://chanhdai.com/components/slide-to-unlock" }