Imagine, code, crée, inspire.
1. Installation avec le CLI de shadcn/ui
Copiez la commande ci-dessous dans votre terminal afin d'installer le composant
pnpm dlx shadcn@latest add @envindavsorg/flip-sentences
2. Installation manuelle
(2.1) installez les dépendances :
pnpm add motion clsx tailwind-merge
(2.2) ajoutez le helper cn :
import { type ClassValue, clsx } from 'clsx';
import { twMerge } from 'tailwind-merge';
export const cn = (...inputClasses: ClassValue[]): string => twMerge(clsx(inputClasses));(2.3) créez le tableau avec les phrases que vous souhaitez voir défiler :
const EXAMPLE_SENTENCES = [
'Imagine, code, crée, inspire.',
'Chaque petit pixel compte !',
'Chaque petit détail compte !',
'Du concept au déploiement !',
];(2.4) ajoutez le code suivant :
'use client';
import { AnimatePresence, motion } from 'motion/react';
import { useEffect, useMemo, useState } from 'react';
import { cn } from '@/lib/utils';
interface FlipSentencesProps {
className?: string;
sentences: string[];
interval?: number;
disableAnimation?: boolean;
}
const sentenceVariants = {
initial: { y: 10, opacity: 0 },
animate: { y: 0, opacity: 1 },
exit: { y: -10, opacity: 0 },
} as const;
const sentenceTransition = {
duration: 0.25,
ease: 'easeOut',
} as const;
export const FlipSentences = ({
className,
sentences,
interval = 4000,
disableAnimation = false,
}: FlipSentencesProps) => {
const [currentIndex, setCurrentIndex] = useState(0);
const sentenceCount = sentences.length;
const longestSentence = useMemo(() => sentences.reduce((a, b) => (b.length > a.length ? b : a), ''), [sentences]);
useEffect(() => {
if (disableAnimation) {
setCurrentIndex(0);
return;
}
const advance = () => setCurrentIndex((prev) => (prev + 1) % sentenceCount);
let timer = setInterval(advance, interval);
const handleVisibility = () => {
clearInterval(timer);
if (!document.hidden) {
advance();
timer = setInterval(advance, interval);
}
};
document.addEventListener('visibilitychange', handleVisibility);
return () => {
clearInterval(timer);
document.removeEventListener('visibilitychange', handleVisibility);
};
}, [sentenceCount, interval, disableAnimation]);
if (disableAnimation) {
return <p className={cn('font-medium text-theme text-xs sm:text-sm', className)}>{sentences[0]}</p>;
}
return (
<div className={cn('relative overflow-hidden', className)}>
<AnimatePresence mode="wait">
<motion.p
animate="animate"
className="font-medium text-theme text-xs sm:text-sm"
exit="exit"
initial="initial"
key={currentIndex}
transition={sentenceTransition}
variants={sentenceVariants}
>
{sentences[currentIndex]}
</motion.p>
</AnimatePresence>
<span aria-hidden="true" className="invisible block h-0">
{longestSentence}
</span>
</div>
);
};(2.5) petite astuce :
Mettez à jour les chemins d'import de vos dépendances pour correspondre à la structure de votre projet et ainsi le faire fonctionner correctement.
3. Utilisation
'use client';
import { FlipSentences } from "@/components/flip-sentences";
<FlipSentences sentences={EXAMPLE_SENTENCES} />