Elastic Slider
ncdai/elastic-sliderUnverifiedComponent
Slider with elastic rubber-band drag and magnetic snap feedback.
Install it
npx shadcn@latest add https://raw.githubusercontent.com/exekartik/exeKartik/main/elastic-slider.jsonSource
1"use client"23import {4 useCallback,5 useEffect,6 useLayoutEffect,7 useRef,8 useState,9} from "react"10import {11 animate,12 motion,13 useMotionValue,14 useReducedMotion,15 useTransform,16} from "motion/react"1718import { cn } from "@/lib/utils"19import { useControllableState } from "@/registry/hooks/use-controllable-state"2021// Drag detection & rubber band22const CLICK_THRESHOLD = 323const DEAD_ZONE = 3224const MAX_CURSOR_RANGE = 20025const MAX_STRETCH = 82627// Layout offsets used by the "handle dodges label/value" calculation.28const HANDLE_BUFFER = 829const LABEL_OFFSET = 12 + 430const VALUE_OFFSET = 12 - 83132function clamp(v: number, lo: number, hi: number) {33 return Math.max(lo, Math.min(hi, v))34}3536function decimalsForStep(step: number): number {37 const s = step.toString()38 const dot = s.indexOf(".")39 return dot === -1 ? 0 : s.length - dot - 140}4142function roundValue(val: number, step: number): number {43 const raw = Math.round(val / step) * step44 return parseFloat(raw.toFixed(decimalsForStep(step)))45}4647// Magnetic snap to the nearest decile when within 3.125% of it.48function snapToDecile(rawValue: number, min: number, max: number): number {49 const normalized = (rawValue - min) / (max - min)50 const nearest = Math.round(normalized * 10) / 1051 if (Math.abs(normalized - nearest) <= 0.03125) {52 return min + nearest * (max - min)53 }54 return rawValue55}5657export type ElasticSliderProps = {58 /** Label shown inside the track. */59 label: string6061 /** Controlled value. Use together with `onValueChange` */62 value?: number63 /** Initial value for uncontrolled mode. Falls back to `min` */64 defaultValue?: number65 /** Called with the new value on drag, click, or key press. */66 onValueChange?: (value: number) => void6768 /**69 * Minimum value.70 * @defaultValue 0 */71 min?: number72 /**73 * Maximum value.74 * @defaultValue 1 */75 max?: number76 /**77 * Smallest increment.78 * @defaultValue 0.01 */79 step?: number80 /** Format the displayed value. Defaults to `value.toFixed(...)` based on `step` */81 formatValue?: (value: number) => string8283 className?: string84 /** Accessible name. Falls back to `label` */85 "aria-label"?: string86}8788export function ElasticSlider({89 label,9091 value: valueProp,92 defaultValue,93 onValueChange,9495 min = 0,96 max = 1,97 step = 0.01,98 formatValue,99100 className,101 "aria-label": ariaLabel,102}: ElasticSliderProps) {103 const [value = min, setValue] = useControllableState({104 prop: valueProp,105// … truncated
What it pulls in
npm packages
Other registry items
Files it writes
More from ncdai
All 17 items| Component | Registry | Kind | Access | Installs | Command |
|---|---|---|---|---|---|
| Apple Hello Effectapple-hello-effect | ncdai | Components | Unverified | 1 dep | |
| Apple Hello Effect - Hindiapple-hello-effect-hindi | ncdai | Components | Unverified | 1 dep | |
| Apple Hello Effect - Spanishapple-hello-effect-spanish | ncdai | Components | Unverified | 1 dep | |
| Apple Hello Effect - Vietnameseapple-hello-effect-vietnamese | ncdai | Components | Unverified | 1 dep | |
| Brand Assets Menubrand-assets-menu | ncdai | Components | Unverified | 1 dep | |
| chevrons-up-down-iconchevrons-up-down-icon | ncdai | Components | Unverified | 1 dep | |
| Code Block Commandcode-block-command | ncdai | Components | Unverified | 4 deps · 3 files | |
| Consent Managerconsent-manager | ncdai | Components | Unverified | 1 dep · 2 files |
