{
	"$schema": "https://shadcn-svelte.com/schema/registry-item.json",
	"name": "lens",
	"title": "Lens",
	"type": "registry:block",
	"description": "An interactive component that enables zooming into images, videos and other elements.",
	"dependencies": [
		"motion-sv"
	],
	"files": [
		{
			"content": "<script lang=\"ts\">\n\timport { motion, AnimatePresence } from \"motion-sv\";\n\timport { cn } from \"$UTILS$\";\n\timport type { Snippet } from \"svelte\";\n\n\tinterface Position {\n\t\t/** The x coordinate of the lens */\n\t\tx: number;\n\t\t/** The y coordinate of the lens */\n\t\ty: number;\n\t}\n\n\tinterface LensProps {\n\t\tchildren: Snippet;\n\t\t/** The zoom factor of the lens */\n\t\tzoomFactor?: number;\n\t\t/** The size of the lens */\n\t\tlensSize?: number;\n\t\t/** The position of the lens */\n\t\tposition?: Position;\n\t\t/** The default position of the lens */\n\t\tdefaultPosition?: Position;\n\t\t/** Whether the lens is static */\n\t\tisStatic?: boolean;\n\t\t/** The duration of the animation */\n\t\tduration?: number;\n\t\t/** The color of the lens */\n\t\tlensColor?: string;\n\t\t/** The aria label of the lens */\n\t\tariaLabel?: string;\n\t\tclass?: string;\n\t}\n\n\tlet {\n\t\tchildren,\n\t\tzoomFactor = 1.3,\n\t\tlensSize = 170,\n\t\tisStatic = false,\n\t\tposition = { x: 0, y: 0 },\n\t\tdefaultPosition,\n\t\tduration = 0.1,\n\t\tlensColor = \"black\",\n\t\tariaLabel = \"Zoom Area\",\n\t\tclass: className,\n\t}: LensProps = $props();\n\n\t// Validation\n\t$effect(() => {\n\t\tif (zoomFactor < 1) {\n\t\t\tthrow new Error(\"zoomFactor must be greater than 1\");\n\t\t}\n\t\tif (lensSize < 0) {\n\t\t\tthrow new Error(\"lensSize must be greater than 0\");\n\t\t}\n\t});\n\n\tlet isHovering = $state(false);\n\tlet mousePosition: Position = $derived(position);\n\tlet containerRef: HTMLDivElement | null = $state(null);\n\n\tconst currentPosition = $derived.by(() => {\n\t\tif (isStatic) return position;\n\t\tif (defaultPosition && !isHovering) return defaultPosition;\n\t\treturn mousePosition;\n\t});\n\n\tconst handleMouseMove = (e: MouseEvent) => {\n\t\tif (!containerRef) return;\n\t\tconst rect = containerRef.getBoundingClientRect();\n\t\tmousePosition = {\n\t\t\tx: e.clientX - rect.left,\n\t\t\ty: e.clientY - rect.top,\n\t\t};\n\t};\n\n\tconst handleKeyDown = (e: KeyboardEvent) => {\n\t\tif (e.key === \"Escape\") isHovering = false;\n\t};\n\n\tconst maskImage = $derived(\n\t\t`radial-gradient(circle ${lensSize / 2}px at ${currentPosition.x}px ${currentPosition.y}px, ${lensColor} 100%, transparent 100%)`\n\t);\n\n\tconst transformOrigin = $derived(`${currentPosition.x}px ${currentPosition.y}px`);\n\n\tconst lensStyle = $derived({\n\t\tmaskImage,\n\t\tWebkitMaskImage: maskImage,\n\t\ttransformOrigin,\n\t\tzIndex: 50,\n\t});\n\n\tconst zoomStyleString = $derived(\n\t\t`transform: scale(${zoomFactor}); transform-origin: ${transformOrigin};`\n\t);\n</script>\n\n<!-- svelte-ignore a11y_no_noninteractive_tabindex -->\n<!-- svelte-ignore a11y_no_noninteractive_element_interactions -->\n<div\n\tbind:this={containerRef}\n\tclass={cn(\"relative z-20 overflow-hidden rounded-xl\", className)}\n\tonmouseenter={() => (isHovering = true)}\n\tonmouseleave={() => (isHovering = false)}\n\tonmousemove={handleMouseMove}\n\tonkeydown={handleKeyDown}\n\trole=\"region\"\n\taria-label={ariaLabel}\n\ttabindex=\"0\"\n>\n\t{@render children()}\n\t{#if isStatic || defaultPosition}\n\t\t<motion.div\n\t\t\tinitial={{ opacity: 0, scale: 0.58 }}\n\t\t\tanimate={{ opacity: 1, scale: 1 }}\n\t\t\texit={{ opacity: 0, scale: 0.8 }}\n\t\t\ttransition={{ duration }}\n\t\t\tclass=\"absolute inset-0 overflow-hidden\"\n\t\t\tstyle={lensStyle}\n\t\t>\n\t\t\t<div class=\"absolute inset-0\" style={zoomStyleString}>\n\t\t\t\t{@render children()}\n\t\t\t</div>\n\t\t</motion.div>\n\t{:else}\n\t\t<AnimatePresence mode=\"popLayout\">\n\t\t\t{#if isHovering}\n\t\t\t\t<motion.div\n\t\t\t\t\tinitial={{ opacity: 0, scale: 0.58 }}\n\t\t\t\t\tanimate={{ opacity: 1, scale: 1 }}\n\t\t\t\t\texit={{ opacity: 0, scale: 0.8 }}\n\t\t\t\t\ttransition={{ duration }}\n\t\t\t\t\tclass=\"absolute inset-0 overflow-hidden\"\n\t\t\t\t\tstyle={lensStyle}\n\t\t\t\t>\n\t\t\t\t\t<div class=\"absolute inset-0\" style={zoomStyleString}>\n\t\t\t\t\t\t{@render children()}\n\t\t\t\t\t</div>\n\t\t\t\t</motion.div>\n\t\t\t{/if}\n\t\t</AnimatePresence>\n\t{/if}\n</div>\n",
			"type": "registry:component",
			"target": "magic/lens/lens.svelte"
		},
		{
			"content": "export { default as Lens } from \"./lens.svelte\";\n",
			"type": "registry:file",
			"target": "magic/lens/index.ts"
		}
	]
}