├── .eslintrc.js ├── .gitignore ├── .prettierignore ├── .prettierrc ├── .travis.yml ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── jest.config.js ├── jest.transform.js ├── nwb.config.js ├── package.json ├── src ├── Node.js ├── ToggleController.js ├── Treefold.js └── index.js ├── storybook ├── .babelrc ├── .eslintrc.js ├── Animated.js ├── Async │ ├── AsyncTree.js │ ├── Controller.js │ ├── data.js │ └── index.js ├── Dropdown │ ├── Dropdown.js │ ├── filterTree.js │ ├── index.js │ └── style.css ├── FamilyTree │ ├── README.md │ ├── data.js │ ├── index.js │ └── styles.css ├── Layout │ ├── index.js │ └── styles.css ├── Selector.js ├── Table.js ├── UnorderedList.js ├── config.js ├── data.js ├── index.js ├── package.json ├── preview-head.html ├── styles.css └── utils.js ├── tests ├── ToggleController.test.js ├── Treefold.test.js └── setup.js └── yarn.lock /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | parser: 'babel-eslint', 3 | extends: [ 4 | 'eslint:recommended', 5 | 'plugin:import/recommended', 6 | 'plugin:react/recommended', 7 | ], 8 | parserOptions: { 9 | ecmaVersion: 6, 10 | sourceType: 'module', 11 | ecmaFeatures: { 12 | jsx: true, 13 | experimentalObjectRestSpread: true, 14 | }, 15 | }, 16 | env: { 17 | browser: true, 18 | node: true, 19 | jest: true, 20 | }, 21 | rules: { 22 | 'valid-jsdoc': 2, 23 | 'react/prop-types': 0, 24 | 'react/jsx-uses-react': 1, 25 | 'react/jsx-no-undef': 2, 26 | 'react/display-name': 0, 27 | 'import/no-unresolved': ['error', { ignore: ['^react$'] }], 28 | 'import/unambiguous': 0, 29 | 'react/jsx-key': 0, 30 | }, 31 | plugins: ['import', 'react'], 32 | }; 33 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.log 2 | /coverage 3 | /es 4 | /lib 5 | /umd 6 | /storybook-static 7 | /storybook/yarn.lock 8 | /storybook/package-lock.json 9 | node_modules 10 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | package.json 2 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "trailingComma": "es5", 3 | "singleQuote": true 4 | } 5 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: false 2 | 3 | language: node_js 4 | node_js: 5 | - 8 6 | 7 | before_install: 8 | - npm install codecov.io coveralls 9 | 10 | after_success: 11 | - cat ./coverage/lcov.info | ./node_modules/codecov.io/bin/codecov.io.js 12 | - cat ./coverage/lcov.info | ./node_modules/coveralls/bin/coveralls.js 13 | 14 | branches: 15 | only: 16 | - master 17 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | ## Prerequisites 2 | 3 | [Node.js](http://nodejs.org/) >= v8 must be installed. 4 | 5 | ## Installation 6 | 7 | * Running `yarn install` in the component's root directory will install everything you need for development. 8 | 9 | ## Demo 10 | 11 | * `yarn storybook` will run a [storybook](https://storybook.js.org/) server with the component's demo views at [http://localhost:9001](http://localhost:9001). 12 | 13 | ## Running Tests 14 | 15 | * `yarn test` will run on every change, only the tests related to what has changed 16 | 17 | * `yarn test:all` will run all the tests once 18 | 19 | ## Building 20 | 21 | * `yarn build` will build the component for publishing to npm. 22 | 23 | * `yarn clean` will delete built resources. 24 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | Copyright (c) 2018 Ernesto García 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in all 12 | copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | SOFTWARE. 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Treefold 2 | 3 | [![styled with prettier](https://img.shields.io/badge/styled_with-prettier-ff69b4.svg)](https://github.com/prettier/prettier) 4 | 5 | A renderless tree React component for your hierarchical views. 6 | 7 | ## The problem 8 | 9 | You need to show hierarchical data in different ways. You know how you want to show the information for each individual data item. But you don't want to repeat over and over again the logic about how to traverse the data, how to assemble it all to make it look like a tree, how to expand/collapse nodes, etc. 10 | 11 | ## This solution 12 | 13 | This is a component that abstracts away some of these repetitive details during a tree-rendering process. You just specify how you want to render each individual data item, and `Treefold` takes care of everything else. 14 | 15 | The component itself is stateless and controlled by default, so you can control any aspects of it from the outside. The expand/collapse state of each individual node is normally also controlled, but if no props for controlling it are specified, the component auto-manages the state for this on its own. 16 | 17 | You can see a live demo [here](http://treefold.netlify.com/). 18 | 19 | ## Installation 20 | 21 | This module is distributed via [npm](https://www.npmjs.com/) which is bundled with [node](https://nodejs.org) and should be installed as one of your project's `dependencies`: 22 | 23 | ``` 24 | npm install --save react-treefold 25 | ``` 26 | 27 | or if you use [yarn](https://yarnpkg.com/): 28 | 29 | ``` 30 | yarn add react-treefold 31 | ``` 32 | 33 | > This package also depends on `react` and `prop-types`. Please make sure you have those installed as well. 34 | 35 | ## Usage 36 | 37 | Use the `Treefold` component by passing to it the hierarchical data (`nodes` prop) and how to render each node in the tree (`render` prop): 38 | 39 | ```jsx 40 | import React from 'react'; 41 | import Treefold from 'react-treefold'; 42 | 43 | const MyTreeView = ({ nodes }) => ( 44 |
45 | ( 56 | <> 57 |
58 | {isFolder && ( 59 | 60 |