# `PhiaUi.Components.TreeEnhanced`
[🔗](https://github.com/charlenopires/PhiaUI/blob/v0.1.17/lib/phia_ui/components/data/tree_enhanced.ex#L1)

Enhanced tree view components for PhiaUI.

10 components extending the base `tree/1` and `tree_item/1` with icons,
tri-state checkboxes, file-system display, search filtering, lazy loading,
and virtual rendering for large datasets.

## Component Overview

| Component          | Tier           | Key Feature                              |
|--------------------|----------------|------------------------------------------|
| `icon_tree`        | `:widget`      | Tree root with icon support              |
| `icon_tree_item`   | `:widget`      | Leaf/branch + Lucide icon + badge        |
| `checkbox_tree`    | `:interactive` | Tri-state checkbox tree root             |
| `checkbox_tree_item` | `:interactive` | Checkbox item with indeterminate state |
| `searchable_tree`  | `:widget`      | Tree with search input above             |
| `file_tree`        | `:widget`      | File-system display tree root            |
| `file_tree_item`   | `:widget`      | File/folder item with extension icon     |
| `lazy_tree`        | `:interactive` | Tree root with lazy-load hook            |
| `lazy_tree_item`   | `:interactive` | Item with loading/loaded states          |
| `virtual_tree`     | `:widget`      | Hook-owned virtual rendering tree        |

## Hooks required

- `PhiaCheckboxTree` — checkbox_tree, checkbox_tree_item (sets `.indeterminate`)
- `PhiaLazyTree` — lazy_tree, lazy_tree_item (fires expand events)
- `PhiaVirtualTree` — virtual_tree (owns DOM rendering)

# `checkbox_tree`

Checkbox tree root. Requires `PhiaCheckboxTree` hook to set the
`.indeterminate` JS property on items with `data-indeterminate="true"`.

## Example

    <.checkbox_tree id="permission-tree">
      <.checkbox_tree_item
        id="perm-read"
        label="Read"
        checked={:read in @permissions}
        on_check="toggle_permission"
        value="read"
      />
    </.checkbox_tree>

## Attributes

* `id` (`:string`) (required) - Unique ID (required for phx-hook).
* `class` (`:string`) - Defaults to `nil`.
* Global attributes are accepted.
## Slots

* `inner_block` (required)

# `checkbox_tree_item`

Checkbox tree item with tri-state support.

The `.indeterminate` JS property is set by the `PhiaCheckboxTree` hook on
`mounted()` and `updated()` when `data-indeterminate="true"`.

## Example

    <.checkbox_tree_item
      id="item-files"
      label="Files"
      checked={:files in @checked}
      indeterminate={has_partial_check?(@checked, @file_ids)}
      on_check="toggle_perm"
      value="files"
    >
      <.checkbox_tree_item id="item-read" label="Read" checked={:read in @checked} />
    </.checkbox_tree_item>

## Attributes

* `id` (`:string`) (required) - Unique ID for the checkbox element.
* `label` (`:string`) (required)
* `checked` (`:boolean`) - Defaults to `false`.
* `indeterminate` (`:boolean`) - Server-computed partial-check state. Defaults to `false`.
* `on_check` (`:string`) - phx-click event name. Defaults to `"check_tree_item"`.
* `value` (`:string`) - phx-value-value sent on check. Defaults to `nil`.
* `depth` (`:integer`) - Indentation depth (multiplied by ml-4). Defaults to `0`.
* `class` (`:string`) - Defaults to `nil`.
## Slots

* `inner_block`

# `file_tree`

File-system display tree root.

## Example

    <.file_tree id="project-files">
      <.file_tree_item label="src" type={:folder} expanded={true}>
        <.file_tree_item label="app.ex" type={:file} />
      </.file_tree_item>
    </.file_tree>

## Attributes

* `id` (`:string`) (required)
* `class` (`:string`) - Defaults to `nil`.
* Global attributes are accepted.
## Slots

* `inner_block` (required)

# `file_tree_item`

File or folder tree item with extension-based icon.

Folders show a folder icon and use `<details>/<summary>`.
Files show a file-type icon based on their extension.

## Example

    <.file_tree_item label="mix.exs" type={:file} on_click="open" value="mix.exs" />

    <.file_tree_item label="lib" type={:folder} expanded={true}>
      <.file_tree_item label="app.ex" type={:file} />
    </.file_tree_item>

## Attributes

* `label` (`:string`) (required) - File or folder name.
* `type` (`:atom`) - Item type. Defaults to `:file`. Must be one of `:file`, or `:folder`.
* `expanded` (`:boolean`) - Defaults to `false`.
* `selected` (`:boolean`) - Defaults to `false`.
* `size` (`:string`) - Optional file size string (e.g. '4.2 KB'). Defaults to `nil`.
* `modified` (`:string`) - Optional last-modified string. Defaults to `nil`.
* `on_click` (`:string`) - Defaults to `nil`.
* `value` (`:string`) - Defaults to `nil`.
* `class` (`:string`) - Defaults to `nil`.
## Slots

* `inner_block`

# `icon_tree`

Tree root with icon-item support.

## Example

    <.icon_tree id="nav-tree">
      <.icon_tree_item label="Components" icon="layers" expandable={true}>
        <.icon_tree_item label="Button" icon="square" />
      </.icon_tree_item>
    </.icon_tree>

## Attributes

* `id` (`:string`) (required)
* `class` (`:string`) - Defaults to `nil`.
* Global attributes are accepted.
## Slots

* `inner_block` (required)

# `icon_tree_item`

Tree item with optional icon, badge, href, and expandable branch support.

Uses `<details>/<summary>` for branches (zero-JS expand/collapse).
Disabled items are non-interactive and visually dimmed.

## Example

    <.icon_tree_item label="Settings" icon="settings" on_click="nav" value="settings" />

    <.icon_tree_item label="src" icon="folder" expandable={true} expanded={true}>
      <.icon_tree_item label="app.ex" icon="file-code" />
    </.icon_tree_item>

## Attributes

* `label` (`:string`) (required)
* `icon` (`:string`) - Lucide icon name shown before the label. Defaults to `nil`.
* `badge` (`:string`) - Optional badge text. Defaults to `nil`.
* `badge_variant` (`:string`) - Badge color variant string. Defaults to `"secondary"`.
* `href` (`:string`) - When set, renders label as `<a>` link. Defaults to `nil`.
* `expandable` (`:boolean`) - Defaults to `false`.
* `expanded` (`:boolean`) - Defaults to `false`.
* `selected` (`:boolean`) - Defaults to `false`.
* `disabled` (`:boolean`) - Defaults to `false`.
* `on_click` (`:string`) - Defaults to `nil`.
* `value` (`:string`) - Defaults to `nil`.
* `class` (`:string`) - Defaults to `nil`.
## Slots

* `inner_block`

# `lazy_tree`

Tree root with lazy-load support via the `PhiaLazyTree` hook.

When a `lazy_tree_item` is expanded by the user, the hook fires
`push_event(@on_expand, %{"id" => item_id})` to the LiveView, which
can load children and update the item's `loaded` assign.

## Example

    <.lazy_tree id="repo-tree" on_expand="load_children">
      <.lazy_tree_item id="src" label="src" expandable={true} loaded={@src_loaded}>
        <.lazy_tree_item :for={f <- @src_files} id={f.id} label={f.name} />
      </.lazy_tree_item>
    </.lazy_tree>

## Attributes

* `id` (`:string`) (required) - Unique ID (required for phx-hook).
* `on_expand` (`:string`) - push_event name when a node expands. Defaults to `"tree_expand"`.
* `class` (`:string`) - Defaults to `nil`.
* Global attributes are accepted.
## Slots

* `inner_block` (required)

# `lazy_tree_item`

Lazy tree item. Fires an expand event to load children on first open.

When `loading` is `true`, shows a spinner instead of children.
When `loaded` is `true`, children are rendered normally.

## Example

    <.lazy_tree_item id="src-dir" label="src" expandable={true} loaded={@src_loaded} loading={@src_loading}>
      <.lazy_tree_item :for={f <- @src_files} id={f.id} label={f.name} />
    </.lazy_tree_item>

## Attributes

* `id` (`:string`) (required) - Node ID sent to the hook on expand.
* `label` (`:string`) (required)
* `expandable` (`:boolean`) - Defaults to `false`.
* `expanded` (`:boolean`) - Defaults to `false`.
* `loading` (`:boolean`) - Shows a spinner while children load. Defaults to `false`.
* `loaded` (`:boolean`) - When true, children are present and loading is done. Defaults to `false`.
* `class` (`:string`) - Defaults to `nil`.
## Slots

* `inner_block`

# `searchable_tree`

Tree with a search input above. Filtering logic lives in the LiveView.

The search input fires `on_search` with `phx-debounce="200"`. Your
LiveView filters the tree data and re-renders only matching items.

## Example

    <.searchable_tree id="file-search" on_search="filter_files" search_value={@search}>
      <.icon_tree_item :for={file <- @filtered_files} label={file.name} icon="file" />
    </.searchable_tree>

## Attributes

* `id` (`:string`) (required)
* `search_placeholder` (`:string`) - Defaults to `"Search..."`.
* `on_search` (`:string`) - phx-change event for search input. Defaults to `"search_tree"`.
* `search_value` (`:string`) - Current search value for controlled input. Defaults to `""`.
* `class` (`:string`) - Defaults to `nil`.
## Slots

* `inner_block` (required)

# `virtual_tree`

Virtual-rendered tree for large datasets (1000+ nodes).

The `PhiaVirtualTree` hook owns the DOM — only visible rows are rendered.
Initial node data is passed as `data-nodes` JSON; subsequent updates are
sent via `push_event("update-nodes", %{nodes: [...]})`.

Use `phx-update="ignore"` (set automatically) to prevent LiveView from
reconciling the hook-managed DOM.

## Example

    <.virtual_tree
      id="large-tree"
      nodes={@flat_nodes}
      row_height={28}
      height={500}
    />

## LiveView update

    {:noreply, push_event(socket, "update-nodes", %{nodes: flat_nodes})}

## Attributes

* `id` (`:string`) (required) - Unique ID (required for phx-hook).
* `nodes` (`:list`) (required) - Flat list of node maps with :id, :label, :depth, :expandable, :expanded.
* `row_height` (`:integer`) - Height of each rendered row in pixels. Defaults to `32`.
* `height` (`:integer`) - Container height in pixels (viewport). Defaults to `400`.
* `class` (`:string`) - Defaults to `nil`.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
