Elastic Line
fancy/elastic-lineFreeComponent
A ui component.
Install it
npx shadcn@latest add https://www.fancycomponents.dev/r/elastic-line.jsonSource
1"use client"23import React, { useEffect, useRef, useState } from "react"4import {5 animate,6 motion,7 useAnimationFrame,8 useMotionValue,9 ValueAnimationTransition,10} from "motion/react"1112import { useDimensions } from "@/hooks/use-dimensions"13import { useElasticLineEvents } from "@/hooks/use-elastic-line-events"1415interface ElasticLineProps {16 isVertical?: boolean17 grabThreshold?: number18 releaseThreshold?: number19 strokeWidth?: number20 transition?: ValueAnimationTransition21 animateInTransition?: ValueAnimationTransition22 className?: string23}2425const ElasticLine: React.FC<ElasticLineProps> = ({26 isVertical = false,27 grabThreshold = 5,28 releaseThreshold = 100,29 strokeWidth = 1,30 transition = {31 type: "spring",32 stiffness: 300,33 damping: 5,34 },35 animateInTransition = {36 duration: 0.3,37 ease: "easeInOut",38 },39 className,40}) => {41 const containerRef = useRef<SVGSVGElement>(null)42 const dimensions = useDimensions(containerRef)43 const pathRef = useRef<SVGPathElement>(null)44 const [hasAnimatedIn, setHasAnimatedIn] = useState(false)4546 // Clamp releaseThreshold to container dimensions47 const clampedReleaseThreshold = Math.min(48 releaseThreshold,49 isVertical ? dimensions.width / 2 : dimensions.height / 250 )5152 const { isGrabbed, controlPoint } = useElasticLineEvents(53 containerRef,54 isVertical,55 grabThreshold,56 clampedReleaseThreshold57 )5859 const x = useMotionValue(dimensions.width / 2)60 const y = useMotionValue(dimensions.height / 2)61 const pathLength = useMotionValue(0)6263 useEffect(() => {64 // Initial draw animation65 if (!hasAnimatedIn && dimensions.width > 0 && dimensions.height > 0) {66 animate(pathLength, 1, {67 ...animateInTransition,68 onComplete: () => setHasAnimatedIn(true),69 })70 }71 x.set(dimensions.width / 2)72 y.set(dimensions.height / 2)73 }, [dimensions, hasAnimatedIn])7475 useEffect(() => {76 if (!isGrabbed && hasAnimatedIn) {77 animate(x, dimensions.width / 2, transition)78 animate(y, dimensions.height / 2, transition)79 }80 }, [isGrabbed])8182 useAnimationFrame(() => {83 if (isGrabbed) {84 x.set(controlPoint.x)85 y.set(controlPoint.y)86 }8788 const controlX = hasAnimatedIn ? x.get() : dimensions.width / 289 const controlY = hasAnimatedIn ? y.get() : dimensions.height / 29091 pathRef.current?.setAttribute(92 "d",93 isVertical94 ? `M${dimensions.width / 2} 0Q${controlX} ${controlY} ${95// … truncated
What it pulls in
npm packages
Other registry items
Files it writes
More from fancy
All 158 items| Component | Registry | Kind | Access | Installs | Command |
|---|---|---|---|---|---|
| Animated Gradient With Svganimated-gradient-with-svg | fancy | Components | Free | no deps | |
| Basic Number Tickerbasic-number-ticker | fancy | Components | Free | 1 dep | |
| Box Carouselbox-carousel | fancy | Components | Free | 1 dep | |
| Breathing Textbreathing-text | fancy | Components | Free | 1 dep | |
| Circling Elementscircling-elements | fancy | Components | Free | 1 dep | |
| Css Boxcss-box | fancy | Components | Free | 1 dep | |
| Cursor Attractor And Gravitycursor-attractor-and-gravity | fancy | Components | Free | 5 deps | |
| Drag Elementsdrag-elements | fancy | Components | Free | 1 dep |
