1.1.0 • Published 6 years ago
react-tree-file-system v1.1.0
react-tree-file-system
A basic tree file system that allows customisation
- custom CSS and classNames
- drag and drop available
- demo available
1 Demo
Version 1.1.0

Version 1.0.6

You can also try out here
2 Get Started
# To download, either
npm install --save react-tree-file-system
# or
yarn add react-tree-file-systemIn your code
import Tree from 'react-tree-file-system';
// import stylesheet
import 'react-tree-file-system/index.css';Uncontrolled component
- you can toggle folder to open or close by using recursion
const recursiveSetState = (tree, indexes, currIndex, key, value) => {
  const dupTree= tree.slice();
  const getIndex = indexes[currIndex];
  if (currIndex === indexes.length - 1) {
    dupTree[getIndex][key] = value;
    return tree;
  }
  dupTree[getIndex].children = recursiveSetState(
    (dupTree[getIndex].children || []).slice(0),
    indexes,
    currIndex + 1, key, value
  );
  return dupTree;
}
// ...
class YourClass extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      treeValue: [
        {
          title: 'folder name'
          type: 'folder',
          children: [
            {
              title: 'child 1'
            },
            {
              title: 'child 2'
            },
            {
              title: 'child 3'
            }
          ]
        }
      ]
    }
  }
  render() {
    return (
      // ...
      <Tree
        value={this.state.treeValue}
        folderOnClick={(_, indexes, state) => {
          this.setState(prevState => {
            return {
              treeValue: recursiveSetState(prevState.treeValue, indexes, 0, 'isOpen', state);
            }
          });
        }}
      />
      // ...
    )
  }
}- you can support on drag with recursion
const recursivelySetChild = (tree, toIndexes, currIndex, extractData) => {
  const dupTree= tree.slice();
  const getIndex = toIndexes[currIndex];
  if (currIndex === toIndexes.length - 1) {
    dupTree[getIndex].children.push(extractData);
    return tree;
  }
  dupTree[getIndex].children = recursivelySetChild((dupTree[getIndex].children || []).slice(0), toIndexes, currIndex + 1, extractData);
  return dupTree;
}
const getRecursiveItem = (tree, fromIndexes, currIndex) => {
  const dupTree = tree.slice(0);
  const getIndex = fromIndexes[currIndex];
  if(currIndex === fromIndexes.length - 1) {
    const child = dupTree.filter((_, i) => i === getIndex);
    return child[0];
  }
  return getRecursiveItem((dupTree[getIndex].children || []).slice(0), fromIndexes, currIndex + 1);
}
const popRecursiveItem = (tree, fromIndexes, currIndex) => {
  const dupTree = tree.slice(0);
  const getIndex = fromIndexes[currIndex];
  if(currIndex === fromIndexes.length - 1) {
    const filtered = dupTree.filter((_, i) => i !== getIndex);
    return filtered;
  }
  const children = popRecursiveItem((dupTree[getIndex].children || []).slice(0), fromIndexes, currIndex + 1);
  dupTree[getIndex].children = children;
  return dupTree;
}
// ...
class YourClass extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      treeValue: [
        {
          title: 'folder name'
          type: 'folder',
          children: [
            {
              title: 'child 1'
            },
            {
              title: 'child 2'
            },
            {
              title: 'child 3'
            }
          ]
        }
      ]
    }
  }
  render() {
    return (
      // ...
      <Tree
        value={this.state.treeValue}
        onDrag={(fromIndexes, toIndexes) => {
          this.setState(prevState => {
            const extractData = getRecursiveItem(prevState.defaultTree, fromIndexes, 0);
            const extraData = recursivelySetChild(prevState.defaultTree, toIndexes, 0, extractData);
            const newData = popRecursiveItem(prevState.defaultTree, fromIndexes, 0);
            return {
              defaultTree: newData
            }
          })
        }}
      />
      // ...
    )
  }
}4 Tree Structure
// Node
interface Node {
  title: string,
  isOpen?: boolean,
  // isLocked?: boolean, // No support yet
  // isHidden?: boolean, // No support yet
  children?: Node[],
  folderIcon?: React.Element,
  fileIcon?: React.Element,
  style?: React.CSSProperties,
  className?: string,
  // able to add anything here
}
// Example
[
  {
    title: 'main', // what is displayed
    isOpen: false, // optional
    type: 'folder',
    folderIcon: <FolderIcon /> // optional
    children: [
      {
        title: 'Child 1',
      },
      {
        title: 'Readme.md',
        fileIcon: <FileIcon />, // optional
        text: 'demo text'
      },
    ]
  },
  // ... repeat Node
]5 API
| Property | Description | Type | Default | 
|---|---|---|---|
| value | The Tree structure given in point 4 | Node[] | undefined | 
| fileOnClick | Called when file is clicked | (event, indexes: number[], value: Node) => void | undefined | 
| folderOnClick | Called when folder is clicked | (event, indexes: number[], state: boolean, value: Node) => void | undefined | 
| onDrop | Called when something is dragged on folder Replace onDrag | (event, fromIndexes, toIndexes) => void | undefined | 
| onDrag | Called when something is dragged on folder Depreciated | (event, fromIndexes, toIndexes) => void | undefined | 
| folderIcon | Replace the default folder icon | JSX.Element | undefined | 
| fileIcon | Replace the default file icon | JSX.Element | undefined | 
| style | customize the general style | React.CSSProperties | undefined | 
| isDraggable | customize the general style | React.CSSProperties | false | 
| selected | Enable highlighting of cell clicked. Basically just store the indexes as indexes.join(',') | string | undefined | 
| selectedClassName | customize the highlighted style with your own className | string | undefined |