ElasticSlider
neon-ui/elastic-sliderFreeComponent
Slider with elastic rubber-band drag and magnetic snap (by @iamncdai, MIT).
Install it
npx shadcn@latest add https://ui.neon.com/r/elastic-slider.jsonSource
1/* oxlint-disable func-style, no-empty-function, no-shadow, no-use-before-define, react/react-compiler, max-lines-per-function, max-lines, no-magic-numbers -- vendored from chanhdai.com/r/elastic-slider.json (MIT, @iamncdai); kept diffable against upstream */2import {3 useCallback,4 useEffect,5 useLayoutEffect,6 useRef,7 useState,8} from "react"9import {10 animate,11 domAnimation,12 LazyMotion,13 m,14 useMotionValue,15 useReducedMotion,16 useTransform,17} from "motion/react"1819// LazyMotion + `m` instead of `motion` to avoid shipping the full animation20// graph (~30kb). (Neon UI patch on the vendored source.)2122import { cn } from "@/lib/utils"23import { useControllableState } from "@/hooks/use-controllable-state"2425// Drag detection & rubber band26const CLICK_THRESHOLD = 327const DEAD_ZONE = 3228const MAX_CURSOR_RANGE = 20029const MAX_STRETCH = 83031// Layout offsets used by the "handle dodges label/value" calculation.32const HANDLE_BUFFER = 833const LABEL_OFFSET = 12 + 434const VALUE_OFFSET = 12 - 83536function clamp(v: number, lo: number, hi: number) {37 return Math.max(lo, Math.min(hi, v))38}3940function decimalsForStep(step: number): number {41 const s = step.toString()42 const dot = s.indexOf(".")43 return dot === -1 ? 0 : s.length - dot - 144}4546function roundValue(val: number, step: number): number {47 const raw = Math.round(val / step) * step48 return parseFloat(raw.toFixed(decimalsForStep(step)))49}5051// Magnetic snap to the nearest decile when within 3.125% of it.52function snapToDecile(rawValue: number, min: number, max: number): number {53 const normalized = (rawValue - min) / (max - min)54 const nearest = Math.round(normalized * 10) / 1055 if (Math.abs(normalized - nearest) <= 0.03125) {56 return min + nearest * (max - min)57 }58 return rawValue59}6061export type ElasticSliderProps = {62 /** Label shown inside the track. */63 label: string6465 /** Controlled value. Use together with `onValueChange` */66 value?: number67 /** Initial value for uncontrolled mode. Falls back to `min` */68 defaultValue?: number69 /** Called with the new value on drag, click, or key press. */70 onValueChange?: (value: number) => void7172 /**73 * Minimum value.74 * @defaultValue 0 */75 min?: number76 /**77 * Maximum value.78 * @defaultValue 1 */79 max?: number80 /**81 * Smallest increment.82 * @defaultValue 0.01 */83 step?: number84 /** Format the displayed value. Defaults to `value.toFixed(...)` based on `step` */85 formatValue?: (value: number) => string8687 className?: string88// … truncated
What it pulls in
npm packages
Other registry items
Files it writes
More from neon-ui
All 77 items| Component | Registry | Kind | Access | Installs | Command |
|---|---|---|---|---|---|
| ActivityFeedactivity-feed | neon-ui | Components | Free | 2 deps | |
| AgentChatagent-chat | neon-ui | Components | Free | 6 deps | |
| AnimatedWashanimated-wash | neon-ui | Components | Free | no deps · 2 files | |
| ApiKeyListapi-key-list | neon-ui | Components | Free | 2 deps | |
| AppCardapp-card | neon-ui | Components | Free | 2 deps | |
| AppCreatorapp-creator | neon-ui | Components | Free | 2 deps | |
| AuthFormauth-form | neon-ui | Components | Free | no deps | |
| AutoscaleChartautoscale-chart | neon-ui | Components | Free | 1 dep |
