Knob
more-shadcn-noair/knobFreeComponent
A theme-aware rotating dial for precise numeric adjustment.
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/knob.jsonSource
1<script lang="ts">2 import { cn } from '$UTILS$';34 let {5 value = $bindable(0),6 defaultValue,7 min = 0,8 max = 100,9 step = 1,10 label,11 size = 60,12 color = 'var(--primary)',13 disabled = false,14 class: className15 }: {16 value: number;17 defaultValue?: number;18 min?: number;19 max?: number;20 step?: number;21 label?: string;22 size?: number;23 color?: string;24 disabled?: boolean;25 class?: string;26 } = $props();2728 let isDragging = $state(false);29 let startY = $state(0);30 let startValue = $state(0);3132 let safeValue = $derived(Math.min(max, Math.max(min, value)));33 let progress = $derived((safeValue - min) / (max - min || 1));34 let rotation = $derived(progress * 270 - 135);3536 const circumference = 2 * Math.PI * 40;37 const arcLength = (270 / 360) * circumference;3839 function handleMouseMove(e: MouseEvent) {40 if (!isDragging || disabled) return;41 const diff = startY - e.clientY;42 const range = max - min;43 const sensitivity = 0.5;44 const newValue = Math.min(max, Math.max(min, startValue + (diff / size) * range * sensitivity));45 value = Math.round(newValue / step) * step;46 }4748 function handleMouseUp() {49 isDragging = false;50 window.removeEventListener('mousemove', handleMouseMove);51 window.removeEventListener('mouseup', handleMouseUp);52 }5354 function onMouseDown(e: MouseEvent) {55 if (disabled) return;56 isDragging = true;57 startY = e.clientY;58 startValue = value;59 window.addEventListener('mousemove', handleMouseMove);60 window.addEventListener('mouseup', handleMouseUp);61 }6263 function onDoubleClick() {64 if (disabled) return;65 value = defaultValue ?? min;66 }6768 function onTouchStart(e: TouchEvent) {69 if (disabled) return;70 isDragging = true;71 startY = e.touches[0].clientY;72 startValue = value;73 }7475 function onTouchMove(e: TouchEvent) {76 if (!isDragging || disabled) return;77 const diff = startY - e.touches[0].clientY;78 const range = max - min;79 const sensitivity = 0.5;80 const newValue = Math.min(max, Math.max(min, startValue + (diff / size) * range * sensitivity));81 value = Math.round(newValue / step) * step;82 }83</script>8485<div86 class={cn(87 'flex flex-col items-center gap-2 select-none',88 disabled && 'opacity-50 grayscale-[0.2]',89 className90 )}91>92 {#if label}93 <span class="text-[10px] font-bold uppercase tracking-widest text-muted-foreground">94 {label}95 </span>96 {/if}9798 <div99 role="slider"100 aria-valuemin={min}101 aria-valuemax={max}102 aria-valuenow={value}103 aria-disabled={disabled}104 class={cn(105// … 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 |
