{
	"$schema": "https://shadcn-svelte.com/schema/registry-item.json",
	"name": "verify-human",
	"title": "Hold Button",
	"type": "registry:ui",
	"description": "A self-contained heuristic bot protection component. It uses honeypots, velocity checks, and event trust analysis.",
	"dependencies": [
		"@lucide/svelte@^0.554.0"
	],
	"devDependencies": [
		"@lucide/svelte@^0.544.0"
	],
	"files": [
		{
			"content": "<script lang=\"ts\">\r\n\timport { cn } from '$UTILS$';\r\n\timport { Check, Loader2, ShieldCheck, X } from '@lucide/svelte';\r\n\timport { onMount } from 'svelte';\r\n\r\n\tlet {\r\n\t\tclass: className,\r\n\t\tonVerify,\r\n\t\tverified = $bindable(false)\r\n\t}: {\r\n\t\tclass?: string;\r\n\t\tonVerify?: () => void;\r\n\t\tverified?: boolean;\r\n\t} = $props();\r\n\r\n\tlet status = $state<'idle' | 'verifying' | 'verified' | 'failed'>('idle');\r\n\tlet mountTime = 0;\r\n\tlet humanInteraction = false;\r\n\tlet honeypot = $state(false);\r\n\r\n\tonMount(() => {\r\n\t\tmountTime = Date.now();\r\n\r\n\t\tconst markHuman = () => {\r\n\t\t\thumanInteraction = true;\r\n\t\t};\r\n\t\twindow.addEventListener('mousemove', markHuman, { once: true });\r\n\t\twindow.addEventListener('touchstart', markHuman, { once: true });\r\n\t\twindow.addEventListener('keydown', markHuman, { once: true });\r\n\r\n\t\treturn () => {\r\n\t\t\twindow.removeEventListener('mousemove', markHuman);\r\n\t\t\twindow.removeEventListener('touchstart', markHuman);\r\n\t\t\twindow.removeEventListener('keydown', markHuman);\r\n\t\t};\r\n\t});\r\n\r\n\tfunction runHeuristics(e: MouseEvent | TouchEvent | KeyboardEvent) {\r\n\t\tif (honeypot) return false;\r\n\r\n\t\tif (Date.now() - mountTime < 500) return false;\r\n\r\n\t\tif (!humanInteraction) return false;\r\n\r\n\t\tif (!e.isTrusted) return false;\r\n\r\n\t\treturn true;\r\n\t}\r\n\r\n\tasync function handleClick(e: any) {\r\n\t\tif (status !== 'idle' && status !== 'failed') return;\r\n\r\n\t\tstatus = 'verifying';\r\n\r\n\t\tawait new Promise((r) => setTimeout(r, 800));\r\n\r\n\t\tif (runHeuristics(e)) {\r\n\t\t\tstatus = 'verified';\r\n\t\t\tverified = true;\r\n\t\t\tonVerify?.();\r\n\t\t} else {\r\n\t\t\tstatus = 'failed';\r\n\t\t\tverified = false;\r\n\t\t\tsetTimeout(() => {\r\n\t\t\t\tstatus = 'idle';\r\n\t\t\t}, 2000);\r\n\t\t}\r\n\t}\r\n</script>\r\n\r\n<input\r\n\ttype=\"checkbox\"\r\n\tclass=\"absolute opacity-0 -z-10 w-0 h-0\"\r\n\ttabindex=\"-1\"\r\n\tbind:checked={honeypot}\r\n\tautocomplete=\"off\"\r\n/>\r\n\r\n<button\r\n\tonclick={handleClick}\r\n\tclass={cn(\r\n\t\t'group flex items-center justify-between w-[300px] h-16 px-4 rounded-md border bg-card text-card-foreground shadow-sm transition-all select-none',\r\n\t\tstatus === 'idle' && 'hover:bg-accent/5 cursor-pointer',\r\n\t\tstatus === 'failed' && 'border-red-500/50 bg-red-500/5 cursor-not-allowed',\r\n\t\t(status === 'verifying' || status === 'verified') && 'cursor-default',\r\n\t\tclassName\r\n\t)}\r\n\ttype=\"button\"\r\n>\r\n\t<div class=\"flex items-center gap-3\">\r\n\t\t<div\r\n\t\t\tclass={cn(\r\n\t\t\t\t'relative flex items-center justify-center w-7 h-7 rounded border-2 bg-background transition-all duration-300',\r\n\t\t\t\tstatus === 'idle' && 'border-muted-foreground/30 group-hover:border-muted-foreground/50',\r\n\t\t\t\tstatus === 'verifying' && 'border-transparent',\r\n\t\t\t\tstatus === 'verified' && 'border-primary bg-primary',\r\n\t\t\t\tstatus === 'failed' && 'border-destructive'\r\n\t\t\t)}\r\n\t\t>\r\n\t\t\t{#if status === 'verifying'}\r\n\t\t\t\t<Loader2 class=\"h-8 w-8 text-primary animate-spin absolute\" />\r\n\t\t\t{/if}\r\n\r\n\t\t\t{#if status === 'verified'}\r\n\t\t\t\t<Check\r\n\t\t\t\t\tclass=\"h-4 w-4 text-primary-foreground animate-in zoom-in duration-300\"\r\n\t\t\t\t\tstrokeWidth={3}\r\n\t\t\t\t/>\r\n\t\t\t{/if}\r\n\r\n\t\t\t{#if status === 'failed'}\r\n\t\t\t\t<X class=\"h-4 w-4 text-destructive animate-in zoom-in duration-300\" strokeWidth={3} />\r\n\t\t\t{/if}\r\n\t\t</div>\r\n\r\n\t\t<div class=\"flex flex-col items-start\">\r\n\t\t\t<span class=\"text-sm font-medium leading-none\">\r\n\t\t\t\t{#if status === 'verified'}\r\n\t\t\t\t\tI am human\r\n\t\t\t\t{:else if status === 'failed'}\r\n\t\t\t\t\tVerification failed\r\n\t\t\t\t{:else if status === 'verifying'}\r\n\t\t\t\t\tVerifying...\r\n\t\t\t\t{:else}\r\n\t\t\t\t\tVerify you are human\r\n\t\t\t\t{/if}\r\n\t\t\t</span>\r\n\t\t\t{#if status === 'failed'}\r\n\t\t\t\t<span class=\"text-[10px] text-destructive mt-1\">Please try again</span>\r\n\t\t\t{/if}\r\n\t\t</div>\r\n\t</div>\r\n\r\n\t<div class=\"flex flex-col items-center justify-center gap-0.5 opacity-50\">\r\n\t\t<ShieldCheck class=\"h-6 w-6 text-muted-foreground\" />\r\n\t\t<span class=\"text-[9px] text-muted-foreground leading-none\">Secure</span>\r\n\t</div>\r\n</button>\r\n",
			"type": "registry:ui",
			"target": "verify-human/verify-human.svelte"
		},
		{
			"content": "import VerifyHuman from './verify-human.svelte';\nexport { VerifyHuman };\n",
			"type": "registry:ui",
			"target": "verify-human/index.ts"
		}
	]
}