# tp-tree-nav `tp-tree-nav` is a low-level, virtualized tree renderer for Lit. It is intentionally “dumb”: it only renders what it is given and emits events. Parents own all state (expanded/selected/custom), perform mutations, and pass updated data back in. This makes it a flexible foundation for building higher-level trees (e.g., VS Code–style explorer, Git ignore/selected indicators, custom icon trees). ## Key ideas - **Multiple roots**: pass a `roots` array; each node may have `children`. - **Virtualized list**: uses `@lit-labs/virtualizer` to render a flat, indented list for large trees. - **Events only**: emits `node-click`, `node-context`, and `node-action` (for chevron toggle and context menu actions). Every event includes `originalEvent` so parents can cancel or coordinate. - **Opt-in actions**: provide `defaultActions` (array of action objects), and per-node `actions`; node actions override defaults on the same `action` key. Use `beforeContextMenu(node, actions)` to modify or block the menu. - **Custom render**: `renderNode(node, meta)` lets you override row rendering (e.g., icons per node type, state-based styling). Common states like `expanded`/`collapsed` are parent-managed via `node.states`. - **Helper methods (pure)**: `getNodesWithState`, `clearState`, `applyStateIf` return data; they don’t mutate internal state—parents update `roots`. - **Default icons**: `chevron`, `folder`, `file` are available via `tp-icon`; pass string keys or custom icons. ## Usage example ```js import './tp-tree-nav.js'; const tree = document.querySelector('tp-tree-nav'); const roots = [ { label: 'Project A', slug: 'project-a', states: ['expanded'], icon: 'folder', children: [ { label: 'main.js', slug: 'main-js', icon: 'file', states: [] }, { label: 'src', slug: 'src', icon: 'folder', states: ['expanded'], children: [ { label: 'index.js', slug: 'index-js', icon: 'file', states: [] }, ], }, ], }, ]; tree.roots = roots; tree.defaultActions = [ { label: 'Rename', action: 'rename', icon: 'pencil' }, { label: 'Delete', action: 'delete', icon: 'delete' }, ]; tree.beforeContextMenu = (node, actions) => { // Example: hide delete on roots if (node.slug === 'project-a') { return actions.filter((a) => a.action !== 'delete'); } return actions; }; tree.renderNode = (node, { depth, states, path, hasChildren }) => { const selected = states.includes('selected'); return html`