{
	"$schema": "https://shadcn-svelte.com/schema/registry-item.json",
	"name": "motion-grid",
	"title": "Motion Grid",
	"type": "registry:block",
	"description": "A frame-based 2D grid animation primitive with active/inactive cell states.",
	"dependencies": [
		"motion-sv"
	],
	"files": [
		{
			"content": "<script lang=\"ts\">\n\timport { motion } from \"motion-sv\";\n\timport { setMotionGridContext } from \"./use-motion-grid-context.svelte\";\n\timport type { MotionGridCellMotionProps, MotionGridProps } from \"./types\";\n\n\ttype StyleValue = MotionGridCellMotionProps[\"style\"];\n\n\tfunction mergeStyles(baseStyle: StyleValue, userStyle: StyleValue): StyleValue {\n\t\treturn {\n\t\t\t...(baseStyle ?? {}),\n\t\t\t...(userStyle ?? {}),\n\t\t};\n\t}\n\n\tfunction withRefProp<T extends Record<string, unknown>>(props: T) {\n\t\treturn Object.defineProperty(props, \"ref\", {\n\t\t\tenumerable: true,\n\t\t\tconfigurable: true,\n\t\t\tget: () => ref,\n\t\t\tset: (value) => {\n\t\t\t\tref = value as HTMLDivElement | null;\n\t\t\t},\n\t\t}) as T & { ref: HTMLDivElement | null };\n\t}\n\n\tlet {\n\t\tref = $bindable(null),\n\t\tgridSize,\n\t\tframes,\n\t\tduration = 200,\n\t\tanimate = true,\n\t\tchild,\n\t\tchildren,\n\t\t...restProps\n\t}: MotionGridProps = $props();\n\n\tlet index = $state(0);\n\n\tlet cols = $derived(gridSize[0]);\n\tlet rows = $derived(gridSize[1]);\n\n\tsetMotionGridContext({\n\t\tanimate: () => {\n\t\t\treturn animate;\n\t\t},\n\t\tindex: () => {\n\t\t\treturn index;\n\t\t},\n\t\tcols: () => {\n\t\t\treturn cols;\n\t\t},\n\t\trows: () => {\n\t\t\treturn rows;\n\t\t},\n\t\tframes: () => {\n\t\t\treturn frames;\n\t\t},\n\t\tduration: () => {\n\t\t\treturn duration;\n\t\t},\n\t});\n\n\t$effect(() => {\n\t\tframes;\n\t\tindex = 0;\n\t});\n\n\t$effect(() => {\n\t\tif (frames.length === 0) {\n\t\t\tindex = 0;\n\t\t\treturn;\n\t\t}\n\n\t\tif (index >= frames.length) {\n\t\t\tindex = 0;\n\t\t}\n\t});\n\n\t$effect(() => {\n\t\tif (!animate || frames.length === 0) return;\n\n\t\tlet interval = setInterval(() => {\n\t\t\tindex = (index + 1) % frames.length;\n\t\t}, duration);\n\n\t\treturn () => clearInterval(interval);\n\t});\n\n\tlet baseStyle = $derived({\n\t\tdisplay: \"grid\",\n\t\tgridTemplateColumns: `repeat(${cols}, minmax(0, 1fr))`,\n\t\tgridAutoRows: \"1fr\",\n\t});\n\n\tlet mergedProps = $derived.by(() => {\n\t\tlet style = mergeStyles(baseStyle, restProps.style as StyleValue);\n\t\treturn withRefProp({\n\t\t\t...restProps,\n\t\t\t\"data-animate\": animate,\n\t\t\tstyle,\n\t\t}) as MotionGridCellMotionProps;\n\t});\n</script>\n\n{#if child}\n\t{@render child({ props: mergedProps })}\n{:else}\n\t<motion.div bind:ref {...mergedProps}>\n\t\t{@render children?.()}\n\t</motion.div>\n{/if}\n",
			"type": "registry:component",
			"target": "magic/motion-grid/motion-grid.svelte"
		},
		{
			"content": "<script lang=\"ts\">\n\timport { motion } from \"motion-sv\";\n\timport { cn } from \"$UTILS$\";\n\timport { useMotionGridContext } from \"./use-motion-grid-context.svelte\";\n\timport type { MotionGridCellMotionProps, MotionGridCellsProps } from \"./types\";\n\n\ttype StyleValue = MotionGridCellMotionProps[\"style\"];\n\n\tfunction mergeStyles(baseStyle: StyleValue, variantStyle: StyleValue): StyleValue {\n\t\treturn {\n\t\t\t...(baseStyle ?? {}),\n\t\t\t...(variantStyle ?? {}),\n\t\t};\n\t}\n\n\tlet { activeProps, inactiveProps, ...props }: MotionGridCellsProps = $props();\n\n\tlet context = useMotionGridContext();\n\tlet cellRef = $state<HTMLDivElement | null>(null);\n\n\tlet animate = $derived(context.animate());\n\tlet index = $derived(context.index());\n\tlet cols = $derived(context.cols());\n\tlet rows = $derived(context.rows());\n\tlet frames = $derived(context.frames());\n\tlet duration = $derived(context.duration());\n\tlet transitionDuration = $derived(duration / 1000);\n\n\tlet active = $derived.by(() => {\n\t\treturn new Set<number>(frames[index]?.map(([x, y]) => y * cols + x) ?? []);\n\t});\n\n\tlet totalCells = $derived(cols * rows);\n\n\tlet baseClass = $derived(props.class);\n\tlet baseStyle = $derived(props.style as StyleValue);\n\tlet baseProps = $derived.by(() => {\n\t\tconst { class: _class, style: _style, ref: _ref, ...rest } = props;\n\t\treturn rest;\n\t});\n</script>\n\n{#each Array.from({ length: totalCells }) as _, i (i)}\n\t{@const isActive = active.has(i)}\n\t{@const variantProps = (isActive ? activeProps : inactiveProps) ?? {}}\n\t{@const variantClass = variantProps.class}\n\t{@const variantStyle = variantProps.style}\n\t{@const mergedClass = cn(baseClass, variantClass)}\n\t{@const mergedStyle = mergeStyles(baseStyle, variantStyle as StyleValue)}\n\t{@const { ref: _variantRef, ...variantRestProps } = variantProps}\n\t{@const restVariantProps = { ...variantRestProps, class: mergedClass, style: mergedStyle }}\n\n\t<motion.div\n\t\tbind:ref={cellRef}\n\t\tdata-active={isActive}\n\t\tdata-animate={animate}\n\t\ttransition={{ duration: transitionDuration, ease: \"easeInOut\" }}\n\t\t{...baseProps}\n\t\t{...restVariantProps}\n\t/>\n{/each}\n",
			"type": "registry:component",
			"target": "magic/motion-grid/motion-grid-cells.svelte"
		},
		{
			"content": "export { default as MotionGrid } from \"./motion-grid.svelte\";\nexport { default as MotionGridCells } from \"./motion-grid-cells.svelte\";\n\nexport type {\n\tFrameDot,\n\tFrame,\n\tFrames,\n\tMotionGridContextType,\n\tMotionGridCellMotionProps,\n\tMotionGridProps,\n\tMotionGridCellsProps,\n} from \"./types\";\n",
			"type": "registry:file",
			"target": "magic/motion-grid/index.ts"
		},
		{
			"content": "import type { MotionHTMLAttributes } from \"motion-sv\";\nimport type { MotionProps } from \"motion-sv\";\nimport type { Snippet } from \"svelte\";\n\nexport type FrameDot = [number, number];\nexport type Frame = FrameDot[];\nexport type Frames = Frame[];\n\nexport type MotionGridContextType = {\n\tindex: () => number;\n\tcols: () => number;\n\trows: () => number;\n\tframes: () => Frames;\n\tduration: () => number;\n\tanimate: () => boolean;\n};\n\nexport type MotionGridCellMotionProps = Omit<MotionProps, \"children\"> & MotionHTMLAttributes<\"div\">;\n\nexport type MotionGridProps = Omit<MotionProps, \"children\" | \"animate\"> &\n\tMotionHTMLAttributes<\"div\"> & {\n\t\tgridSize: [number, number];\n\t\tframes: Frames;\n\t\tduration?: number;\n\t\tanimate?: boolean;\n\t\tchild?: Snippet<[{ props: MotionGridCellMotionProps }]>;\n\t\tchildren?: Snippet;\n\t};\n\nexport type MotionGridCellsProps = Omit<MotionProps, \"children\"> &\n\tMotionHTMLAttributes<\"div\"> & {\n\t\tactiveProps?: MotionGridCellMotionProps;\n\t\tinactiveProps?: MotionGridCellMotionProps;\n\t};\n",
			"type": "registry:file",
			"target": "magic/motion-grid/types.ts"
		},
		{
			"content": "import { getContext, setContext } from \"svelte\";\nimport type { MotionGridContextType } from \"./types\";\n\nconst MOTION_GRID_CONTEXT_KEY = Symbol(\"motion-grid-context\");\n\nexport function setMotionGridContext(value: MotionGridContextType): MotionGridContextType {\n\tsetContext(MOTION_GRID_CONTEXT_KEY, value);\n\treturn value;\n}\n\nexport function useMotionGridContext(): MotionGridContextType {\n\tconst context = getContext<MotionGridContextType>(MOTION_GRID_CONTEXT_KEY);\n\tif (!context) {\n\t\tthrow new Error(\"MotionGridCells must be used within a MotionGrid provider\");\n\t}\n\treturn context;\n}\n",
			"type": "registry:file",
			"target": "magic/motion-grid/use-motion-grid-context.svelte.ts"
		}
	]
}