, parentPath: string = ''): FileNode[] {
+ return nodes.map(node => {
+ const currentPath = parentPath ? `${parentPath}/${node.name}` : node.name;
+ const desc = descriptions[currentPath] || descriptions[node.name];
+
+ const newNode = { ...node };
+ if (desc) {
+ newNode.description = desc;
+ }
+
+ if (newNode.children) {
+ newNode.children = injectDescriptions(newNode.children, descriptions, currentPath);
+ }
+
+ return newNode;
+ });
+}
+
+const startViewTransition = (callback: () => void) => {
+ if (typeof document !== 'undefined' && 'startViewTransition' in document) {
+ (document as any).startViewTransition(() => {
+ flushSync(callback);
+ });
+ } else {
+ callback();
+ }
+};
+
+const getIconColorClass = (hasChildren: boolean, isExplicitFolder: boolean | undefined, iconType: any) => {
+ if (hasChildren || isExplicitFolder || iconType === FolderOutlined || iconType === FolderOpenOutlined) {
+ return "text-[var(--ifm-color-primary)]";
+ }
+ return "text-[var(--ifm-color-emphasis-700)]";
+};
+
+const NodeItem = React.memo(({
+ node,
+ path,
+ onSelect,
+ selectedPath,
+}: {
+ node: FileNode;
+ path: string;
+ onSelect: (path: string) => void;
+ selectedPath: string | null;
+}): React.ReactElement => {
+ const currentPath = `${path}/${node.name}`;
+ const hasChildren = Boolean(node.children && node.children.length);
+ const hasDescription = Boolean(node.description);
+ const isExplicitFolder = node.isFolder;
+
+ const [expanded, setExpanded] = useState(true);
+ const [showDesc, setShowDesc] = useState(false);
+
+ const handleMainClick = (e: React.MouseEvent) => {
+ e.stopPropagation();
+ onSelect(currentPath);
+
+ startViewTransition(() => {
+ if (hasChildren) {
+ setExpanded(prev => !prev);
+ }
+ if (hasDescription) {
+ setShowDesc(prev => !prev);
+ }
+ });
+ };
+
+ const handleChevronClick = (e: React.MouseEvent) => {
+ e.stopPropagation();
+ startViewTransition(() => {
+ setExpanded(prev => !prev);
+ });
+ };
+
+ let Icon = node.icon;
+ if (!Icon) {
+ if (hasChildren) {
+ Icon = expanded ? : ;
+ } else if (isExplicitFolder) {
+ Icon = ;
+ } else {
+ Icon = getIcon(node.name);
+ }
+ }
+
+ const isSelected = selectedPath === currentPath;
+ const iconColorClass = getIconColorClass(hasChildren, isExplicitFolder, (Icon as React.ReactElement)?.type);
+
+ return (
+
+
+
+ {hasChildren && (
+ expanded ? :
+ )}
+
+
+
+ {Icon}
+
+
+
+ {node.name}
+
+ {node.comment && (
+
+ // {node.comment}
+
+ )}
+ {hasDescription && (
+
+ )}
+
+
+ {hasDescription && showDesc && (
+
+ {node.description}
+
+ )}
+
+ {hasChildren && expanded && (
+
+ {node.children!.map((child) => (
+
+ ))}
+
+ )}
+
+ );
+});
+
+NodeItem.displayName = 'NodeItem';
+
+export function FileTree({ nodes, children, descriptions }: FileTreeProps): React.ReactElement {
+ const [selectedPath, setSelectedPath] = useState(null);
+
+ const treeData = useMemo(() => {
+ if (nodes) return nodes;
+ if (typeof children === 'string') {
+ const parsed = parseTreeString(children);
+ if (descriptions) {
+ return injectDescriptions(parsed, descriptions);
+ }
+ return parsed;
+ }
+ return [];
+ }, [nodes, children, descriptions]);
+
+ const handleSelect = useCallback((path: string) => {
+ setSelectedPath(path);
+ }, []);
+
+ return (
+
+
+ {treeData.map((node) => (
+
+ ))}
+
+
+ );
+}