{"$schema":"https://ui.shadcn.com/schema/registry-item.json","name":"text-reveal","type":"registry:ui","title":"Text reveal","description":"Reveal a short piece of content with restrained motion.","categories":["text"],"dependencies":[],"registryDependencies":["https://uiarc.dev/r/arc-foundation.json"],"files":[{"path":"registry/components/text-reveal/text-reveal.tsx","type":"registry:component","target":"@components/arc/text-reveal/text-reveal.tsx","content":"\"use client\";\nimport { Fragment, type CSSProperties } from \"react\";\nimport { motionTokens } from \"../lib/motion-tokens\";\nimport styles from \"./text-reveal.module.css\";\n\n/**\n * Reveals a short headline or sentence once, as it mounts: each word rises out of its own clip while it sharpens from a soft blur.\n * The entrance runs in CSS, so it starts on first paint, never waits for hydration, and never leaves text hidden when scripts are slow.\n * Use `\\n` in `text` for a deliberate line break and change the element's `key` to replay it.\n */\nexport interface TextRevealProps { text: string; as?: \"h1\" | \"h2\" | \"h3\" | \"p\"; className?: string; id?: string; /** Seconds to wait before the first word rises. Defaults to 0. */ delay?: number }\n/** Total stagger stays under this many seconds, however long the text is. */\nconst MAX_STAGGER = motionTokens.duration.considered;\n\nexport function TextReveal({ text, as = \"h2\", className, id, delay = 0 }: TextRevealProps) {\n const Tag = as;\n const lines = text.split(\"\\n\").map(line => line.split(\" \").filter(Boolean));\n const count = lines.reduce((total, words) => total + words.length, 0);\n const step = Math.min(motionTokens.stagger.word, MAX_STAGGER / Math.max(count, 1));\n const blur = as === \"p\" ? motionTokens.blur.soft : motionTokens.blur.text;\n let index = 0;\n return \n {text.replace(/\\n/g, \" \")}\n {lines.map((words, lineIndex) => {words.map((word, wordIndex) => {\n const position = index++;\n return {word}{wordIndex < words.length - 1 ? \" \" : null};\n })}{lineIndex < lines.length - 1 ? \" \" : null})}\n ;\n}\n\nexport default TextReveal;\n"},{"path":"registry/components/text-reveal/text-reveal.module.css","type":"registry:component","target":"@components/arc/text-reveal/text-reveal.module.css","content":".reveal { max-width: 24ch; margin: 0; overflow: visible; color: var(--foreground); text-wrap: balance; }\n.line { display: block; }\n/* The clip hides the rise below the line through a feathered bottom edge, so a blurred word surfaces softly instead of being cut by a hard line.\n Padding with matching negative margins leaves room for descenders and the blur without changing layout; the feather sits below the descenders, so resting words are never dimmed. */\n.clip { display: inline-block; vertical-align: top; padding: .1em .16em .24em; margin: -.1em -.16em -.24em; mask-image: linear-gradient(#000 calc(100% - .18em), transparent); }\n/* Three tracks: the rise settles longest, the fade finishes first, and the blur clears between them.\n Backwards fill holds the hidden start through each word's delay, then lets go at the end, so resting words keep no transform or filter layer and render as crisp as plain text. */\n.word { display: inline-block; animation: rise .76s var(--ease-enter) var(--reveal-delay, 0s) backwards, fade .44s var(--ease-standard) var(--reveal-delay, 0s) backwards, focus .58s var(--ease-enter) var(--reveal-delay, 0s) backwards; }\n.srOnly { position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0; overflow: hidden; clip-path: inset(50%); white-space: nowrap; border: 0; user-select: none; }\n@keyframes rise { from { transform: translateY(.62em); } }\n@keyframes fade { from { opacity: 0; } }\n@keyframes focus { from { filter: blur(var(--reveal-blur, 4px)); } }\n@media (prefers-reduced-motion: reduce) { .clip { mask-image: none; } .word { animation: fade var(--duration-fast) var(--ease-standard) backwards; } }\n"}],"docs":"Docs and live preview: https://uiarc.dev/components/text-reveal","meta":{"tier":"free","kind":"component","docs":"https://uiarc.dev/components/text-reveal","markdown":"https://uiarc.dev/components/text-reveal/markdown","tags":["text","motion","content"]}}