"use client"; import {Accordion as BaseAccordion} from "@base-ui/react/accordion"; import {mergeProps} from "@base-ui/react/merge-props"; import {useRender} from "@base-ui/react/use-render"; import {ChevronDown} from "lucide-react"; import * as React from "react"; import {cn} from "@/lib/utilities"; import styles from "./accordion.module.css"; type AccordionRootBaseProps = Omit< React.ComponentPropsWithRef, "defaultValue" | "multiple" | "onValueChange" | "value" | "className" >; /** * Props for the single-item accordion root wrapper. */ interface AccordionSingleProps extends AccordionRootBaseProps { /** Controls whether the accordion only allows one item to be expanded at a time. @default "single" */ type?: "single"; /** Legacy compatibility flag accepted by the wrapper but not forwarded to Base UI. @default undefined */ collapsible?: boolean; /** Additional CSS classes merged with the accordion root styles. @default undefined */ className?: string; /** The initially expanded item value in uncontrolled single mode. @default undefined */ defaultValue?: string; /** Called when the expanded item changes in single mode. @default undefined */ onValueChange?: (value: string | undefined, eventDetails: unknown) => void; /** The controlled expanded item value in single mode. @default undefined */ value?: string; } /** * Props for the multi-item accordion root wrapper. */ interface AccordionMultipleProps extends AccordionRootBaseProps { /** Controls whether the accordion allows multiple items to stay expanded. @default "multiple" */ type: "multiple"; /** Legacy compatibility flag accepted by the wrapper but not forwarded to Base UI. @default undefined */ collapsible?: boolean; /** Additional CSS classes merged with the accordion root styles. @default undefined */ className?: string; /** The initially expanded item values in uncontrolled multi mode. @default undefined */ defaultValue?: string[]; /** Called when the expanded item values change in multi mode. @default undefined */ onValueChange?: (value: string[], eventDetails: unknown) => void; /** The controlled expanded item values in multi mode. @default undefined */ value?: string[]; } type AccordionSingleRootProps = Omit; type AccordionMultipleRootProps = Omit; /** * Props for an accordion item wrapper. */ interface AccordionItemProps extends Omit, "className"> { /** Additional CSS classes merged with the accordion item styles. @default undefined */ className?: string; } /** * Props for an accordion trigger wrapper. */ interface AccordionTriggerProps extends Omit, "className"> { /** Additional CSS classes merged with the accordion trigger styles. @default undefined */ className?: string; } /** * Props for an accordion content wrapper. */ interface AccordionContentProps extends Omit, "className"> { /** Additional CSS classes merged with the accordion content styles. @default undefined */ className?: string; } /** * Groups disclosure items into a styled accordion container. * * @remarks * - Renders a `
` element by default * - Built on {@link https://base-ui.com/react/components/accordion | Base UI Accordion} * - Supports the `render` prop for element composition * - Styling via CSS Modules with `--ac-*` custom properties * * @example Basic usage * ```tsx * * * Section * Content * * * ``` * * @see {@link https://base-ui.com/react/components/accordion | Base UI Documentation} */ function Accordion(props: Readonly): React.ReactElement { const {className, render, type = "single"} = props; const accordionRender = useRender({ defaultTagName: "div", render: render as never, props: mergeProps({className: cn(className)}, {}), }); if (type === "multiple") { const {defaultValue, onValueChange, value, ...otherProps} = omitAccordionWrapperProps(props) as AccordionMultipleRootProps; return ( ); } const {defaultValue, onValueChange, value, ...otherProps} = omitAccordionWrapperProps(props) as AccordionSingleRootProps; return ( { onValueChange?.(nextValue[0], eventDetails); }} value={value ? [value] : undefined} {...otherProps} render={accordionRender} /> ); } Accordion.displayName = "Accordion"; function omitAccordionWrapperProps(props: Accordion.Props): AccordionSingleRootProps | AccordionMultipleRootProps { const rootProps: Partial = {...props}; Reflect.deleteProperty(rootProps, "className"); Reflect.deleteProperty(rootProps, "collapsible"); Reflect.deleteProperty(rootProps, "render"); Reflect.deleteProperty(rootProps, "type"); return rootProps as AccordionSingleRootProps | AccordionMultipleRootProps; } /** * Wraps a single accordion item with shared border and spacing styles. * * @remarks * - Renders a `
` element by default * - Built on {@link https://base-ui.com/react/components/accordion | Base UI Accordion} * - Supports the `render` prop for element composition * - Styling via CSS Modules with `--ac-*` custom properties * * @example Basic usage * ```tsx * * Section * Content * * ``` * * @see {@link https://base-ui.com/react/components/accordion | Base UI Documentation} */ function AccordionItem(props: Readonly): React.ReactElement { const {className, children, render, ...otherProps} = props; return ( {children} ); } AccordionItem.displayName = "AccordionItem"; /** * Toggles an accordion item while rendering the chevron affordance. * * @remarks * - Renders a `