npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

react-hyper-tree

v0.3.12

Published

Fully customizable react tree component

Downloads

5,304

Readme

React hyper tree

Fully customizable tree view react component

Welcome to the react hyper tree component 😄 I want to introduce you to an awesome react component for displaying tree data structure

dependecies license min minzip

Features

  • render tree-like data structure
  • show/hide lines
  • fully custom component by providing render functions (node and drag zone) or custom class names
  • tree management by global utility (treeHandlers)
  • single/multiple node selection
  • async loading of children
  • drag and drop using 3 types of insertion (before, children, after)

Table of contents

Live demo is available!

Check also react-hyper-modal library

Installation

You can use npm or yarn package managers
$ npm i --save react-hyper-tree

or

$ yarn add react-hyper-tree

Usage

Simple Usage

import React from 'react'
import Tree, { useTreeState } from 'react-hyper-tree'

const data = {
  id: 1,
  name: 'Parent 1',
  children: [
    {
      id: 2,
      name: 'Child 1',
      children: [
        {
          id: 5,
          name: 'Child 1__1',
        },
        {
          id: 6,
          name: 'Child 1__2',
        },
        {
          id: 7,
          name: 'Child 1__3',
        },
      ],
    },
  ],
}

...

const MyTreeComponent = () => {
  const { required, handlers } = useTreeState({
    data,
    id: 'your_tree_id',
  })

  return (
    <Tree
      {...required}
      {...handlers}
    />
  )
}

Properties

| Props | Description | | ----------------------- | -------------------------------------------------------------------------------------- | | classes? | object with elements class names | | data | nodes data, provided by required prop | | depthGap? | children indentation related to parent | | disableHorizontalLines? | disable horizontal lines | | disableLines? | disable all lines | | disableVerticalLines? | disable vertical lines | | disableTransitions? | disable transitions (improves performance) | | displayedName? | format node content, if you use default node renderer | | draggable?: | enable draggable mode | | gapMode? | indentation mode | | horizontalLineStyles? | horizontal line styles, SVG properties | | renderDragZone? | function to render your custom drag zone | | renderNode? | function to render your custom node | | setOpen? | open node children, provided by handlers prop | | setSelected? | select node, provided by handlers prop | | staticNodeHeight? | set static height of node, otherwise dynamic height will be used | | verticalLineOffset? | vertical line offset related to parent | | verticalLineStyles? | vertical line styles, SVG properties | | verticalLineTopOffset? | vertical line top offset |

useTreeState API

useTreeState React hook includes the state management functionality. It prepares and transforms the data to use all functionality of the Node API.

useTreeState input

| Property | Description | | ------------------ | --------------------------------------------- | | childrenKey? | set the children key, e.g. 'children' | | data | tree-like data | | defaultOpened? | if true, all parent will be opened | | filter? | function to filter tree nodes | | id | tree id, required | | idKey? | set the data id key, e.g. 'id' | | multipleSelect? | if true, a several nodes can be selected | | sort? | function to sort tree nodes | | refreshAsyncNodes? | load async children every time when open node |

useTreeState output

| Property | Description | | -------- | ---------------------------------------------------------------------------------------------------------- | | handlers | handlers to manipulate node state. setOpen, setLoading, setSelected, setChildren, setRawChildren | | instance | tree view instance including all tree methods | | required | includes enhanced tree structure |

Actually TreeView component is a renderer. It hasn't any functionality to manipulate of tree state.

Node API

| Method | Description | Typings | | --------------- | ------------------------------------------ | ----------------------------------------------------------------------------- | | getChildren | returns node children or empty array | () => TreeNode[] | | getData | returns raw node data | () => any | | getFirstChild | returns the first child | () => TreeNode | null | | getLastChild | returns the last child | () => TreeNode | null | | getPath | get node path | (array?: boolean) => string | string[] | | hasChildren | returns true if node has atleast one child | () => boolean | | isLoading | returns true if node is loading | () => boolean | | isOpened | returns true if node is opened | () => boolean | | isSelected | returns true if node is selected | () => boolean | | setChildren | a simple equivalent of setNodeChildren | (children: TreeNode[]) => void | | setData | sets node data | (data?: any) => void | | setLoading | set node loading | (loading?: boolean) => void | | setNodeChildren | insert node children | (children: TreeNode[], type?: InsertChildType, reset?: boolean) => TreeNode[] | | setOpened | set node opened | (opened?: boolean) => void | | setParent | set node parent | (parent?: TreeNode) => void | | setSelected | set node selected | (selected?: boolean) => void | | getPath | get node path | (array?: boolean) => string | string[] | | getReactKey | returns calculated property for react key | () => string |

Global state manager

The main goal to implement the tree view library was a simple usage and global tree manager.

