# useTableTreeState

## Usage

State management companion for `useTableTreeData`. Owns the expanded set (controlled or uncontrolled) and flattens nested data into the visible row array; collapsed subtrees are unmounted, not hidden, so the table body contains exactly the visible rows. Returns `expandAll` / `collapseAll` helpers, the aggregate `isAllExpanded` state (true/false/indeterminate) for a header expand-all control, and a ready-to-use `plugin` for the tree. Note: because collapsed rows unmount, local component state inside collapsed subtrees is lost on collapse; lift state that must survive.

```ts
import { useTableTreeState } from '@astryx-vue/core/Table'
```

## Examples

### useTableTreeState — Tree Table

Nested rows are flattened into the visible rows, and the expanded set lives in the hook. The header control expands every branch, and a row click expands a node that has children.

```vue
<script setup lang="ts">
import type { TableColumn } from '@astryx-vue/core/Table'
import { proportional, Table, useTableTreeState } from '@astryx-vue/core/Table'

interface Node extends Record<string, unknown> {
  id: string
  name: string
  owner: string
  children?: Node[]
}

const nodes: Node[] = [
  {
    id: 'platform',
    name: 'Platform',
    owner: 'Ada',
    children: [
      { id: 'api', name: 'API', owner: 'Grace' },
      {
        id: 'web',
        name: 'Web',
        owner: 'Lin',
        children: [
          { id: 'docs', name: 'Docs', owner: 'Maya' },
        ],
      },
    ],
  },
  { id: 'design', name: 'Design', owner: 'Noah' },
]

const columns: TableColumn<Node>[] = [
  { key: 'name', header: 'Name', width: proportional(2) },
  { key: 'owner', header: 'Owner', width: proportional(1) },
]

const { visibleData, plugin: treePlugin } = useTableTreeState<Node>({
  data: nodes,
  idKey: 'id',
  defaultExpandedIds: ['platform'],
  hasExpandAllControl: true,
  hasRowClickExpansion: true,
})
</script>

<template>
  <Table
    :data="visibleData"
    :columns="columns"
    id-key="id"
    has-hover
    :plugins="{ tree: treePlugin }"
  />
</template>
```

## Properties

`data` is a `MaybeRefOrGetter`; pass a getter or a ref when the tree can change. The other fields are read from the config object you pass.

## Parameters

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `data` | `MaybeRefOrGetter<readonly T[]>` | — | Nested data: rows may carry child rows under `childrenKey`. Flat data (no children anywhere) makes the plugin a no-op, so it can be adopted before the data becomes hierarchical. |
| `idKey` | `(keyof T & string) \| ((item: T) => string \| number)` | — | Row ID accessor: property name or function returning a unique id. |
| `childrenKey` | `string` | `'children'` | Property holding each row's children array. |
| `defaultExpandedIds` | `Iterable<string>` | — | Initial expanded row ids for uncontrolled mode, read once at setup. Ignored when `expandedIds` is provided. |
| `expandedIds` | `ReadonlySet<string>` | — | Controlled set of expanded row ids. Pair with `onExpandedIdsChange`. |
| `onExpandedIdsChange` | `(ids: ReadonlySet<string>) => void` | — | Called with the next expanded set whenever expansion changes (both modes). In lazy-loading setups, trigger the children fetch here. |
| `isItemExpandable` | `(item: T) => boolean` | non-empty children | Should this row show an expander? Overrides the default non-empty-children check; use for lazy loading, where a row is expandable before its children have been fetched. |
| `sortSiblings` | `(siblings: T[]) => T[]` | — | Sort each sibling group independently during flattening; children always stay directly under their parent. Use it to compose column sorting with the tree order. |
| `indent` | `'sm' \| 'md' \| 'lg'` | `'md'` | Indent step per level (spacing-3 / spacing-4 / spacing-6), forwarded to `useTableTreeData`. |
| `treeColumnKey` | `string` | the first column no plugin added | Column that carries the indent + expander, forwarded to `useTableTreeData`. |
| `hasExpandAllControl` | `boolean` | `false` | Show the expand-all/collapse-all toggle in the tree column header. |
| `hasRowClickExpansion` | `boolean` | `false` | Let a click anywhere on an expandable row toggle it, forwarded to `useTableTreeData`. |

## Returns

| Field | Type | Description |
| --- | --- | --- |
| `visibleData` | `ComputedRef<T[]>` | The rows to render, parents followed by the children of expanded rows. Pass it as `data` to the table. |
| `plugin` | `TablePlugin` | The tree plugin, already wired to the visible rows and the expanded set. Put it under any key of the `plugins` prop. |
| `expandedIds` | `ComputedRef<ReadonlySet<string>>` | The expanded set in use: your controlled value, or the internal one. |
| `isAllExpanded` | `ComputedRef<boolean \| 'indeterminate'>` | Aggregate expansion state over every expandable row. |
| `expandAll` | `() => void` | Expands every expandable row and reports the new set through `onExpandedIdsChange`. |
| `collapseAll` | `() => void` | Collapses every row and reports the empty set through `onExpandedIdsChange`. |
