Files
graff-mate-client/src/components/Accordion.tsx
T
2025-07-22 18:11:57 +05:00

60 lines
1.7 KiB
TypeScript

import { useState } from "react";
import ChevronDownIcon from "./icons/ChevronDownIcon";
import clsx from "clsx";
import { AnimatePresence, motion } from "motion/react";
import { useClickAway } from "@uidotdev/usehooks";
function Accordion({ text, title }: { title: string; text: string }) {
const [isOpen, setIsOpen] = useState(false);
const [initialHeight, setInitialHeight] = useState(0);
const [textHeight, setTextHeight] = useState(0);
const ref = useClickAway<HTMLDivElement>(() => setIsOpen(false));
return (
<motion.div
ref={(el) => {
if (el) {
ref.current = el;
setInitialHeight(el?.clientHeight || 0);
}
}}
animate={{
height: isOpen ? initialHeight + textHeight + 12 : initialHeight,
}}
className="p-[1.111vw] space-y-[0.833vw] bg-[#F6F6F6] rounded-[0.833vw] overflow-hidden cursor-pointer select-none"
onClick={() => setIsOpen(!isOpen)}
>
<div className="flex items-center justify-between">
<p className="button-m font-medium">{title}</p>
<div
className={clsx(
"text-[#7D7D7D] size-[1.389vw] transition-transform duration-300",
isOpen && "rotate-180"
)}
>
<ChevronDownIcon />
</div>
</div>
<AnimatePresence>
{isOpen && (
<motion.p
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
exit={{ opacity: 0 }}
transition={{ duration: 0.2 }}
ref={(el) => setTextHeight(el?.clientHeight || 0)}
className="text-s text-[#7D7D7D]"
>
{text}
</motion.p>
)}
</AnimatePresence>
</motion.div>
);
}
export default Accordion;