Actually, global state manager (GSM) is represented as treeHandlers object. It has all instances of trees in the project.

Every time you use useTreeState hook. It will create a new TreeView instance and add the instance to treeHandlers object.

The GSM structure

The GSM object has the one property trees.

type Handler = (...args: any[]) => any

interface IHandlers {
    [key: string]: Handler
}

interface ITreeItem {
    instance: TreeView
    handlers: IHandlers
}

interface ITrees {
    [key: string]: ITreeItem
}

trees: ITrees

When you use useTreeState with the tree id, it will add tree instance to GSM. To access to tree instance you should do the next:

import { treeHandlers } from 'react-hyper-tree'

treeHandlers.trees[your - tree - id].instance

You can use the full tree instance functionality from the GSM. Also the GSM has the handlers property for every tree instance.

Every tree has a default set of methods to manipulate the data

| Method | Descriptipn | Typings | | ----------------- | --------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------- | | rerender | rerender the tree component | (callback? () => void) => void | | setLoading | set loading property | (node: TreeNode | string | number, loading?: boolean) => void | | setOpen | set opened property | (node: TreeNode | string | number, toggle?: boolean) => void | | setOpenByPath | set opened by path | (path: string) => void | | setRawChildren | set node children, use it if you have a raw children data | (parent: TreeNode | string | number, children: IData[], type?: InsertChildType, reset?: boolean) => void | | setChildren | set node children, use it if you have an enhanced children data | (parent: TreeNode | string | number, children: TreeNode[], type?: InsertChildType, reset?: boolean) => void | | setSelected | set selected property | (node: TreeNode | string | number, selected?: boolean) => void | | setSelectedByPath | set selected by path | (path: string, all?: boolean, toggle?: boolean) => void | | setSiblings | set node siblings | (node: TreeNode | string | number, siblings: TreeNode[], type: InsertSiblingType) => void | | getNodeData | returns node data | (node: TreeNode | string | number, siblings: TreeNode[]) => void | | getNode | returns node | (node: TreeNode | string | number, siblings: TreeNode[]) => void | | selectAll | select all nodes (if multipleSelect is true) | () => void | | unselectAll | unselect all nodes | () => void |

To call any method you should do the next:

import { treeHandlers } from 'react-hyper-tree'

treeHandlers.trees[your-tree-id].handlers.setOpen(...)

treeHandlers API

| Method | Description | Typings | | ----------------- | ----------------------------- | -------------------------------------------------------------------------------------- | | getIds | get trees ids | () => string[] | | remove | remove tree from the GSM | (id: string): TreeHandlers | | removeHandler | remove handler from the tree | removeHandler(treeId: string, handlerName: string): TreeHandlers | | safeUpdate | add or update tree in the GSM | safeUpdate(id: string, tree: TreeView) => TreeHandlers | | safeUpdateHandler | add or update tree handler | safeUpdateHandler(treeId: string, handlerName: string, handler: Handler): TreeHandlers |

You can also use treeHandlers like call chain

treeHandlers
    .safeUpdateHandler(id, 'setLoading', setLoading)
    .safeUpdateHandler(id, 'setSelected', setSelected)
    .safeUpdateHandler(id, 'setRawChildren', setRawChildren)
    .safeUpdateHandler(id, 'setChildren', setChildren)

Async children

You also can use loadable children. To enable the feature you should provide getChildren function to node data

const getChildren = ({ node }) => {
    return getChildrenByParentId(node.id)
}

const data = {
    id: 1,
    name: 'Parent 1',
    getChildren
}

getChildren function can return Promise and resolve the children data in format like this:

const getChildren = () =>
    new Promise(resolve =>
        setTimeout(
            () =>
                resolve([
                    {
                        id: 2,
                        name: 'Child'
                    }
                ]),
            1000
        )
    )

You can also fire any events like redux-actions in the getChildren function. In this case you can set the children by the GSM

Default properties

export const defaultProps = {
    childrenKey: 'children',
    classes: {} as ClassesType,
    depthGap: 20,
    displayedName: (node: TreeNode) => node.data.name,
    filter: () => true,
    gapMode: 'margin' as const,
    horizontalLineStyles: { stroke: 'black', strokeWidth: 1, strokeDasharray: '1 1' },
    idKey: 'id',
    opened: [],
    verticalLineOffset: 5,
    verticalLineStyles: { stroke: 'black', strokeWidth: 1, strokeDasharray: '1 1' },
    verticalLineTopOffset: 0
}

Road map

  • Coverage by tests
  • Inner improvements and extending functionality
  • Documentation improvements

Contributing

Pull requests are welcome. For major changes, please open an issue first to discuss what you would like to change.

License

MIT