import type { ElementType, HTMLAttributes, ReactElement } from 'react'
import React, { createContext, forwardRef, useContext } from 'react'
import type {
PolymorphicComponentPropsWithRef,
PolymorphicRef,
} from '../../typings'
interface AccordionItemContext {
index: number
panel: string
button: string
prefixId: string
}
const AccordionItemContext = createContext(
undefined
)
interface Props extends HTMLAttributes {
/**
* ID to find this component in testing tools (e.g.: cypress,
* testing-library, and jest).
*/
testId?: string
/**
* Index of the current accordion item within the accordion.
*/
index?: number
/**
* Namespace ID prefix for the current Accordion item's panel and button
* to avoid ID duplication when multiple instances are on the same page.
*/
prefixId?: string
}
export type AccordionItemProps =
PolymorphicComponentPropsWithRef
type AccordionItemComponent = (
props: AccordionItemProps
) => ReactElement | null
const AccordionItem = forwardRef<
HTMLDivElement,
Omit, 'ref'>
>(function AccordionItem(
{
prefixId = '',
index = 0,
as: MaybeComponent,
children,
testId = 'fs-accordion-item',
...otherProps
}: AccordionItemProps,
ref: PolymorphicRef
) {
const Component = MaybeComponent ?? 'div'
const context = {
index,
prefixId,
panel: `${prefixId && `${prefixId}-`}panel--${index}`,
button: `${prefixId && `${prefixId}-`}button--${index}`,
}
return (
{children}
)
}) as AccordionItemComponent
export function useAccordionItem() {
const context = useContext(AccordionItemContext)
if (context === undefined) {
throw new Error(
'Do not use AccordionItem components outside the AccordionItem context.'
)
}
return context
}
export default AccordionItem