"use client"; import { Children, Fragment, cloneElement, isValidElement, type ReactElement, type ReactNode, } from "react"; import { cx } from "../../utils"; import type { FoxBulletLevel, FoxBulletListItemProps } from "../fox-bullet-list-item"; export interface FoxBulletListProps { /** `FoxBulletListItem`들. 단계는 평평하게 늘어놓고 각 항목의 `level`로 적는다. */ children: ReactNode; /** 참이면 번호 목록(`1.` · `a.` · `①`)이 되고, 아니면 기호 목록이다. */ ordered?: boolean; /** 참이면 렌더하지 않는다(DOM에 남지 않는다). */ hidden?: boolean; /** 배치 조정용. */ className?: string; } type ItemElement = ReactElement; type Entry = { level: FoxBulletLevel; element: ItemElement }; /** Fragment로 감싸 넘겨도 안쪽 항목까지 찾아낸다. */ function collect(children: ReactNode): Entry[] { const entries: Entry[] = []; Children.forEach(children, (child) => { if (!isValidElement(child)) { return; } if (child.type === Fragment) { const fragment = child as ReactElement<{ children?: ReactNode }>; entries.push(...collect(fragment.props.children)); return; } const element = child as ItemElement; entries.push({ level: element.props.level ?? 1, element }); }); return entries; } /** * 평평한 단계 목록을 진짜 중첩으로 접는다. * * 더 깊은 항목들은 바로 앞 항목 **안쪽** 목록이 된다 — `