Scrubbable Input
more-shadcn-noair/scrubbableFreeComponent
A drag-to-adjust numeric input, similar to Blender or Unity.
Live preview
live · rendered by the registry
Rendered by more-shadcn-noair on their own page — this is the component running, not a screenshot of it.Install it
npx shadcn@latest add https://more-shadcn.noair.fun/r/scrubbable.jsonSource
1<script lang="ts">2 import { cn } from '$UTILS$';3 import { setScrubbableContext } from './ctx';4 import type { Snippet } from 'svelte';5 import { cva, type VariantProps } from 'class-variance-authority';67 const scrubbableVariants = cva(8 'group relative inline-flex items-center justify-between cursor-ew-resize select-none touch-none rounded-md px-3 py-1.5 text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50',9 {10 variants: {11 variant: {12 default: 'bg-muted text-foreground hover:bg-muted/80',13 primary: 'bg-primary text-primary-foreground hover:bg-primary/90',14 outline: 'border border-input bg-background hover:bg-accent hover:text-accent-foreground',15 secondary: 'bg-secondary text-secondary-foreground hover:bg-secondary/80',16 ghost: 'hover:bg-accent hover:text-accent-foreground'17 },18 size: {19 default: 'h-9',20 sm: 'h-8 px-2 text-xs',21 lg: 'h-10 px-4',22 icon: 'h-9 w-9 justify-center px-0'23 }24 },25 defaultVariants: {26 variant: 'default',27 size: 'default'28 }29 }30 );3132 type Props = VariantProps<typeof scrubbableVariants> & {33 value: number;34 min?: number;35 max?: number;36 step?: number;37 sensitivity?: number;38 defaultValue?: number;39 class?: string;40 onValueChange?: (v: number) => void;41 children: Snippet;42 };4344 let {45 value = $bindable(0),46 min = -Infinity,47 max = Infinity,48 step = 1,49 sensitivity = 2,50 defaultValue,51 variant,52 size,53 class: className,54 onValueChange,55 children56 }: Props = $props();5758 let isDragging = $state(false);59 let startX = 0;60 let startValue = 0;6162 function handleMouseDown(e: MouseEvent) {63 if (e.button !== 0) return;6465 isDragging = true;66 startX = e.clientX;67 startValue = value;6869 document.body.style.cursor = 'ew-resize';70 document.body.style.userSelect = 'none';7172 window.addEventListener('mousemove', handleMove);73 window.addEventListener('mouseup', handleUp);74 }7576 function handleMove(e: MouseEvent) {77 if (!isDragging) return;7879 const deltaX = e.clientX - startX;80 const isPrecision = e.shiftKey;8182 const dragScale = isPrecision ? 0.1 : 1;83 const change = (deltaX / sensitivity) * step * dragScale;8485 let newValue = startValue + change;8687 newValue = Math.max(min, Math.min(max, newValue));8889 if (!isPrecision) {90 newValue = Math.round(newValue / step) * step;91 }9293 const decimals = step.toString().split('.')[1]?.length || 0;94// … truncated
More from more-shadcn-noair
All 43 items| Component | Registry | Kind | Access | Installs | Command |
|---|---|---|---|---|---|
| Audioaudio | more-shadcn-noair | Components | Free | no deps | |
| Audio Waveaudio-wave | more-shadcn-noair | Components | Free | no deps | |
| Autocompleteautocomplete | more-shadcn-noair | Components | Free | no deps | |
| Bannerbanner | more-shadcn-noair | Components | Free | no deps | |
| Big Calendarbig-calendar | more-shadcn-noair | Components | Free | no deps | |
| Bottom Navigationbottom-nav | more-shadcn-noair | Components | Free | no deps | |
| Canvascanvas | more-shadcn-noair | Components | Free | no deps | |
| Chipchip | more-shadcn-noair | Components | Free | no deps |
