2import React, { ReactNode, ReactElement, isValidElement } from 'react';
3import { AnimatePresence, motion } from 'motion/react';
4import { ChevronDown } from 'lucide-react';
5import { cn } from '@/lib/utils';
7type AccordionContextType = {
10 onChangeIndex: (value: string) => void;
13const AccordionContext = React.createContext<AccordionContextType>({
19const useAccordion = () => React.useContext(AccordionContext);
21export function AccordionContainer({
29 <div className={cn('grid grid-cols-2 gap-1', className)}>{children}</div>
33export function AccordionWrapper({
38 return <div>{children}</div>;
41export function Accordion({
48 defaultValue?: string | string[];
50 const [activeIndex, setActiveIndex] = React.useState<string[]>(
51 multiple ? (defaultValue ? (Array.isArray(defaultValue) ? defaultValue : [defaultValue]) : []) :
52 (defaultValue ? (Array.isArray(defaultValue) ? [defaultValue[0]] : [defaultValue]) : [])
55 function onChangeIndex(value: string) {
56 setActiveIndex((currentActiveIndex) => {
58 return value === currentActiveIndex[0] ? [] : [value];
61 if (currentActiveIndex.includes(value)) {
62 return currentActiveIndex.filter((i) => i !== value);
65 return [...currentActiveIndex, value];
69 return React.Children.map(children, (child) => {
70 if (!isValidElement<{ value?: string }>(child)) return null;
72 const value = child.props.value ?? '';
73 const isActive = multiple
74 ? activeIndex.includes(value)
75 : activeIndex[0] === value;
78 <AccordionContext.Provider value={{ isActive, value, onChangeIndex }}>
79 {React.cloneElement(child)}
80 </AccordionContext.Provider>
85export function AccordionItem({
92 const { isActive } = useAccordion();
96 data-active={isActive || undefined}
97 className={`rounded-lg overflow-hidden mb-2 ${
99 ? 'active border-2 dark:border-[#656fe2] border-[#F2F2F2] dark:bg-[#E0ECFB] bg-[#F2F2F2]'
100 : 'bg-transparent border-2 dark:hover:border-[#656fe2]'
110export function AccordionHeader({
119 const { isActive, value, onChangeIndex } = useAccordion();
123 data-active={isActive || undefined}
124 className={`group p-4 cursor-pointer transition-all font-semibold dark:text-white text-black dark:hover:bg-[#1e2a78] hover:bg-[#F2F2F2] dark:hover:text-white hover:text-black flex justify-between items-center ${
126 ? 'active dark:bg-[#1e2a78] bg-[#F2F2F2] '
127 : 'dark:bg-[#11112b] bg-white'
130 onClick={() => onChangeIndex(value)}
137 isActive ? "rotate-180" : "rotate-0",
145export function AccordionPanel({
152 const { isActive } = useAccordion();
155 <AnimatePresence initial={true}>
158 data-active={isActive || undefined}
159 initial={{ height: 0, overflow: 'hidden' }}
160 animate={{ height: 'auto', overflow: 'hidden' }}
162 transition={{ type: 'spring', duration: 0.3, bounce: 0 }}
163 className={cn('group dark:bg-white bg-[#F2F2F2]', className)}
166 initial={{ clipPath: 'polygon(0 0, 100% 0, 100% 0, 0 0)' }}
167 animate={{ clipPath: 'polygon(0 0, 100% 0, 100% 100%, 0% 100%)' }}
169 clipPath: 'polygon(0 0, 100% 0, 100% 0, 0 0)',
176 className={`p-3 bg-transparent text-black `}