Skip to content

A React tree component offering drag-and-drop, virtualization, and nested structuring. Crafted with TypeScript for dynamic and efficient data hierarchy management.

License

Notifications You must be signed in to change notification settings

alpernative/tree

Repository files navigation

alpernative-tree

AlperNative Tree

@alpernative/tree is a high-performance, customizable tree component for React. It provides a wide range of features, including virtualization, drag-and-drop, and nested drag-and-drop support.

Features

  • High Performance: @alpernative/tree is designed to handle large datasets with ease, providing smooth and responsive user experiences.
  • Customizable: @alpernative/tree offers a wide range of customization options, allowing you to tailor the appearance and behavior of the tree to your specific needs.
  • Virtualization: @alpernative/tree supports virtualization, enabling you to render only the visible portion of the tree, which can significantly improve performance when working with large datasets.
  • Drag and Drop: @alpernative/tree provides built-in support for drag-and-drop operations, making it easy to rearrange tree nodes.
  • Nested Drag and Drop: @alpernative/tree supports nested drag-and-drop operations, allowing you to move nodes within and between different levels of the tree.

Getting Started

Installation

npm install @alpernative/tree

or using yarn:

yarn add @alpernative/tree

Basic Usage

We need to create TreeItem.tsx file to render the tree items

import { FC, useState } from 'react';

import { RenderItemParams, TreeItem as TreeItemType } from '@alpernative/tree';
import { AiOutlineFile, AiOutlineFolder, AiOutlineFolderOpen } from 'react-icons/ai';
import { FaChevronRight, FaChevronDown } from 'react-icons/fa';

export const TreeItem: FC<RenderItemParams> = ({ item, provided, onCollapse, onExpand }) => {
  const [isSelected, setIsSelected] = useState(false);

  const renderItemIcon = () => {
    // You can customize the your icons based on the item's properties
    if (!item.hasChildren) return <AiOutlineFile />;
    if (item.isExpanded) return <AiOutlineFolderOpen />;
    return <AiOutlineFolder />;
  };

  const handleOnClick = (item: TreeItemType) => {
    setIsSelected(value => !value);
    if (item.isExpanded) onCollapse(item.id);
    if (!item.isExpanded) onExpand(item.id);
  };

  return (
    <div
      ref={provided.innerRef}
      {...provided.draggableProps}
      {...provided.dragHandleProps}
      onClick={() => handleOnClick(item)}
    >
      <div style={{ color: isSelected ? 'red' : 'gray' }}>
        {item.hasChildren && (item.isExpanded ? <FaChevronDown /> : <FaChevronRight />)}
        {renderItemIcon()}
        {item.data.title}
      </div>
    </div>
  );
};

Then we can use the Tree component in our App.tsx file

import { FC, useState } from 'react';

import Tree from '@alpernative/tree';

import { TreeItem } from './TreeItem';

export const basicTreeData = {
  rootId: 'root',
  items: {
    root: {
      id: 'root',
      data: { title: 'Root' },
      children: ['item-0'],
      hasChildren: true,
      isExpanded: true,
      isChildrenLoading: false,
    },
    'item-0': {
      id: 'item-0',
      data: {
        title: 'Item 0',
      },
      children: ['item-1', 'item-2', 'item-3', 'item-4'],
      hasChildren: true,
      isExpanded: true,
      isChildrenLoading: false,
    },
    'item-1': {
      id: 'item-1',
      data: {
        title: 'Item 1',
      },
      children: [],
      hasChildren: false,
      isExpanded: true,
      isChildrenLoading: false,
    },
    'item-2': {
      id: 'item-2',
      data: {
        title: 'Item 2',
      },
      children: [],
      hasChildren: false,
      isExpanded: true,
      isChildrenLoading: false,
    },
    'item-3': {
      id: 'item-3',
      data: {
        title: 'Item 3',
      },
      children: [],
      hasChildren: false,
      isExpanded: true,
      isChildrenLoading: false,
    },
    'item-4': {
      id: 'item-4',
      data: {
        title: 'Item 4',
      },
      children: [],
      hasChildren: false,
      isExpanded: true,
      isChildrenLoading: false,
    },
  },
};

export const App: FC = () => {
  const [treeData, setTreeData] = useState<TreeData>(basicTreeData);

  const onExpand = (ItemId: ItemId) => {
    setTreeData(mutateTree(treeData, ItemId, { isExpanded: true }));
  };

  const onCollapse = (ItemId: ItemId) => {
    setTreeData(mutateTree(treeData, ItemId, { isExpanded: false }));
  };

  const onDragEnd = (source: TreeSourcePosition, destination?: TreeDestinationPosition) => {
    if (!destination) return;

    const newTree = moveItemOnTree(treeData, source, destination);
    setTreeData(newTree);
  };

  return (
    <div style={{ width: 200, height: 300 }}>
      <Tree
        tree={treeData}
        offsetPerLevel={19}
        renderItem={props => <TreeItem {...props} />}
        onExpand={onExpand}
        onCollapse={onCollapse}
        onDragEnd={onDragEnd}
        isNestingEnabled
        isDragEnabled
        virtualItemHeight={24}
        isVirtualizationEnabled
      />
    </div>
  );
};

Examples

Looking for more examples? Check out the Storybook for a wide range of use cases and customization options.

Do you want more? Check out the CodeSandbox for a wide range of use cases and customization options.

Documentation

For full documentation, visit Link to Documentation.

Contributing

Contributions are always welcome! Please read the contribution guidelines first.

License

This project is licensed under the MIT License - see the LICENSE.md file for details.

About

A React tree component offering drag-and-drop, virtualization, and nested structuring. Crafted with TypeScript for dynamic and efficient data hierarchy management.

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published