Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/alekseymakhankov/hyper-tree
React treeview component
https://github.com/alekseymakhankov/hyper-tree
custom-hook react react-component react-hooks reactjs tree tree-structure treeview
Last synced: 30 days ago
JSON representation
React treeview component
- Host: GitHub
- URL: https://github.com/alekseymakhankov/hyper-tree
- Owner: alekseymakhankov
- License: mit
- Created: 2020-02-15T15:45:44.000Z (almost 5 years ago)
- Default Branch: master
- Last Pushed: 2023-02-04T10:08:04.000Z (almost 2 years ago)
- Last Synced: 2024-11-29T00:05:52.513Z (about 1 month ago)
- Topics: custom-hook, react, react-component, react-hooks, reactjs, tree, tree-structure, treeview
- Language: TypeScript
- Size: 2.02 MB
- Stars: 68
- Watchers: 1
- Forks: 11
- Open Issues: 14
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
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](https://img.shields.io/badge/dependecies-no%20dependencies-green.svg)
![license](https://img.shields.io/badge/license-MIT-brightgreen.svg)
![min](https://img.shields.io/bundlephobia/min/react-hyper-tree)
![minzip](https://img.shields.io/bundlephobia/minzip/react-hyper-tree)## 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
- [Installation](#installation)
- [Usage](#usage)
- [Properties](#properties)
- [API](#use-tree-state)
- [useTreeState API](#use-tree-state)
- [Node API](#node-api)
- [Global State Manager (GSM)](#global-state-manager)
- [Async children](#async-children)
- [Default properties](#default-props)
- [Road map](#road-map)
- [Contributing](#contributing)
- [License](#license)## [Live demo is available!](https://alekseymakhankov.github.io/packages/?package=hyper-tree)
### Check also [react-hyper-modal](https://www.npmjs.com/package/react-hyper-modal) library
###### You can use [![npm](https://api.iconify.design/logos:npm.svg?height=14)](https://www.npmjs.com/get-npm) or [![yarn](https://api.iconify.design/logos:yarn.svg?height=14)](https://yarnpkg.com/lang/en/docs/install) package managers
```console
$ npm i --save react-hyper-tree
```**or**
```console
$ yarn add react-hyper-tree
```### Simple Usage
```javascript
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 (
)
}
```| 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](https://www.w3schools.com/html/html5_svg.asp) 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](https://www.w3schools.com/html/html5_svg.asp) properties |
| verticalLineTopOffset? | vertical line top offset |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.
| 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 |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_.
```typescript
type Handler = (...args: any[]) => anyinterface 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:
```javascript
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:
```javascript
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
```javascript
treeHandlers
.safeUpdateHandler(id, 'setLoading', setLoading)
.safeUpdateHandler(id, 'setSelected', setSelected)
.safeUpdateHandler(id, 'setRawChildren', setRawChildren)
.safeUpdateHandler(id, 'setChildren', setChildren)
```You also can use loadable children. To enable the feature you should provide _getChildren_ function to node data
```javascript
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:
```javascript
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_
```typescript
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
}
```- Coverage by tests
- Inner improvements and extending functionality
- Documentation improvementsPull requests are welcome. For major changes, please open an issue first to discuss what you would like to change.
[MIT](https://choosealicense.com/licenses/mit/)