Renders a recursive, multi-level document tree navigation UI with support for both desktop sidebar and mobile dropdown layouts, handling folder/file selection state with a folder-index (README) convention. ## Key Components ### Exports | Name | Type | Description | |------|------|-------------| | `NavigationNode` | Interface | Tree node shape (file or folder) compatible with `DocNode` for type-safe assignment | | `MultiLevelNavigation` | Component | Desktop sidebar navigation with recursive expand/collapse and visual selection ribbon | | `MobileNavigationDropdown` | Component | Compact mobile variant of the navigation tree | ### Internal | Name | Description | |------|-------------| | `isNodeVisuallySelected` | Pure function implementing the folder-with-README selection convention — the folder node is never visually selected; its README child is | | `NavigationItem` | Recursive desktop tree node (file icon, folder icon, expand chevron, selection ribbon) | | `MobileNavigationItem` | Recursive mobile tree node (slightly smaller hit targets) | ### Props (`MultiLevelNavigationProps`) | Prop | Type | Description | |------|------|-------------| | `nodes` | `NavigationNode[]` | Root-level tree nodes | | `selectedPath` | `string` | Currently active document path | | `expandedNodes` | `Set` | Set of expanded folder node IDs | | `onNodeClick` | `(node) => void` | Called on node selection | | `onToggleExpand` | `(nodeId) => void` | Optional separate expand handler | | `folderIndexFile` | `string` | Folder-index filename, defaults to `'README.md'` | ## Usage Example ```typescript import { MultiLevelNavigation, MobileNavigationDropdown } from './multi-level-navigation' import type { NavigationNode } from './multi-level-navigation' import { useState } from 'react' const tree: NavigationNode[] = [ { id: 'docs', name: 'Docs', path: 'docs', type: 'folder', hasReadme: true, children: [ { id: 'docs/README.md', name: 'README', path: 'docs/README.md', type: 'file' }, { id: 'docs/setup.md', name: 'Setup', path: 'docs/setup.md', type: 'file' }, ], }, ] export function Sidebar() { const [selectedPath, setSelectedPath] = useState('') const [expandedNodes, setExpandedNodes] = useState>(new Set(['docs'])) return ( setSelectedPath(node.path)} onToggleExpand={(id) => setExpandedNodes(prev => { const next = new Set(prev) next.has(id) ? next.delete(id) : next.add(id) return next }) } /> ) } ``` > **Folder-index convention:** When `selectedPath` points to a folder that has a README, the visual selection ribbon renders on the README child, not the folder row itself.