{ "$schema": "https://ui.shadcn.com/schema/registry-item.json", "name": "flip-text", "type": "registry:ui", "dependencies": [], "files": [ { "path": "components/ui/flip-text.tsx", "content": "\"use client\";\r\n\r\nimport React, { useMemo } from \"react\";\r\nimport { cn } from \"@/lib/utils\";\r\n\r\ninterface FlipTextProps {\r\n /**\r\n * Additional CSS classes for the wrapper\r\n */\r\n className?: string;\r\n\r\n /**\r\n * The text content to animate (will be split by spaces)\r\n */\r\n children: string;\r\n\r\n /**\r\n * Duration of the flip animation in seconds\r\n * @default 2.2\r\n */\r\n duration?: number;\r\n\r\n /**\r\n * Initial delay before animation starts in seconds\r\n * @default 0\r\n */\r\n delay?: number;\r\n\r\n /**\r\n * Whether the animation should loop infinitely\r\n * @default true\r\n */\r\n loop?: boolean;\r\n\r\n /**\r\n * Custom separator for splitting text (default is space)\r\n * @default \" \"\r\n */\r\n separator?: string;\r\n\r\n /**\r\n * Whether all characters should animate together (no stagger)\r\n * @default false\r\n */\r\n together?: boolean;\r\n}\r\n\r\nexport function FlipText({\r\n className,\r\n children,\r\n duration = 2.2,\r\n delay = 0,\r\n loop = true,\r\n separator = \" \",\r\n together = false,\r\n}: FlipTextProps) {\r\n const words = useMemo(() => children.split(separator), [children, separator]);\r\n const totalChars = children.length;\r\n\r\n // Calculate character index for each position\r\n const getCharIndex = (wordIndex: number, charIndex: number) => {\r\n let index = 0;\r\n for (let i = 0; i < wordIndex; i++) {\r\n index += words[i].length + (separator === \" \" ? 1 : separator.length);\r\n }\r\n return index + charIndex;\r\n };\r\n\r\n return (\r\n \r\n {words.map((word, wordIndex) => {\r\n const chars = word.split(\"\");\r\n\r\n return (\r\n \r\n {chars.map((char, charIndex) => {\r\n const currentGlobalIndex = getCharIndex(wordIndex, charIndex);\r\n\r\n // Calculate delay - if together, use same delay for all\r\n let calculatedDelay = delay;\r\n if (!together) {\r\n const normalizedIndex = currentGlobalIndex / totalChars;\r\n const sineValue = Math.sin(normalizedIndex * (Math.PI / 2));\r\n calculatedDelay = sineValue * (duration * 0.25) + delay;\r\n }\r\n\r\n return (\r\n \r\n {char}\r\n \r\n );\r\n })}\r\n {separator === \" \" && wordIndex < words.length - 1 && (\r\n  \r\n )}\r\n {separator !== \" \" && wordIndex < words.length - 1 && (\r\n {separator}\r\n )}\r\n \r\n );\r\n })}\r\n \r\n );\r\n}\r\n\r\nexport default FlipText;\r\n", "type": "registry:ui", "target": "components/ui/flip-text.tsx" } ] }