Scramble Text
Brouille les caracteres puis les resout en texte final. Installez Scramble Text depuis le registre VLLNT UI avec la CLI shadcn.
Brouille les caracteres puis les resout en texte final. Fait partie de la famille content dans VLLNT UI, il est publie comme entree de registre lisible par machine — copiez la source directement dans votre application avec la CLI shadcn et possedez-la, sans dependance d'execution a une bibliotheque de composants.
Apercu
Basculez entre clair et sombre pour inspecter l'apercu Storybook integre.
Installation
Ajoutez Scramble Text a votre projet avec la CLI shadcn. La source arrive dans votre code, prete a etre adaptee :
pnpm dlx shadcn@latest add https://ui.vllnt.ai/r/scramble-text.jsonSource
"use client";
import * as React from "react";
import { cn } from "../../lib/utils";
/** Props for {@link ScrambleText}. */
export type ScrambleTextProps = React.ComponentPropsWithoutRef<"span"> & {
/** Milliseconds for the full resolve. Defaults to `1200`. */
duration?: number;
/** Pool of glyphs used while scrambling. */
scrambleCharacters?: string;
/** Final resolved text. */
text: string;
};
function usePrefersReducedMotion(): boolean {
const [reduced, setReduced] = React.useState(false);
React.useEffect(() => {
if (
typeof window === "undefined" ||
typeof window.matchMedia !== "function"
) {
return;
}
const query = window.matchMedia("(prefers-reduced-motion: reduce)");
const onChange = (): void => {
setReduced(query.matches);
};
onChange();
query.addEventListener("change", onChange);
return () => {
query.removeEventListener("change", onChange);
};
}, []);
return reduced;
}
function scramble(text: string, revealed: number, pool: string): string {
const characters = text.match(/[\s\S]/gu) ?? [];
return characters
.map((character, index) => {
if (index < revealed || character === " ") {
return character;
}
return pool.charAt(Math.floor(Math.random() * pool.length));
})
.join("");
}
const defaultPool = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
/**
* Resolves text left-to-right out of randomized glyphs on mount.
*
* Respects `prefers-reduced-motion`: the final text shows at once.
*
* @example
* ```tsx
* <ScrambleText text="DECRYPTED" />
* ```
*/
export const ScrambleText = ({
className,
duration = 1200,
ref,
scrambleCharacters = defaultPool,
text,
...props
}: ScrambleTextProps & { ref?: React.Ref<HTMLSpanElement> }) => {
const reduced = usePrefersReducedMotion();
const [display, setDisplay] = React.useState(text);
React.useEffect(() => {
if (reduced) {
setDisplay(text);
return;
}
const steps = Math.max(text.length, 1);
const tick = duration / steps;
let revealed = 0;
const timer = setInterval(() => {
revealed += 1;
setDisplay(scramble(text, revealed, scrambleCharacters));
if (revealed >= text.length) {
clearInterval(timer);
}
}, tick);
return () => {
clearInterval(timer);
};
}, [duration, reduced, scrambleCharacters, text]);
return (
<span
aria-label={text}
className={cn("font-mono", className)}
ref={ref}
{...props}
>
<span aria-hidden="true">{display}</span>
</span>
);
};
ScrambleText.displayName = "ScrambleText";
Stories
Explorez chaque variante et etat dans le Storybook interactif :
Apercu
Basculez entre clair et sombre pour inspecter l'apercu Storybook integre.