{
	"$schema": "https://shadcn-svelte.com/schema/registry-item.json",
	"name": "text-animate",
	"title": "Text Animate",
	"type": "registry:block",
	"description": "Animate text with various effects like blur, slide, scale, and fade with granular control over words, characters, or lines.",
	"dependencies": [
		"runed",
		"motion-sv"
	],
	"files": [
		{
			"content": "<script lang=\"ts\">\n\timport { cn } from \"$UTILS$\";\n\timport type { ElementType, MotionProps, Variants } from \"motion-sv\";\n\timport { motion, AnimatePresence } from \"motion-sv\";\n\n\ttype AnimationType = \"text\" | \"word\" | \"character\" | \"line\";\n\ttype AnimationVariant =\n\t\t| \"fadeIn\"\n\t\t| \"blurIn\"\n\t\t| \"blurInUp\"\n\t\t| \"blurInDown\"\n\t\t| \"slideUp\"\n\t\t| \"slideDown\"\n\t\t| \"slideLeft\"\n\t\t| \"slideRight\"\n\t\t| \"scaleUp\"\n\t\t| \"scaleDown\";\n\n\tconst staggerTimings: Record<AnimationType, number> = {\n\t\ttext: 0.06,\n\t\tword: 0.05,\n\t\tcharacter: 0.03,\n\t\tline: 0.06,\n\t};\n\n\tconst defaultContainerVariants = {\n\t\thidden: { opacity: 1 },\n\t\tshow: {\n\t\t\topacity: 1,\n\t\t\ttransition: {\n\t\t\t\tdelayChildren: 0,\n\t\t\t\tstaggerChildren: 0.05,\n\t\t\t},\n\t\t},\n\t\texit: {\n\t\t\topacity: 0,\n\t\t\ttransition: {\n\t\t\t\tstaggerChildren: 0.05,\n\t\t\t\tstaggerDirection: -1,\n\t\t\t},\n\t\t},\n\t};\n\tconst defaultItemVariants: Variants = {\n\t\thidden: { opacity: 0 },\n\t\tshow: {\n\t\t\topacity: 1,\n\t\t},\n\t\texit: {\n\t\t\topacity: 0,\n\t\t},\n\t};\n\n\tconst defaultItemAnimationVariants: Record<\n\t\tAnimationVariant,\n\t\t{ container: Variants; item: Variants }\n\t> = {\n\t\tfadeIn: {\n\t\t\tcontainer: defaultContainerVariants,\n\t\t\titem: {\n\t\t\t\thidden: { opacity: 0, y: 20 },\n\t\t\t\tshow: {\n\t\t\t\t\topacity: 1,\n\t\t\t\t\ty: 0,\n\t\t\t\t\ttransition: {\n\t\t\t\t\t\tduration: 0.3,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\texit: {\n\t\t\t\t\topacity: 0,\n\t\t\t\t\ty: 20,\n\t\t\t\t\ttransition: { duration: 0.3 },\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\tblurIn: {\n\t\t\tcontainer: defaultContainerVariants,\n\t\t\titem: {\n\t\t\t\thidden: { opacity: 0, filter: \"blur(10px)\" },\n\t\t\t\tshow: {\n\t\t\t\t\topacity: 1,\n\t\t\t\t\tfilter: \"blur(0px)\",\n\t\t\t\t\ttransition: {\n\t\t\t\t\t\tduration: 0.3,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\texit: {\n\t\t\t\t\topacity: 0,\n\t\t\t\t\tfilter: \"blur(10px)\",\n\t\t\t\t\ttransition: { duration: 0.3 },\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\tblurInUp: {\n\t\t\tcontainer: defaultContainerVariants,\n\t\t\titem: {\n\t\t\t\thidden: { opacity: 0, filter: \"blur(10px)\", y: 20 },\n\t\t\t\tshow: {\n\t\t\t\t\topacity: 1,\n\t\t\t\t\tfilter: \"blur(0px)\",\n\t\t\t\t\ty: 0,\n\t\t\t\t\ttransition: {\n\t\t\t\t\t\ty: { duration: 0.3 },\n\t\t\t\t\t\topacity: { duration: 0.4 },\n\t\t\t\t\t\tfilter: { duration: 0.3 },\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\texit: {\n\t\t\t\t\topacity: 0,\n\t\t\t\t\tfilter: \"blur(10px)\",\n\t\t\t\t\ty: 20,\n\t\t\t\t\ttransition: {\n\t\t\t\t\t\ty: { duration: 0.3 },\n\t\t\t\t\t\topacity: { duration: 0.4 },\n\t\t\t\t\t\tfilter: { duration: 0.3 },\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\tblurInDown: {\n\t\t\tcontainer: defaultContainerVariants,\n\t\t\titem: {\n\t\t\t\thidden: { opacity: 0, filter: \"blur(10px)\", y: -20 },\n\t\t\t\tshow: {\n\t\t\t\t\topacity: 1,\n\t\t\t\t\tfilter: \"blur(0px)\",\n\t\t\t\t\ty: 0,\n\t\t\t\t\ttransition: {\n\t\t\t\t\t\ty: { duration: 0.3 },\n\t\t\t\t\t\topacity: { duration: 0.4 },\n\t\t\t\t\t\tfilter: { duration: 0.3 },\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\tslideUp: {\n\t\t\tcontainer: defaultContainerVariants,\n\t\t\titem: {\n\t\t\t\thidden: { y: 20, opacity: 0 },\n\t\t\t\tshow: {\n\t\t\t\t\ty: 0,\n\t\t\t\t\topacity: 1,\n\t\t\t\t\ttransition: {\n\t\t\t\t\t\tduration: 0.3,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\texit: {\n\t\t\t\t\ty: -20,\n\t\t\t\t\topacity: 0,\n\t\t\t\t\ttransition: {\n\t\t\t\t\t\tduration: 0.3,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\tslideDown: {\n\t\t\tcontainer: defaultContainerVariants,\n\t\t\titem: {\n\t\t\t\thidden: { y: -20, opacity: 0 },\n\t\t\t\tshow: {\n\t\t\t\t\ty: 0,\n\t\t\t\t\topacity: 1,\n\t\t\t\t\ttransition: { duration: 0.3 },\n\t\t\t\t},\n\t\t\t\texit: {\n\t\t\t\t\ty: 20,\n\t\t\t\t\topacity: 0,\n\t\t\t\t\ttransition: { duration: 0.3 },\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\tslideLeft: {\n\t\t\tcontainer: defaultContainerVariants,\n\t\t\titem: {\n\t\t\t\thidden: { x: 20, opacity: 0 },\n\t\t\t\tshow: {\n\t\t\t\t\tx: 0,\n\t\t\t\t\topacity: 1,\n\t\t\t\t\ttransition: { duration: 0.3 },\n\t\t\t\t},\n\t\t\t\texit: {\n\t\t\t\t\tx: -20,\n\t\t\t\t\topacity: 0,\n\t\t\t\t\ttransition: { duration: 0.3 },\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\tslideRight: {\n\t\t\tcontainer: defaultContainerVariants,\n\t\t\titem: {\n\t\t\t\thidden: { x: -20, opacity: 0 },\n\t\t\t\tshow: {\n\t\t\t\t\tx: 0,\n\t\t\t\t\topacity: 1,\n\t\t\t\t\ttransition: { duration: 0.3 },\n\t\t\t\t},\n\t\t\t\texit: {\n\t\t\t\t\tx: 20,\n\t\t\t\t\topacity: 0,\n\t\t\t\t\ttransition: { duration: 0.3 },\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\tscaleUp: {\n\t\t\tcontainer: defaultContainerVariants,\n\t\t\titem: {\n\t\t\t\thidden: { scale: 0.5, opacity: 0 },\n\t\t\t\tshow: {\n\t\t\t\t\tscale: 1,\n\t\t\t\t\topacity: 1,\n\t\t\t\t\ttransition: {\n\t\t\t\t\t\tduration: 0.3,\n\t\t\t\t\t\tscale: {\n\t\t\t\t\t\t\ttype: \"spring\",\n\t\t\t\t\t\t\tdamping: 15,\n\t\t\t\t\t\t\tstiffness: 300,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\texit: {\n\t\t\t\t\tscale: 0.5,\n\t\t\t\t\topacity: 0,\n\t\t\t\t\ttransition: { duration: 0.3 },\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\tscaleDown: {\n\t\t\tcontainer: defaultContainerVariants,\n\t\t\titem: {\n\t\t\t\thidden: { scale: 1.5, opacity: 0 },\n\t\t\t\tshow: {\n\t\t\t\t\tscale: 1,\n\t\t\t\t\topacity: 1,\n\t\t\t\t\ttransition: {\n\t\t\t\t\t\tduration: 0.3,\n\t\t\t\t\t\tscale: {\n\t\t\t\t\t\t\ttype: \"spring\",\n\t\t\t\t\t\t\tdamping: 15,\n\t\t\t\t\t\t\tstiffness: 300,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\texit: {\n\t\t\t\t\tscale: 1.5,\n\t\t\t\t\topacity: 0,\n\t\t\t\t\ttransition: { duration: 0.3 },\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t};\n\n\tinterface TextAnimateProps extends MotionProps {\n\t\t/**\n\t\t * The text content to animate\n\t\t */\n\t\tcontent: string;\n\t\t/**\n\t\t * The class name to be applied to the component\n\t\t */\n\t\tclass?: string;\n\t\t/**\n\t\t * The class name to be applied to each segment\n\t\t */\n\t\tsegmentClass?: string;\n\t\t/**\n\t\t * The delay before the animation starts\n\t\t */\n\t\tdelay?: number;\n\t\t/**\n\t\t * The duration of the animation\n\t\t */\n\t\tduration?: number;\n\t\t/**\n\t\t * Custom motion variants for the animation\n\t\t */\n\t\tvariants?: Variants;\n\t\t/**\n\t\t * The element type to render\n\t\t */\n\t\t// as?: ElementType;\n\t\t/**\n\t\t * How to split the text (\"text\", \"word\", \"character\")\n\t\t */\n\t\tby?: AnimationType;\n\t\t/**\n\t\t * Whether to start animation when component enters viewport\n\t\t */\n\t\tstartOnView?: boolean;\n\t\t/**\n\t\t * Whether to animate only once\n\t\t */\n\t\tonce?: boolean;\n\t\t/**\n\t\t * The animation preset to use\n\t\t */\n\t\tanimation?: AnimationVariant;\n\t\t/**\n\t\t * Whether to enable accessibility features (default: true)\n\t\t */\n\t\taccessible?: boolean;\n\t}\n\n\t// as = \"span\",\n\tlet {\n\t\tcontent,\n\t\tclass: className = \"\",\n\t\tsegmentClass = \"\",\n\t\tdelay = 0,\n\t\tduration = 0.3,\n\t\tvariants,\n\t\tby = \"word\",\n\t\tstartOnView = true,\n\t\tonce = false,\n\t\tanimation = \"fadeIn\",\n\t\taccessible = true,\n\t}: TextAnimateProps = $props();\n\n\tlet segments: string[] = $derived.by(() => {\n\t\tif (!content) return [];\n\t\tlet text = content;\n\t\tswitch (by) {\n\t\t\tcase \"word\":\n\t\t\t\treturn text.split(/(\\s+)/);\n\t\t\t\tbreak;\n\t\t\tcase \"character\":\n\t\t\t\treturn text.split(\"\");\n\t\t\t\tbreak;\n\t\t\tcase \"line\":\n\t\t\t\t// split by \\n or \\r\\n or \\\\n\n\t\t\t\t// trim each line\n\t\t\t\treturn (\n\t\t\t\t\ttext.split(\"\\\\n\").map((line) => line.trim()) ||\n\t\t\t\t\ttext.split(\"\\n\").map((line) => line.trim())\n\t\t\t\t);\n\t\t\t\tbreak;\n\t\t\tcase \"text\":\n\t\t\tdefault:\n\t\t\t\treturn [text];\n\t\t\t\tbreak;\n\t\t}\n\t});\n\n\tlet finalVariants = $derived(\n\t\tvariants\n\t\t\t? {\n\t\t\t\t\tcontainer: {\n\t\t\t\t\t\thidden: { opacity: 0 },\n\t\t\t\t\t\tshow: {\n\t\t\t\t\t\t\topacity: 1,\n\t\t\t\t\t\t\ttransition: {\n\t\t\t\t\t\t\t\topacity: { duration: 0.01, delay },\n\t\t\t\t\t\t\t\tdelayChildren: delay,\n\t\t\t\t\t\t\t\tstaggerChildren: duration / segments.length,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t\texit: {\n\t\t\t\t\t\t\topacity: 0,\n\t\t\t\t\t\t\ttransition: {\n\t\t\t\t\t\t\t\tstaggerChildren: duration / segments.length,\n\t\t\t\t\t\t\t\tstaggerDirection: -1,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\titem: variants,\n\t\t\t\t}\n\t\t\t: animation\n\t\t\t\t? {\n\t\t\t\t\t\tcontainer: {\n\t\t\t\t\t\t\t...defaultItemAnimationVariants[animation].container,\n\t\t\t\t\t\t\tshow: {\n\t\t\t\t\t\t\t\t...defaultItemAnimationVariants[animation].container.show,\n\t\t\t\t\t\t\t\ttransition: {\n\t\t\t\t\t\t\t\t\tdelayChildren: delay,\n\t\t\t\t\t\t\t\t\tstaggerChildren: duration / segments.length,\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\texit: {\n\t\t\t\t\t\t\t\t...defaultItemAnimationVariants[animation].container.exit,\n\t\t\t\t\t\t\t\ttransition: {\n\t\t\t\t\t\t\t\t\tstaggerChildren: duration / segments.length,\n\t\t\t\t\t\t\t\t\tstaggerDirection: -1,\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t\titem: defaultItemAnimationVariants[animation].item,\n\t\t\t\t\t}\n\t\t\t\t: { container: defaultContainerVariants, item: defaultItemVariants }\n\t);\n\n\t// $inspect(segments, \"Segments\");\n\t// $inspect(content, \"Content\");\n</script>\n\n<AnimatePresence mode=\"popLayout\">\n\t<motion.div\n\t\tvariants={finalVariants.container as Variants}\n\t\tinitial=\"hidden\"\n\t\twhileInView={startOnView ? \"show\" : undefined}\n\t\tanimate={startOnView ? undefined : \"show\"}\n\t\texit=\"exit\"\n\t\tinViewOptions={{ once }}\n\t\taria-label={accessible ? segments.join(\" \") : undefined}\n\t\tclass={cn(\"whitespace-pre-wrap\", className)}\n\t>\n\t\t{#if accessible}\n\t\t\t<span class=\"sr-only\">{content}</span>\n\t\t{/if}\n\t\t{#each segments as segment, i}\n\t\t\t<motion.span\n\t\t\t\tvariants={finalVariants.item}\n\t\t\t\tcustom={i * staggerTimings[by]}\n\t\t\t\tclass={cn(\n\t\t\t\t\tby === \"line\" ? \"block\" : \"inline-block whitespace-pre\",\n\t\t\t\t\tby === \"character\" && \"\",\n\t\t\t\t\tsegmentClass\n\t\t\t\t)}\n\t\t\t\taria-hidden={accessible ? true : undefined}\n\t\t\t>\n\t\t\t\t{segment}\n\t\t\t</motion.span>\n\t\t{/each}\n\t</motion.div>\n</AnimatePresence>\n",
			"type": "registry:component",
			"target": "magic/text-animate/text-animate.svelte"
		},
		{
			"content": "import TextAnimate from \"./text-animate.svelte\";\nexport { TextAnimate };\n",
			"type": "registry:file",
			"target": "magic/text-animate/index.ts"
		}
	]
}