React Complex Tree

repository·main·Indexed 23 days ago

https://github.com/lukasbach/react-complex-tree

An unopinionated, accessible library for building complex, interactive tree structures in React. It supports W3C accessibility specifications, multi-item drag-and-drop, multi-selection, and keyboard controls for renaming and searching. The library offers both controlled and uncontrolled interfaces, zero external dependencies, and full TypeScript support. It includes specialized packages such as react-complex-tree-blueprintjs-renderers for BlueprintJS styling and react-complex-tree-autodemo for automated demonstrations.

Tokens
27.8K
Snippets
62
Records
106
Agent score
78%

What's inside react-complex-tree

  1. Overview of React Complex Tree features

    main

    React Complex Tree is an unopinionated, accessible tree component designed for complex interactions.

    Core Capabilities

    • Accessibility: Conforms to W3C specifications for accessible trees, supporting screen readers and full keyboard navigation.
    • Drag and Drop: Supports advanced drag-and-drop, including multi-item dragging across different trees within the same environment.
    • Multi-Selection: Allows users to select multiple items (e.g., using Ctrl + click) and move them simultaneously.
    • Keyboard Controls: Includes built-in support for renaming (press F2), searching (start typing while focused), and tree navigation.
    • Multi-Tree Environments: Multiple <Tree /> components can exist under a single <UncontrolledTreeEnvironment />, allowing them to share state and interact with one another.
    • Flexible Interfaces: Supports both Uncontrolled (environment manages state) and Controlled (you manage state) interfaces.
    • Zero Dependencies: The package does not include any external dependencies, keeping your bundle lean.
    • TypeScript Support: Fully typed for enhanced developer experience and type safety.
  2. Configure Interaction Modes in React Complex Tree

    main

    The interaction mode determines how mouse and keyboard inputs interact with the tree (e.g., how clicking an item affects focus, selection, or expansion).

    You can set the interaction mode by providing the interactionMode prop to a tree environment (like UncontrolledTreeEnvironment). This prop accepts either a string corresponding to a built-in mode from the InteractionMode enum or a custom InteractionManager object.

    Built-in modes are identified by the following string keys:

    • click-arrow-to-expand
    • click-item-to-expand (Default)
    • double-click-item-to-expand
    <UncontrolledTreeEnvironment
      // ... other props
      defaultInteractionMode={'click-item-to-expand'}
    >
      <Tree treeId="tree-1" rootItem="root" />
    </UncontrolledTreeEnvironment>
  3. How to enable drag-and-drop across multiple trees

    main

    To allow multiple <Tree /> components to interact with one another (e.g., dragging items from one tree to another), they must be wrapped within the same tree environment. This means both trees must be children of the same ControlledTreeEnvironment or UncontrolledTreeEnvironment instance.

    When sharing an environment:

    • Drag and drop works across the trees.
    • Trees maintain their own state for search and renaming.
    • Only one search or renaming input is active at a time across all trees in that environment.
    • Trees maintain a shared state, which facilitates synchronization.
    <UncontrolledTreeEnvironment
      canDragAndDrop={true}
      canDropOnFolder={true}
      canReorderItems={true}
      dataProvider={new StaticTreeDataProvider(longTree.items, (item, data) => ({ ...item, data }))}
      getItemTitle={item => item.data}
      viewState={{}}
    >
      <Tree treeId="tree-1" rootItem="root" treeLabel="Tree 1" />
      <Tree treeId="tree-2" rootItem="root" treeLabel="Tree 2" />
    </UncontrolledTreeEnvironment>
  4. Managing a tree's view state

    main

    The viewState prop defines the visual state of a tree, including which items are focusedItem, selectedItems, and expandedItems.

    • In a controlled environment (ControlledTreeEnvironment), viewState must always reflect the current visual state and must be manually updated via change hooks when the user interacts with the tree.
    • In an uncontrolled environment (UncontrolledTreeEnvironment), the viewState provided is used only as the initial state, and subsequent user interactions will update the state internally.
  5. How to use multiple independent tree environments

    main

    If you need multiple tree components on a single page that do not share state or drag-and-drop capabilities, you must use separate environment instances (e.g., two different UncontrolledTreeEnvironment components).

    When using multiple environments, follow these rules:

    1. Unique IDs: Each <Tree /> must have a unique treeId. This ID must be unique even across different environments on the same page.
    2. No Nesting: An environment must not contain another tree environment.
    3. DOM Structure: If you need a specific DOM structure that would otherwise require nesting environments, use React Portals to render the environments disjunctly.
  6. Use UncontrolledTreeEnvironment for uncontrolled tree management

    main

    The UncontrolledTreeEnvironment component is used to manage a tree in an uncontrolled manner. This means the component manages its own internal state for things like selection, expansion, and tree structure, rather than requiring you to pass state down via props and handle updates manually.

    For a detailed explanation of how to implement and manage state in this mode, refer to the Guide on Uncontrolled Environments.

  7. Implement custom drop handlers and understand drop targets

    main

    To implement custom drop logic, implement the onDrop handler from TreeChangeHandlers. The target variable in the onDrop handler provides details about where the item was dropped:

    • item (DraggingPositionItem): The user dropped in the center of an item. If it's a folder, props.canDropOnFolder is true; otherwise, props.canDropOnNonFolder is true. The dragged items are inserted into this target.
    • between-items (DraggingPositionBetweenItems): The user is dragging on the top or bottom part of an item. Use target.linePosition ('top' or 'bottom') to determine if the item should be inserted above or below the target.
    • root (DraggingPositionRoot): The user is dragging on the top-level of the tree (e.g., an empty tree or the space below the last item). The item is inserted at the bottom of the top-level.

    Indexing Concepts

    • childIndex: The position of an item within its immediate parent.
    • linearIndex: The overall position of the item within the entire tree as if all items were laid out linearly.
  8. Search functionality in React Complex Tree

    main

    React Complex Tree provides native search support that looks through all items currently visible in the tree. When the tree is focused, users can start typing to initiate a search. This includes accessibility support where typing a single character moves focus to the first matching item, following W3C treeview keyboard binding specifications.

    Note: Search only scans items that are currently loaded/visible in the tree. To find items that are not currently visible (e.g., inside collapsed nodes), you must implement custom logic to find the item's path and then use the tree's API to expand the path.

  9. Use ControlledTreeEnvironment for controlled tree state

    main

    The ControlledTreeEnvironment component is used to implement a controlled tree where the state (such as selection, expansion, and drag-and-drop) is managed by the consumer rather than the component itself. This is useful when you need to sync the tree state with an external store (like Redux or React state) or perform complex state transitions.

    For detailed implementation patterns, refer to the Guide on Controlled Environments.