{
	"$schema": "https://shadcn-svelte.com/schema/registry-item.json",
	"name": "knob",
	"title": "Knob",
	"type": "registry:ui",
	"description": "A theme-aware rotating dial for precise numeric adjustment.",
	"files": [
		{
			"content": "<script lang=\"ts\">\n\timport { cn } from '$UTILS$';\n\n\tlet {\n\t\tvalue = $bindable(0),\n\t\tdefaultValue,\n\t\tmin = 0,\n\t\tmax = 100,\n\t\tstep = 1,\n\t\tlabel,\n\t\tsize = 60,\n\t\tcolor = 'var(--primary)',\n\t\tdisabled = false,\n\t\tclass: className\n\t}: {\n\t\tvalue: number;\n\t\tdefaultValue?: number;\n\t\tmin?: number;\n\t\tmax?: number;\n\t\tstep?: number;\n\t\tlabel?: string;\n\t\tsize?: number;\n\t\tcolor?: string;\n\t\tdisabled?: boolean;\n\t\tclass?: string;\n\t} = $props();\n\n\tlet isDragging = $state(false);\n\tlet startY = $state(0);\n\tlet startValue = $state(0);\n\n\tlet safeValue = $derived(Math.min(max, Math.max(min, value)));\n\tlet progress = $derived((safeValue - min) / (max - min || 1));\n\tlet rotation = $derived(progress * 270 - 135);\n\n\tconst circumference = 2 * Math.PI * 40;\n\tconst arcLength = (270 / 360) * circumference;\n\n\tfunction handleMouseMove(e: MouseEvent) {\n\t\tif (!isDragging || disabled) return;\n\t\tconst diff = startY - e.clientY;\n\t\tconst range = max - min;\n\t\tconst sensitivity = 0.5;\n\t\tconst newValue = Math.min(max, Math.max(min, startValue + (diff / size) * range * sensitivity));\n\t\tvalue = Math.round(newValue / step) * step;\n\t}\n\n\tfunction handleMouseUp() {\n\t\tisDragging = false;\n\t\twindow.removeEventListener('mousemove', handleMouseMove);\n\t\twindow.removeEventListener('mouseup', handleMouseUp);\n\t}\n\n\tfunction onMouseDown(e: MouseEvent) {\n\t\tif (disabled) return;\n\t\tisDragging = true;\n\t\tstartY = e.clientY;\n\t\tstartValue = value;\n\t\twindow.addEventListener('mousemove', handleMouseMove);\n\t\twindow.addEventListener('mouseup', handleMouseUp);\n\t}\n\n\tfunction onDoubleClick() {\n\t\tif (disabled) return;\n\t\tvalue = defaultValue ?? min;\n\t}\n\n\tfunction onTouchStart(e: TouchEvent) {\n\t\tif (disabled) return;\n\t\tisDragging = true;\n\t\tstartY = e.touches[0].clientY;\n\t\tstartValue = value;\n\t}\n\n\tfunction onTouchMove(e: TouchEvent) {\n\t\tif (!isDragging || disabled) return;\n\t\tconst diff = startY - e.touches[0].clientY;\n\t\tconst range = max - min;\n\t\tconst sensitivity = 0.5;\n\t\tconst newValue = Math.min(max, Math.max(min, startValue + (diff / size) * range * sensitivity));\n\t\tvalue = Math.round(newValue / step) * step;\n\t}\n</script>\n\n<div\n\tclass={cn(\n\t\t'flex flex-col items-center gap-2 select-none',\n\t\tdisabled && 'opacity-50 grayscale-[0.2]',\n\t\tclassName\n\t)}\n>\n\t{#if label}\n\t\t<span class=\"text-[10px] font-bold uppercase tracking-widest text-muted-foreground\">\n\t\t\t{label}\n\t\t</span>\n\t{/if}\n\n\t<div\n\t\trole=\"slider\"\n\t\taria-valuemin={min}\n\t\taria-valuemax={max}\n\t\taria-valuenow={value}\n\t\taria-disabled={disabled}\n\t\tclass={cn(\n\t\t\t'relative flex items-center justify-center rounded-full',\n\t\t\tdisabled ? 'cursor-not-allowed' : 'cursor-ns-resize'\n\t\t)}\n\t\tstyle=\"width: {size}px; height: {size}px;\"\n\t\tonmousedown={onMouseDown}\n\t\tondblclick={onDoubleClick}\n\t\tontouchstart={onTouchStart}\n\t\tontouchmove={onTouchMove}\n\t\tontouchend={() => (isDragging = false)}\n\t>\n\t\t<svg class=\"absolute inset-0 h-full w-full\" viewBox=\"0 0 100 100\">\n\t\t\t<circle\n\t\t\t\tcx=\"50\"\n\t\t\t\tcy=\"50\"\n\t\t\t\tr=\"40\"\n\t\t\t\tfill=\"none\"\n\t\t\t\tstroke=\"currentColor\"\n\t\t\t\tstroke-width=\"8\"\n\t\t\t\tclass=\"text-muted/20\"\n\t\t\t\tstroke-dasharray=\"{arcLength} {circumference}\"\n\t\t\t\tstroke-linecap=\"round\"\n\t\t\t\tstyle=\"transform: rotate(135deg); transform-origin: 50% 50%;\"\n\t\t\t/>\n\t\t\t<circle\n\t\t\t\tcx=\"50\"\n\t\t\t\tcy=\"50\"\n\t\t\t\tr=\"40\"\n\t\t\t\tfill=\"none\"\n\t\t\t\tstroke={color}\n\t\t\t\tstroke-width=\"8\"\n\t\t\t\tstroke-dasharray=\"{progress * arcLength} {circumference}\"\n\t\t\t\tstroke-linecap=\"round\"\n\t\t\t\tstyle=\"transform: rotate(135deg); transform-origin: 50% 50%;\"\n\t\t\t/>\n\t\t</svg>\n\n\t\t<div\n\t\t\tclass=\"relative flex items-center justify-center rounded-full border bg-secondary\"\n\t\t\tstyle=\"width: {size * 0.65}px; height: {size * 0.65}px; transform: rotate({rotation}deg);\"\n\t\t>\n\t\t\t<div\n\t\t\t\tclass=\"mt-1 mb-auto h-[35%] w-1 rounded-full opacity-90 transition-colors\"\n\t\t\t\tstyle=\"background-color: {color};\"\n\t\t\t></div>\n\t\t</div>\n\t</div>\n\n\t<span class=\"font-mono text-xs font-medium tracking-tighter text-foreground\">\n\t\t{value}\n\t</span>\n</div>\n",
			"type": "registry:ui",
			"target": "knob/knob.svelte"
		},
		{
			"content": "import Knob from './knob.svelte';\nexport { Knob };\n",
			"type": "registry:ui",
			"target": "knob/index.ts"
		}
	]
}