"use client"; import { useReducedMotion } from "../motion/Preferences.tsx"; import { createContext, useContext, useState, useId, type ReactNode, } from "react"; import { AnimatePresence, motion } from "motion/react"; import { EASE_EXPO } from "../motion/easings.ts"; type AccordionContextValue = { open: readonly string[]; toggle: (value: string) => void; level: 2 | 3 | 4 | 5 | 6; }; const AccordionContext = createContext(null); export function Accordion({ children, allowMultiple = false, value, defaultValue = [], onValueChange, level = 3, className = "", }: { children: ReactNode; allowMultiple?: boolean; value?: readonly string[]; defaultValue?: readonly string[]; onValueChange?: (value: string[]) => void; level?: 2 | 3 | 4 | 5 | 6; className?: string; }) { const [internal, setInternal] = useState(defaultValue); const open = value ?? internal; const toggle = (item: string) => { const next = open.includes(item) ? open.filter((v) => v !== item) : allowMultiple ? [...open, item] : [item]; if (value === undefined) setInternal(next); onValueChange?.(next); }; return (
{children}
); } export function AccordionItem({ value, title, children, className = "", }: { value: string; title: string; children: ReactNode; className?: string; }) { const id = useId(); const reduce = useReducedMotion(); const ctx = useContext(AccordionContext); if (!ctx) throw new Error("AccordionItem must be used within "); const isOpen = ctx.open.includes(value); const Heading = `h${ctx.level}` as const; const buttonId = `mizu-acc-${id}-btn`; const panelId = `mizu-acc-${id}-panel`; return (
{isOpen && (
{children}
)}
); }