import React, { useState, useEffect } from 'react';
import { TocItem } from '@/lib/toc';
import { cn } from '@/lib/utils';
import { ChevronRight, ChevronDown, Circle } from 'lucide-react';
interface TableOfContentsListProps {
toc: TocItem[];
depth?: number;
isMobile?: boolean;
activeId?: string;
defaultOpen?: boolean;
}
export function TableOfContentsList({
toc,
depth = 0,
isMobile = false,
activeId,
defaultOpen = false
}: TableOfContentsListProps) {
if (!toc || toc.length === 0) return null;
return (
0 && !isMobile ? "border-l border-border ml-[11px] pl-2" : "" // Vertical guide line
)}>
{toc.map((heading, index) => (
))}
);
}
function TocItemRenderer({
heading,
depth,
isMobile,
activeId,
defaultOpen
}: {
heading: TocItem,
depth: number,
isMobile: boolean,
activeId?: string,
defaultOpen: boolean
}) {
const [isOpen, setIsOpen] = useState(defaultOpen || depth < 1); // Expand root items by default
const hasChildren = heading.children.length > 0;
// Check if this item matches active ID directly
const isActive = activeId === heading.slug;
const itemRef = React.useRef(null);
React.useEffect(() => {
if (isActive && itemRef.current) {
itemRef.current.scrollIntoView({ behavior: 'smooth', block: 'nearest' });
}
}, [isActive]);
// Check if any child is active (to auto-expand)
const isChildActive = React.useMemo(() => {
const checkActive = (items: TocItem[]): boolean => {
return items.some(item => item.slug === activeId || checkActive(item.children));
};
return checkActive(heading.children);
}, [heading.children, activeId]);
useEffect(() => {
if (isChildActive || defaultOpen) {
setIsOpen(true);
}
}, [isChildActive, defaultOpen]);
const handleToggle = (e: React.MouseEvent) => {
if (hasChildren) {
e.preventDefault();
e.stopPropagation();
setIsOpen(!isOpen);
}
};
return (
{hasChildren && isOpen && (
)}
);
}