@neo4j-ndl/react
Version:
React implementation of Neo4j Design System
546 lines (512 loc) • 17.9 kB
Markdown
# TreeView
Import: `import { TreeView } from '@neo4j-ndl/react'`
## Props
### TreeView
| Prop | Type | Required | Default | Description |
|------|------|----------|---------|-------------|
| `items` | `TreeItem<T>[]` | ✅ | | The items to be displayed in the tree view |
| `onItemsChanged` | `(newItems: TreeItem<T>[], itemChangedReason: ItemChangedReason<T>) => void` | ✅ | | A function that is called when the items in the tree view change |
| `TreeItemComponent` | `TreeItemComponent<T, E>` | | | The component to use for the tree items, if not provided the default component will be used |
### TreeView.SortableTreeViewItem
| Prop | Type | Required | Default | Description |
|------|------|----------|---------|-------------|
| `ariaLevel` | `number` | | | |
| `ariaPosInSet` | `number` | | | |
| `ariaSetSize` | `number` | | | |
| `childCount` | `number` | | | Number of child items |
| `clone` | `boolean` | | | Whether this is a clone item |
| `collapsed` | `boolean` | | | Whether the item is collapsed |
| `depth` | `number` | ✅ | | Depth of the item in the tree |
| `id` | `UniqueIdentifier` | ✅ | | |
| `indentationWidth` | `number` | ✅ | | Width of the indentation |
| `indicator` | `boolean` | | | Whether this is an indicator item |
| `isLast` | `boolean` | ✅ | | Whether this is the last item in its parent |
| `item` | `FlattenedTreeItem<T>` | ✅ | | The tree item data |
| `items` | `FlattenedTreeItem<T>[]` | ✅ | | All items in the tree |
| `keepGhostInPlace` | `boolean` | | | Whether to keep the ghost item in place while dragging |
| `onCollapse` | `(id: UniqueIdentifier) => void` | | | Function to call when item is collapsed |
| `onFocus` | `() => void` | | | Function to call when the item receives focus |
| `onItemsChanged` | `(newItems: FlattenedTreeItem<T>[], itemChangedReason: ItemChangedReason<T>) => void` | ✅ | | Function to call when the item has changed |
| `onRemove` | `(id: UniqueIdentifier) => void` | | | Function to call when item is removed |
| `parent` | `FlattenedTreeItem<T>` | ✅ | | Parent item of this item |
| `shouldDisableInteraction` | `boolean` | | | Whether interaction should be disabled |
| `shouldDisableSorting` | `boolean` | | | Whether sorting should be disabled for this item |
| `sortableProps` | `Omit<Arguments, "id">` | | | Props for the sortable functionality |
| `tabIndex` | `number` | | | |
| `trails` | `("none" \| "straight" \| "straight-curved" \| "curved")[]` | ✅ | | A list of trails to render before the item |
| `TreeItemComponent` | `TreeItemComponent<T, E>` | ✅ | | The component to use for rendering the tree item |
| `wrapperRef` | `(node: HTMLLIElement) => void` | | | Function to set the wrapper ref |
### TreeView.TreeItemWrapper
| Prop | Type | Required | Default | Description |
|------|------|----------|---------|-------------|
| `ariaLevel` | `number` | | | |
| `ariaPosInSet` | `number` | | | |
| `ariaSetSize` | `number` | | | |
| `depth` | `number` | ✅ | | Depth of the item in the tree |
| `dragHandleProps` | `Record<string, unknown>` | | | Props for the drag handle |
| `indentationWidth` | `number` | ✅ | | Width of the indentation |
| `isCollapsed` | `boolean` | | | If the item is collapsed |
| `isGhost` | `boolean` | | | If the item is should be rendered as a placeholder (for example, while dragging) |
| `isIndicator` | `boolean` | | | True if the item should be rendered as a indicator (for example, while dragging) |
| `isLastInParent` | `boolean` | ✅ | | True if this item is the last in the parent list |
| `isOver` | `boolean` | ✅ | | True if dragged item is over this Node. |
| `isOverParent` | `boolean` | ✅ | | True if dragged item is over the parent of this Node. |
| `item` | `FlattenedTreeItem<T>` | ✅ | | The tree item data |
| `items` | `FlattenedTreeItem<T>[]` | ✅ | | All items in the tree |
| `onCollapse` | `() => void` | | | Function to call when the item is collapsed/expanded |
| `onFocus` | `() => void` | | | Function to call when the item receives focus |
| `onItemsChanged` | `(newItems: FlattenedTreeItem<T>[], reason: ItemChangedReason<T>) => void` | ✅ | | Function to call when the item has changed |
| `parent` | `FlattenedTreeItem<T>` | ✅ | | Parent item of this item |
| `ref` | `Ref<HTMLDivElement>` | | | A ref to apply to the root element. |
| `setActivatorNodeRef` | `(node: HTMLElement) => void` | ✅ | | Function to set the ref of the element that should activate sorting |
| `setNodeRef` | `(node: HTMLLIElement) => void` | ✅ | | Function to set the ref of the element that should be sorted (the wrapper element of the item) |
| `shouldDisableInteraction` | `boolean` | | | While dragging it makes sense to disable some interaction for all other items. |
| `shouldDisableSorting` | `boolean` | | | True if sorting is disabled for this item. |
| `tabIndex` | `number` | | | |
| `trails` | `("none" \| "straight" \| "straight-curved" \| "curved")[]` | ✅ | | A list of trails to render before the item |
### TreeView.TreeViewTextItem
| Prop | Type | Required | Default | Description |
|------|------|----------|---------|-------------|
| `ariaLevel` | `number` | | | |
| `ariaPosInSet` | `number` | | | |
| `ariaSetSize` | `number` | | | |
| `depth` | `number` | ✅ | | Depth of the item in the tree |
| `dragHandleProps` | `Record<string, unknown>` | | | Props for the drag handle |
| `indentationWidth` | `number` | ✅ | | Width of the indentation |
| `isCollapsed` | `boolean` | | | If the item is collapsed |
| `isGhost` | `boolean` | | | If the item is should be rendered as a placeholder (for example, while dragging) |
| `isIndicator` | `boolean` | | | True if the item should be rendered as a indicator (for example, while dragging) |
| `isLastInParent` | `boolean` | ✅ | | True if this item is the last in the parent list |
| `isOver` | `boolean` | ✅ | | True if dragged item is over this Node. |
| `isOverParent` | `boolean` | ✅ | | True if dragged item is over the parent of this Node. |
| `item` | `FlattenedTreeItem<T>` | ✅ | | The tree item data |
| `items` | `FlattenedTreeItem<T>[]` | ✅ | | All items in the tree |
| `onCollapse` | `() => void` | | | Function to call when the item is collapsed/expanded |
| `onFocus` | `() => void` | | | Function to call when the item receives focus |
| `onItemsChanged` | `(newItems: FlattenedTreeItem<T>[], reason: ItemChangedReason<T>) => void` | ✅ | | Function to call when the item has changed |
| `parent` | `FlattenedTreeItem<T>` | ✅ | | Parent item of this item |
| `ref` | `Ref<HTMLDivElement> & Ref<HTMLElement>` | | | A ref to apply to the root element. |
| `setActivatorNodeRef` | `(node: HTMLElement) => void` | ✅ | | Function to set the ref of the element that should activate sorting |
| `setNodeRef` | `(node: HTMLLIElement) => void` | ✅ | | Function to set the ref of the element that should be sorted (the wrapper element of the item) |
| `shouldDisableInteraction` | `boolean` | | | While dragging it makes sense to disable some interaction for all other items. |
| `shouldDisableSorting` | `boolean` | | | True if sorting is disabled for this item. |
| `tabIndex` | `number` | | | |
| `trails` | `("none" \| "straight" \| "straight-curved" \| "curved")[]` | ✅ | | A list of trails to render before the item |
## Examples
### Treeview Custom
```tsx
import '@neo4j-ndl/base/lib/neo4j-ds-styles.css';
import { TreeView } from '@neo4j-ndl/react';
import {
ChevronDownIconSolid,
ChevronUpIconSolid,
FolderIconOutline,
} from '-ndl/react/icons';
import type React from 'react';
import { useState } from 'react';
const TREE_ITEMS: React.ComponentProps<typeof TreeView>['items'] = [
{
canHaveSubItems: true,
data: {
custom: 'Custom Root',
},
id: 'Root',
isCollapsed: false,
isSelected: false,
subItems: [
{
canHaveSubItems: false,
data: {
custom: 'Custom child 1',
},
id: 'Child 1',
isSelected: false,
},
{
canHaveSubItems: false,
data: {
custom: 'Custom child 2',
},
id: 'Child 2',
isSelected: false,
},
{
canHaveSubItems: false,
data: {
custom: 'Custom child 3',
},
id: 'Child 3',
isSelected: false,
},
],
},
];
const Component = () => {
const [items, setItems] = useState(TREE_ITEMS);
return (
<TreeView
items={items}
onItemsChanged={(newItems) => {
setItems(newItems);
}}
TreeItemComponent={function CustomTreeItem({
ref,
onItemsChanged,
...restProps
}: React.ComponentProps<typeof TreeView.TreeItemWrapper>) {
return (
<TreeView.TreeItemWrapper
{...restProps}
onItemsChanged={onItemsChanged}
ref={ref}
>
<div
className="n-items-center n-flex n-flex-row"
style={{
background: !restProps.item.canHaveSubItems
? 'linear-gradient(in hsl longer hue 45deg, red 0 0)'
: '',
}}
>
{restProps.item.canHaveSubItems && (
<>
<FolderIconOutline className="n-h-5 w-h-5" />
<button
type="button"
onClick={() =>
restProps.onCollapse && restProps.onCollapse()
}
>
{restProps.item.isCollapsed ? (
<ChevronUpIconSolid className="n-h-5 w-h-5" />
) : (
<ChevronDownIconSolid className="n-h-5 w-h-5" />
)}
</button>
</>
)}
{'custom' in restProps.item.data &&
typeof restProps.item.data.custom === 'string' &&
restProps.item.data.custom}
</div>
</TreeView.TreeItemWrapper>
);
}}
/>
);
};
export default Component;
```
### Treeview Default
```tsx
import '@neo4j-ndl/base/lib/neo4j-ds-styles.css';
import { TreeView } from '@neo4j-ndl/react';
import { PencilIconOutline } from '@neo4j-ndl/react/icons';
import type React from 'react';
import { useState } from 'react';
const TREE_ITEMS: React.ComponentProps<typeof TreeView>['items'] = [
{
canHaveSubItems: true,
data: {
actions: [
{
buttonProps: {
description: 'Edit',
onClick: () => {
alert('Pencil was clicked');
},
},
icon: <PencilIconOutline />,
},
],
onTextClick: () => {
alert('Text was clicked');
},
text: 'Folder 1',
},
id: 'Folder 1',
isCollapsed: false,
isSelected: false,
isSortable: false,
subItems: [
{
canHaveSubItems: false,
data: {
actions: [
{
buttonProps: {
description: 'Edit',
onClick: () => {
alert('Pencil was clicked');
},
},
icon: <PencilIconOutline />,
},
],
onTextClick: () => {
alert('Text was clicked');
},
text: 'Child 1',
},
id: 'Child 1',
isSelected: false,
isSortable: true,
},
{
canHaveSubItems: false,
data: {
actions: [
{
buttonProps: {
description: 'Edit',
onClick: () => {
alert('Pencil was clicked');
},
},
icon: <PencilIconOutline />,
},
],
onTextClick: () => {
alert('Text was clicked');
},
text: 'Child 2',
},
id: 'Child 2',
isSelected: false,
isSortable: true,
},
{
canHaveSubItems: false,
data: {
actions: [
{
buttonProps: {
description: 'Edit',
onClick: () => {
alert('Pencil was clicked');
},
},
icon: <PencilIconOutline />,
},
],
onTextClick: () => {
alert('Text was clicked');
},
text: 'Child 3',
},
id: 'Child 3',
isSelected: false,
isSortable: true,
},
{
canHaveSubItems: true,
data: {
actions: [
{
buttonProps: {
description: 'Edit',
onClick: () => {
alert('Pencil was clicked');
},
},
icon: <PencilIconOutline />,
},
],
onTextClick: () => {
alert('Text was clicked');
},
text: 'Folder 2',
},
id: 'Folder 2',
isCollapsed: true,
isSelected: false,
isSortable: true,
subItems: [
{
canHaveSubItems: false,
data: {
actions: [
{
buttonProps: {
description: 'Edit',
onClick: () => {
alert('Pencil was clicked');
},
},
icon: <PencilIconOutline />,
},
],
onTextClick: () => {
alert('Text was clicked');
},
text: 'Child 4',
},
id: 'Child 4',
isSelected: false,
},
{
canHaveSubItems: false,
data: {
actions: [
{
buttonProps: {
description: 'Edit',
onClick: () => {
alert('Pencil was clicked');
},
},
icon: <PencilIconOutline />,
},
],
onTextClick: () => {
alert('Text was clicked');
},
text: 'Child 5',
},
id: 'Child 5',
isSelected: false,
},
{
canHaveSubItems: false,
data: {
actions: [
{
buttonProps: {
description: 'Edit',
onClick: () => {
alert('Pencil was clicked');
},
},
icon: <PencilIconOutline />,
},
],
onTextClick: () => {
alert('Text was clicked');
},
text: 'Child 6',
},
id: 'Child 6',
isSelected: false,
},
],
},
],
},
{
canHaveSubItems: false,
data: {
actions: [
{
buttonProps: {
description: 'Edit',
onClick: () => {
alert('Pencil was clicked');
},
},
icon: <PencilIconOutline />,
},
],
onTextClick: () => {
alert('Text was clicked');
},
text: 'Child 7',
},
id: 'Child 7',
isSelected: false,
isSortable: true,
},
];
const Component = () => {
const [items, setItems] =
useState<React.ComponentProps<typeof TreeView>['items']>(TREE_ITEMS);
return (
<TreeView
items={items}
onItemsChanged={(newItems, itemChangedReason) => {
// eslint-disable-next-line no-restricted-syntax
console.log('change with itemChangedReason:', itemChangedReason);
setItems(newItems);
}}
TreeItemComponent={undefined}
/>
);
};
export default Component;
```
### Treeview Skeleton Loading
```tsx
import '@neo4j-ndl/base/lib/neo4j-ds-styles.css';
import { TreeView } from '@neo4j-ndl/react';
import type React from 'react';
import { useState } from 'react';
const TREE_ITEMS: React.ComponentProps<typeof TreeView>['items'] = [
{
canHaveSubItems: true,
data: {
actions: [],
text: 'Folder 1',
},
id: 'Folder 1',
isCollapsed: false,
isSelected: false,
subItems: [
{
canHaveSubItems: false,
data: {
actions: [],
text: 'Item 1',
},
id: 'Item 1',
isSelected: false,
},
{
canHaveSubItems: true,
data: {
actions: [],
text: 'Folder 2',
},
id: 'Folder 2',
isCollapsed: false,
isSelected: false,
isSkeletonLoading: true,
subItems: [
{
canHaveSubItems: false,
data: {
actions: [],
text: 'Item 2',
},
id: 'Item 2',
isSelected: false,
},
{
canHaveSubItems: false,
data: {
actions: [],
text: 'Item 3',
},
id: 'Item 3',
isSelected: false,
isSkeletonLoading: true,
},
],
},
],
},
];
const Component = () => {
const [items, setItems] =
useState<React.ComponentProps<typeof TreeView>['items']>(TREE_ITEMS);
return (
<TreeView
items={items}
onItemsChanged={(newItems, itemChangedReason) => {
console.info('change with itemChangedReason:', itemChangedReason);
setItems(newItems);
}}
TreeItemComponent={undefined}
/>
);
};
export default Component;
```