import { createContext, useContext, useState, ReactNode, } from 'react'; type AccordionCtx = { openId: string | null; setOpenId: (id: string | null) => void; }; const AccordionContext = createContext<AccordionCtx | null>(null); const ItemContext = createContext<string | null>(null); function useAccordion(): AccordionCtx { const ctx = useContext(AccordionContext); if (!ctx) throw new Error('Accordion.* must be used within <Accordion>'); return ctx; } function useItemId(): string { const id = useContext(ItemContext); if (id == null) throw new Error('Header/Panel must be inside Accordion.Item'); return id; } export function Accordion({ defaultOpen = null, children, }: { defaultOpen?: string | null; children: ReactNode; }) { // TODO: openId 상태를 useState로 만들고 AccordionContext.Provider로 children을 감싸세요 return <>{children}</>; } function Item({ id, children }: { id: string; children: ReactNode }) { // TODO: ItemContext.Provider value={id} 로 children을 감싸세요 return <div>{children}</div>; } function Header({ children }: { children: ReactNode }) { // TODO: useAccordion()과 useItemId()를 호출 // TODO: 클릭 시 자기 id가 openId면 null로, 아니면 자기 id로 setOpenId return <button type="button">{children}</button>; } function Panel({ children }: { children: ReactNode }) { // TODO: useAccordion()과 useItemId()를 호출, openId === id 일 때만 children을 렌더 return null; } Accordion.Item = Item; Accordion.Header = Header; Accordion.Panel = Panel;
Tests