# rn-tree-table URL: /docs/native/docyrus/tree-table Hierarchical table with a pinned name column, horizontally scrolling data columns, search, expand / collapse all and a "Move to…" sheet — API-aligned with the web TreeTable. ## Installation ```bash pnpm dlx @docyrus/cli add @docyrus/rn-tree-table ``` **Dependencies:** - [@shopify/flash-list](https://www.npmjs.com/package/@shopify/flash-list) - [react-native-reanimated](https://www.npmjs.com/package/react-native-reanimated) - [tailwind-variants](https://www.npmjs.com/package/tailwind-variants) ## Usage ```tsx import { useState } from 'react'; import { StatusChip } from '@/components/docyrus-native/status-chip'; import { TreeTable, type TreeTableColumn } from '@/components/docyrus-native/tree-table'; import { type TreeViewItem } from '@/components/docyrus-native/tree-view'; const columns: TreeTableColumn[] = [ { id: 'status', header: 'Status', width: 130, cell: item => }, { id: 'owner', header: 'Owner', accessorKey: 'owner', width: 160 }, { id: 'progress', header: 'Progress', accessorKey: 'progress', width: 100, align: 'right' } ]; export function ProjectTree({ initial }: { initial: TreeViewItem[] }) { const [data, setData] = useState(initial); return ( item.type !== 'task'} maxHeight={420} onDataChange={nextData => setData(nextData)} /> ); } ``` ### Layout and interaction - Rows are the **flattened visible tree** rendered by a `FlashList` with fixed row heights. The name column plus all data columns sit inside one horizontal `ScrollView`; with `stickyNameColumn` (default) the name cells are translated by the horizontal scroll offset (reanimated), so the hierarchy stays visible while the data columns scroll underneath. - Tapping the chevron expands / collapses a folder. Tapping a row calls `onRowPress`; without `onRowPress` a folder row toggles itself. - The options button next to the search opens **Expand All / Collapse All** (hidden with `showExpandAll={false}`). Searching filters by name and opens matching branches. - `draggable` replaces web drag-and-drop with a **"Move to…" sheet** (long-press drag inside nested, horizontally scrolling rows is unreliable on a phone). Each row gets a `…` button (long-press works too); the sheet lists every valid target (the moved item and its subtree are excluded) plus **Top level**, and offers **Before / Inside / After** — *Inside* only when `canDropInside(target)` allows. The move goes through `moveTreeViewItem` and fires `onDataChange(nextData, details)` exactly like web. Moving is disabled while a search query is active, and items with `draggable: false` get no `…` button. ## API Reference ### TreeTableProps | Prop | Type | Default | Description | |------|------|---------|-------------| | `data` | `TreeViewItem[]` | - | Tree rows. The table keeps an internal copy (so moves apply immediately) that is re-seeded whenever `data` changes | | `columns` | `TreeTableColumn[]` | - | Data columns rendered after the name column | | `variant` | `'default' \| 'outline' \| 'ghost'` | `'default'` | Container style (`treeViewVariants`) | | `size` | `'sm' \| 'default' \| 'lg'` | `'default'` | Row height (36 / 44 / 52) and text size | | `nameColumnHeader` | `ReactNode` | `t('ui.treeTable.name', 'Name')` | Header of the name column | | `nameColumnWidth` | `number` | `200` | Name column width in dp (native addition) | | `getIcon` | `(item: TreeViewItem, depth: number) => ReactNode` | - | Icon rendered before the name | | `showExpandAll` | `boolean` | `true` | Show the options button with Expand All / Collapse All | | `searchPlaceholder` | `string` | `t('ui.treeView.searchPlaceholder', 'Search...')` | Search placeholder | | `emptyText` | `string` | `t('ui.treeView.noItemsFound', 'No items found')` | Text when no rows match | | `draggable` | `boolean` | `false` | Adds the row `…` button / long-press that opens the "Move to…" sheet | | `canDropInside` | `(item: TreeViewItem) => boolean` | `canTreeViewItemAcceptChildren` | Whether an item accepts children (the *Inside* position) | | `onDataChange` | `(nextData: TreeViewItem[], details: TreeViewMoveDetails) => void` | - | Tree changed by a move | | `maxHeight` | `number \| string` | - | Max height (dp or `'Npx'`) before rows scroll vertically; without it every row renders at full height | | `onRowPress` | `(item: TreeViewItem) => void` | - | Row tapped (native addition). Without it, a folder row tap toggles the folder | | `stickyNameColumn` | `boolean` | `true` | Keep the name column pinned while the data columns scroll horizontally (native addition) | | `className` | `string` | - | Additional classes for the root container | | `testID` | `string` | - | Test id for the root container | ### TreeTableColumn | Field | Type | Default | Description | |-------|------|---------|-------------| | `id` | `string` | - | Column id | | `header` | `ReactNode` | - | Header content (strings are wrapped in `Text`) | | `accessorKey` | `string` | - | Key read from the item when `cell` is not set | | `cell` | `(item: TreeViewItem) => ReactNode` | - | Custom cell renderer | | `width` | `number` | `120` | Column width in dp (web also accepts CSS strings) | | `align` | `'left' \| 'center' \| 'right'` | `'left'` | Cell alignment | | `className` | `string` | - | Extra classes for body cells | | `headerClassName` | `string` | - | Extra classes for the header cell | ### Differences from web - `ref` and div HTML attributes are dropped (`className` + `testID` remain). - Drag-and-drop (dnd-kit) is replaced by the "Move to…" sheet; `onDataChange` / `TreeViewMoveDetails` are identical and `position` is one of `before` / `after` / `inside` / `root`. - `TreeTableColumn.width` is a number. - `nameColumnWidth`, `onRowPress` and `stickyNameColumn` are native additions. ## Translation keys Copy resolves through `useUiTranslation()`. Shared with web: `ui.treeView.searchPlaceholder`, `ui.treeView.noItemsFound`. Native additions: `ui.treeTable.name`, `ui.treeTable.options`, `ui.treeView.expandAll`, `ui.treeView.collapseAll`, `ui.treeView.expand`, `ui.treeView.collapse`, `ui.treeView.moveTo`, `ui.treeView.moveToRoot`, `ui.treeView.moveBefore`, `ui.treeView.moveInside`, `ui.treeView.moveAfter`. ## Components | Component | Description | |-----------|-------------| | `TreeTable` | Main component | ## Type Exports | Type | Description | |------|-------------| | `TreeTableProps` | Props for `TreeTable` | | `TreeTableColumn` | Column definition |