GithubHelp home page GithubHelp logo

swiftcarrot / react-ui-tree Goto Github PK

View Code? Open in Web Editor NEW
755.0 22.0 202.0 454 KB

React tree component with drag & drop

Home Page: https://swiftcarrot.github.io/react-ui-tree/

License: MIT License

CSS 13.18% JavaScript 81.68% HTML 5.14%
react javascript tree draggable

react-ui-tree's Introduction

react-ui-tree

Build Status npm npm

React tree component

This project was initially developed for a webpage builder. It maintains an internal tree structure within the component through js-tree.

Demo

swiftcarrot.github.io/react-ui-tree/

Installation

npm install react-ui-tree --save

Usage

<Tree
  paddingLeft={20}              // left padding for children nodes in pixels
  tree={this.state.tree}        // tree object
  onChange={this.handleChange}  // onChange(tree) tree object changed
  renderNode={this.renderNode}  // renderNode(node) return react element
/>

// a sample tree object
// node.children, node.collapsed, node.leaf properties are hardcoded
{
  "module": "react-ui-tree",
  "children": [{
    "collapsed": true,
    "module": "dist",
    "children": [{
      "module": "node.js"
    }]
  }]
}

check app.js for a working example

Development

License

MIT

react-ui-tree's People

Contributors

ga-mo avatar juzhiyuan avatar robertlong avatar wangzuo avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

react-ui-tree's Issues

getting wrong mouse position if page is scrolled while dragging

This can be reproduced in the example, resize your browser window and make it shorter than the tree.
if you scroll the window when you are dragging a node. The node will go to a wrong position.
Solutions could be stop drag and drop the node at where it is when start a scroll
or count the scrollTop value in the drag handler.

webpack: Failed to compile with npm start

when i run the demo ,it throw this error.
ERROR in ./example/app.js
Module build failed: SyntaxError: Unexpected token (12:8)

  10 |
  11 | class App extends Component {
> 12 |   state = {
     |         ^
  13 |     active: null,
  14 |     tree: tree
  15 |   };

React 15

Hey, any plans to support React 15?

Drag and drop doesn't work correctly unless all of the nodes are the same height.

The DnD functionality assumes that all nodes are the same height in the diffY calculation. If a node is of a different size and you begin dragging it down, the initial diffY is < 0, indicating to the code that we're actually dragging up. Not a huge deal, but once you've dragged sufficiently to get diffY into positive territory, you have to weight until you've gone twice the height of node you're dragging before it registers as below the next lower node. This is due to the } else if (diffY > dragging.h) { clause at line 167. Should probably be (diffY > index.height), but again, the diffY calculation is off. I think there needs to be separate calculations based on whether the drag is up or down, but I'm not sure.

I've been trying to solve this bug as it impacts my group, but so far haven't had any luck. I'll submit a PR if I do find a solution.

Fire onMove for nodes that were moved

So that I can make API calls with an updated path for a particular object, I'd like it if if there was a handleMove/onMove hook for when an object is moved. This would be sent a parameter of the object being moved, and ideally include its path.

I'll have a look and see if I can do this.... but obviously other contributions welcome!

Trying to convert to JSX

Hi there, great component here!

I'm attempting to convert the lib to JSX for front end use as it's my preferred format to edit things in. I'm running into some issues though and I can't really figure out what's happening.

The tree loads, but no child nodes are getting rendered. I also don't get any errors...I'll attach the working files maybe you can easily see where I'm going wrong. FYI I'm pretty sure I am using React.addons.classSet incorrectly but I don't think that should cause this issue specifically.

Tree.js

var Tree = function (obj) {
  this.cnt = 1;
  this.obj = obj || {children:[]};
  this.indexes = {};
  this.build(this.obj);
}

var proto = Tree.prototype;

proto.build = function(obj) {
  var indexes = this.indexes;
  var startId = this.cnt;
  var self = this;
  var index = {id: startId, node: obj};

  indexes[this.cnt + ''] = index;
  this.cnt ++;

  if(obj.children && obj.children.length) walk(obj.children, index);

  function walk(objs, parent) {
    var children = [];

    objs.forEach(function(obj, i) {
      var index = {};

      index.id = self.cnt;
      index.node = obj;

      if(parent) index.parent = parent.id;

      indexes[self.cnt + ''] = index;
      children.push(self.cnt);
      self.cnt ++;

      if(obj.children && obj.children.length) walk(obj.children, index);
    });
    parent.children = children;

    children.forEach(function(id, i) {
      var index = indexes[id + ''];
      if(i > 0) index.prev = children[i - 1];
      if(i < children.length - 1) index.next = children[i + 1];
    });
  }

  return index;
};

proto.getIndex = function(id) {
  var index = this.indexes[id + ''];
  if(index) return index;
};

proto.removeIndex = function(index) {
  var self = this;

  del(index);

  function del(index) {
    delete self.indexes[index.id + ''];
    if(index.children && index.children.length) {
      index.children.forEach(function(child) {
        del(self.getIndex(child));
      });
    }
  }
};

proto.get = function(id) {
  var index = this.getIndex(id);

  if(index && index.node) return index.node;

  return null;
};

proto.remove = function(id) {
  var index = this.getIndex(id);
  var node = this.get(id);
  var parentIndex = this.getIndex(index.parent);
  var parentNode = this.get(index.parent);

  parentNode.children.splice(parentNode.children.indexOf(node), 1);
  parentIndex.children.splice(parentIndex.children.indexOf(id), 1);

  this.removeIndex(index);
  this.updateChildren(parentIndex.children);

  return node;
};

proto.updateChildren = function(children) {
  children.forEach(function(id, i) {
    var index = this.getIndex(id);

    index.prev = index.next = null;

    if(i > 0) index.prev = children[i - 1];
    if(i < children.length-1) index.next = children[i + 1];
  }.bind(this));
};

proto.insert = function(obj, parentId, i) {
  var parentIndex = this.getIndex(parentId);
  var parentNode = this.get(parentId);
  var index = this.build(obj);

  index.parent = parentId;

  parentNode.children = parentNode.children || [];
  parentIndex.children = parentIndex.children || [];

  parentNode.children.splice(i, 0, obj);
  parentIndex.children.splice(i, 0, index.id);

  this.updateChildren(parentIndex.children);

  if(parentIndex.parent) {
    this.updateChildren(this.getIndex(parentIndex.parent).children);
  }

  return index;
};

proto.insertBefore = function(obj, destId) {
  var destIndex = this.getIndex(destId);
  var parentId = destIndex.parent;
  var i = this.getIndex(parentId).children.indexOf(destId);

  return this.insert(obj, parentId, i);
};

proto.insertAfter = function(obj, destId) {
  var destIndex = this.getIndex(destId);
  var parentId = destIndex.parent;
  var i = this.getIndex(parentId).children.indexOf(destId);

  return this.insert(obj, parentId, i + 1);
};

proto.prepend = function(obj, destId) {
  return this.insert(obj, destId, 0);
};

proto.append = function(obj, destId) {
  var destIndex = this.getIndex(destId);

  destIndex.children = destIndex.children || [];

  return this.insert(obj, destId, destIndex.children.length);
};

proto.updateNodesPosition = function () {
  var top = 1;
  var left = 1;
  var root = this.getIndex(1);
  var self = this;

  root.top = top++;
  root.left = left++;

  walk(root.children, root, left, root.node.collapsed);

  function walk(children, parent, left, collapsed) {
    var height = 1;

    children.forEach(function (id) {
      var node = self.getIndex(id);

      if (collapsed) {
        node.top = null;
        node.left = null;
      } else {
        node.top = top++;
        node.left = left;
      }

      if (node.children && node.children.length) {
        height += walk(node.children, node, left + 1, collapsed || node.node.collapsed);
      } else {
        node.height = 1;
        height += 1;
      }
    });

    if (parent.node.collapsed) parent.height = 1;else parent.height = height;

    return parent.height;
  }
};

proto.move = function (fromId, toId, placement) {
  if (fromId === toId || toId === 1) return;

  var obj = this.remove(fromId);
  var index = null;

  if (placement === 'before') index = this.insertBefore(obj, toId);else if (placement === 'after') index = this.insertAfter(obj, toId);else if (placement === 'prepend') index = this.prepend(obj, toId);else if (placement === 'append') index = this.append(obj, toId);

  // todo: perf
  this.updateNodesPosition();
  return index;
};

proto.getNodeByTop = function (top) {
  var indexes = this.indexes;

  for (var id in indexes) {
    if (indexes.hasOwnProperty(id)) {
      if (indexes[id].top === top) return indexes[id];
    }
  }
};

TreeNode.jsx

var cx = React.addons.classSet;
var TreeNode = React.createClass({
    displayName:'TreeUINode',

    renderCollapse:function () {
        var index = this.props.index;

        if (index.children && index.children.length) {
            var collapsed = index.node.collapsed;

            return (
                <span
                    className={cx('collapse', collapsed ? 'caret-right' : 'caret-down')}
                    onMouseDown={this.stopMouseDown}
                    onClick={this.handleCollapse}
                >
                </span>
            );
        }

        return null;
    },

    renderChildren:function () {
        var _this = this;
        var index = this.props.index;
        var tree = this.props.tree;
        var dragging = this.props.dragging;

        if (index.children && index.children.length) {
            var childrenStyles = {};

            if (index.node.collapsed) childrenStyles.display = 'none';

            childrenStyles.paddingLeft = this.props.paddingLeft + 'px';

            console.log(index);

            return (
                <div className='children' style={childrenStyles}>
                    {
                        index.children.map(function (child) {
                            var childIndex = tree.getIndex(child);
                            <TreeNode
                                tree={tree}
                                index={childIndex}
                                key={childIndex.id}
                                dragging={dragging}
                                paddingLeft={_this.props.paddingLeft}
                                onCollapse={_this.props.onCollapse}
                                onDragStart={_this.props.onDragStart}
                            />
                        })
                    }
                </div>
            );

            return null;
        }
    },

    handleCollapse:function (e) {
        e.stopPropagation();
        var nodeId = this.props.index.id;
        if (this.props.onCollapse) this.props.onCollapse(nodeId);
    },

    stopMouseDown:function (e) {
        e.stopPropagation();
    },

    handleMouseDown:function (e) {
        var nodeId = this.props.index.id;
        var dom = this.refs.inner.getDOMNode();

        if (this.props.onDragStart) {
            this.props.onDragStart(nodeId, dom, e);
        }
    },

    render:function () {
        var tree = this.props.tree;
        var index = this.props.index;
        var dragging = this.props.dragging;
        var node = index.node;
        var styles = {};

        return (
            <div
                className={cx('m-node', {placeholder: index.id === dragging})}
                styles={styles}
            >
                <div
                    className='inner'
                    ref='inner'
                    onMouseDown={this.handleMouseDown}
                >
                    {this.renderCollapse()}
                    {tree.renderNode(node)}
                </div>
                {this.renderChildren()}
            </div>
        );
    }
});

TreeUI.jsx

var TreeUI = React.createClass({
    displayName: 'TreeUI',

    propTypes: {
        tree: React.PropTypes.object.isRequired,
        paddingLeft: React.PropTypes.number,
        renderNode: React.PropTypes.func.isRequired
    },

    getDefaultProps: function() {
        return {
            paddingLeft: 20
        };
    },

    getInitialState: function() {
        return this.init(this.props);
    },

    componentWillReceiveProps: function (nextProps) {
        if (!this._updated) this.setState(this.init(nextProps));else this._updated = false;
    },

    init:function (props) {
        var tree = new Tree(props.tree);

        tree.isNodeCollapsed = props.isNodeCollapsed;
        tree.renderNode = props.renderNode;
        tree.changeNodeCollapsed = props.changeNodeCollapsed;
        tree.updateNodesPosition();

        return {
            tree: tree,
            dragging: {
                id: null,
                x: null,
                y: null,
                w: null,
                h: null
           }
        };
    },

    getDraggingDom:function () {
        var tree = this.state.tree;
        var dragging = this.state.dragging;

        if (dragging && dragging.id) {
            var draggingIndex = tree.getIndex(dragging.id);
            var draggingStyles = {
                top: dragging.y,
                left: dragging.x,
                width: dragging.w
            };

            return (
                <div className='m-draggable' style={draggingStyles}>
                    <TreeNode
                        tree={tree}
                        index={draggingIndex}
                        paddingLeft={this.props.paddingLeft}
                    />
                 </div>
             );
         }

         return null;
     },

    dragStart:function (id, dom, e) {
        this.dragging = {
            id: id,
            w: dom.offsetWidth,
            h: dom.offsetHeight,
            x: dom.offsetLeft,
            y: dom.offsetTop
        };

        this._startX = dom.offsetLeft;
        this._startY = dom.offsetTop;
        this._offsetX = e.clientX;
        this._offsetY = e.clientY;
        this._start = true;

        window.addEventListener('mousemove', this.drag);
        window.addEventListener('mouseup', this.dragEnd);
     },

    drag:function (e) {
        if (this._start) {
            this.setState({
                dragging: this.dragging
            });

           this._start = false;
        }

        var tree = this.state.tree;
        var dragging = this.state.dragging;
        var paddingLeft = this.props.paddingLeft;
        var newIndex = null;
        var index = tree.getIndex(dragging.id);
        var collapsed = index.node.collapsed;

        var _startX = this._startX;
        var _startY = this._startY;
        var _offsetX = this._offsetX;
        var _offsetY = this._offsetY;

        var pos = {
            x: _startX + e.clientX - _offsetX,
            y: _startY + e.clientY - _offsetY
        };

        dragging.x = pos.x;
        dragging.y = pos.y;

        var diffX = dragging.x - paddingLeft / 2 - (index.left - 2) * paddingLeft;
        var diffY = dragging.y - dragging.h / 2 - (index.top - 2) * dragging.h;

        if (diffX < 0) {
           // left
            if (index.parent && !index.next) {
                newIndex = tree.move(index.id, index.parent, 'after');
            }
        } else if (diffX > paddingLeft) {
            // right
            if (index.prev && !tree.getIndex(index.prev).node.collapsed) {
                newIndex = tree.move(index.id, index.prev, 'append');
            }
        }

        if (newIndex) {
            index = newIndex;
            newIndex.node.collapsed = collapsed;
            dragging.id = newIndex.id;
        }

        if (diffY < 0) {
            // up
            var above = tree.getNodeByTop(index.top - 1);
            newIndex = tree.move(index.id, above.id, 'before');
        } else if (diffY > dragging.h) {
            // down
            if (index.next) {
                var below = tree.getIndex(index.next);

                if (below.children && below.children.length && !below.node.collapsed) {
                    newIndex = tree.move(index.id, index.next, 'prepend');
                } else {
                    newIndex = tree.move(index.id, index.next, 'after');
            }
        } else {
                var below = tree.getNodeByTop(index.top + index.height);
                if (below && below.parent !== index.id) {
                    if (below.children && below.children.length) {
                        newIndex = tree.move(index.id, below.id, 'prepend');
                    } else {
                        newIndex = tree.move(index.id, below.id, 'after');
                    }
                }
           }
        }

        if (newIndex) {
            newIndex.node.collapsed = collapsed;
            dragging.id = newIndex.id;
        }

        this.setState({
            tree: tree,
            dragging: dragging
        });
     },

    dragEnd: function () {
        this.setState({
            dragging: {
                id: null,
                x: null,
                y: null,
                w: null,
                h: null
            }
        });

        this.change(this.state.tree);

        window.removeEventListener('mousemove', this.drag);
        window.removeEventListener('mouseup', this.dragEnd);
    },

    change: function (tree) {
        this._updated = true;
        if (this.props.onChange) this.props.onChange(tree.obj);
    },

    toggleCollapse: function (nodeId) {
        var tree = this.state.tree;
        var index = tree.getIndex(nodeId);
        var node = index.node;

        node.collapsed = !node.collapsed;
        tree.updateNodesPosition();

        this.setState({
            tree: tree
        });

        this.change(tree);
    },

    render: function() {
        var tree = this.state.tree;
        var dragging = this.state.dragging;
        var draggingDom = this.getDraggingDom();

        return (
            <div className='m-tree'>
                {draggingDom}
                <TreeNode
                    tree={tree}
                    index={tree.getIndex(1)}
                    key={1}
                    paddingLeft={this.props.paddingLeft}
                    onDragStart={this.dragStart}
                    onCollapse={this.toggleCollapse}
                    dragging={dragging && dragging.id}
                />
            </div>
        );
    },
});

Performance

Not exactly an issue but I'd love to see what kind of hit others are taking performance wise, I'm currently taking the following hit for 982 nodes

perf

It's taking quite a while as you can see. Is this to be expected? I'm testing on Windows 7 enterprise with Chrome v43.0.2357.132

Issue: node being dragged always under passing nodes, should be above.

First off I want to thank you for this great app. I am trying to avoid jQuery at all cost and this saved the day for me. In my case I turned your treeview into a nested list.

My only issue is the drag over. The node being dragged is always under the passing nodes when it should be above.

I tried everything, eg, z-index, position, etc.

What would anyone recommend?

Crash when providing a tree with a root node and no child nodes.

This works:
{tree:{"name": "Channel Name","type": "channel","children":[{}]}

this doesn't:
{tree:{"name": "Channel Name","type": "channel","children":[]}

Crashes on call to children.forEach under walk() in the updateNodesPosition function. Children is undefined.

can add drag limit?

is there anyway to limit drag at the same parent?
ps

tree = {
  module: 'tree',
  children: [
    { 
      module: 'parentA',
      children: [
        { module: 'a1'},
        { module: 'a2'}
      ]
    },
    { 
      module: 'parentB',
      children: [
        { module: 'b1'},
        { module: 'b2'}
      ]
    }
  ]
}

parentA's children can only drag in parentA;
can add drag limit ? such as beforeDrag callback to stop dragging.

Change tree only on changing parent of dragging node

I need to use drag-n-drop feature only to change parents of nodes, not sorting (because all nodes will be sorted in alphabetic or another order that can be defined by user). And I think it's a common case of the use of tree view. So it would be great if there will be an option, that will:

  • onDragEnd revert tree state into old state if dragging node didn't change his parent (so node will be placed to its place) and call onChange
  • (optional) make draggable placeholder appears only inside other folders (nodes that can be parents)

Maybe someone already solved this issue and can share the solution?
Thanks!

Clicking on a renderedNode triggers drag.

Clicking on a renderedNode triggers drag. Propagation is stopped, so rendered node never gets click event. Drag-n-drop feature should have a disable option or implemented properly with distinguishing click and drag.

Some dragging issues

Wondering if this is related to #2, but you can test it in the example. Add a bunch of items and go to one near the bottom of the list and drag it. For me, the update of the cloned draggingDom is a bit slow, there's quite a bit of a delay between the node being dragged and the draggingDom. Any idea for improvements here?

Only one top node?

Is the component limited to one top node or is this in some way configurable ?

Lazy loading

I have a very large tree that I won't be able to load on initialization. Would it be possible to do lazy loading? A user clicks on a node and fetches data from server and adds it to the tree. We would need some way of telling the node that it has children but it should be loaded from the server.

Click on a node opens all siblings too

I noticed odd behaviour when testing the demo at the demo page.
when I close the tree, and click 1 of the nodes to open, it's siblings pop open as well.

note when I click the arrow it only opens the one, but when I click the name it opens all siblings.

see gif for detail info
weird-behaviour

Build

How can I build the demo? In terminal wrote 'npm test', and it passes the test. But how can I build it into a web page? I saw that the port is 8888, but if I put 'localhost:8888' in the url it shows me just the files from this project. Exactly, how can I test the demo from my own pc? (If the demo is builded)

Feature request: ability to validate change on (or before) change.

I've tried returning false from the onChange event I've provided to the Tree, but even though I'm not updating the underlying data structure (this.state.tree), the UI still updates. It would be really nice to be able to run some checks and possibly prevent this from happening.

leaf node support

Are there any planing to support leaf node?

Particularly, I'm implementing a file manager, in which there are two types of nodes, folder and file. You can only drag a file or folder into a folder, but can't drag them into a file. It seems a little hard to achieve this behaviour using this lib.

Drag and Drop support for touch enabled devices

I am trying to add DnD support for touch enabled devices and it seems to be behaving weirdly. While dragging seems to start with touchmove event and stops abruptly. But if you pickup from the same position and move, then things seem to work. Here is the GIF file just to show that.
react-ui-tree-dnd-issue

Observations so far:

  • Seems react is somehow not happy with tree being modified with tree.move() inside drag() method.
  • Seems react is somehow not happy with setState().
  • When drag starts and suddenly stops, we see the page scrolls so guessing the event has stopped midway by react but not sure.

All my changes are in this repo https://github.com/venugopalkathavate/react-ui-tree.git if you want to check. NOTE this can be reproduced with Chrome dev tools.

My fix for the example

The example in the repo is outdated, so I analyzed the code of the demo page.

app.js

const React = require('react')
const Tree = require('react-ui-tree')
const cx = require('classnames')

const tree = require('./tree')

class App extends React.Component {
  constructor (props) {
    super(props)

    this.active = null
    this.state = {
      tree: tree
    }

    this.onClickNode = this.onClickNode.bind(this)
    this.renderNode = this.renderNode.bind(this)
    this.handleChange = this.handleChange.bind(this)
  }

  render () {
    return (
        <div className='tree'>
          <Tree
            paddingLeft={15}
            onChange={this.handleChange}
            isNodeCollapsed={this.isNodeCollapsed}
            tree={this.state.tree}
            renderNode={this.renderNode}
          />
        </div>
    )
  }

  renderNode (node) {
    return (
      <span
        className={cx('node', {
          'is-active': node === this.active
        })}
        onClick={this.onClickNode}
      >
        {node.module}
      </span>
    )
  }

  onClickNode (node) {
    this.active = node
  }

  handleChange (tree) {
    this.setState({
      tree: tree
    })
  }
}

module.exports = App

theme.css

.tree {
  /* Your definition here*/
}

.f-no-select, .m-tree {
  user-select: none;
}
.m-draggable{
  position: absolute;
  opacity: .8;
  user-select: none;
}
.m-node.placeholder > * {
  visibility: hidden;
}
.m-node.placeholder {
  border: 1px dashed #ccc;
}
.m-node .inner {
  position: relative;
  cursor: pointer;
  padding-left: 10px;
  color: #9da5b4;
  font-size: 12px;
  font-family: Menlo;
}
.m-node .collapse {
  position: absolute;
  left: 0;
  cursor: pointer;
}
.m-node .caret-right:before {
  content: "\25B8";
}
.m-node .caret-down:before{
  content: "\25BE";
}
.m-node .node {
  display: inline-block;
  width: 100%;
  padding: 4px 5px;
}
.m-node .node.is-active {
  background-color:#31363f;
}

clicking node or collapse causes tree to ignore next prop change

We are swapping out the tree prop to show different trees when the user clicks on a navigation link. When the user clicks on a node in the tree or clicks on a collapse icon, the next time they click on one of the external navigation links, the tree ignores the new prop.

The problem appears to be in the componentWillReceiveProps method which checks the status of _updated in order to determine whether or not to initialize a new tree. Clicking a node or collapse icon sets _updated to true which prevents initialization of a new tree, even though that is the desired outcome when a different tree is passed in as a prop.

_updated is only ever reset to false when the component is getting new props, so I can't see what purpose this check serves. I can fix my issue by removing this check, but without knowing why the check is there in the first place, I am hesitant to do so.

Level three nodes cant have children

Consider the case of the following Tree:

  • Root
    • Level 1
      • Level 2 Node
      • Another Level 2 Node
    • New node

The component will not let me drag "New node" into any level 2 node. To do this, I have to drag out a level 2 node, drag the "New node" into it and then drag it back into level 1.

After doing this, the tree will end up like this:

  • Root
    • Level 1
      • Level 2 Node
      • Another Level 2 Node
        • New node

I have tried to debug why this is happening but couldn't find any solution. In the github page example, this behaviour happens too.

Styles

Is it possible to change CSS on a node when it's clicked? I'd like to check and uncheck items when they are selected.

Redux implementation with normalized data

Hi everyone !
I'd like to solve a problem with you. How would you implement react-ui-tree with normalised data;
Like Dan Abramov advised, we can shape our store like this in the case of comments as entity:

{
  comments: {
    1: {
      id: 1,
      children: [2, 3]
    },
    2: {
      id: 2,
      children: []
    },
    3: {
      id: 3,
      children: [42]
    },
    ...
  }
}

I'd like to implement with the same store this UI Tree component.
I've seen the example of a tree view on redux repo (https://github.com/reactjs/redux/tree/master/examples/tree-view) but the only interesting implementation is deleting recursively.

How would you handle modifications and indent length for the UI tree?

run demo error

<Tree
    paddingLeft={20}
    tree={this.state.tree}
    onChange={this.handleChange}
    isNodeCollapsed={this.isNodeCollapsed}
    renderNode={this.renderNode}
/>

image

How to create tree with 1+n roots?

tree field is waiting for object
e.g.
state = { tree: { "module": "first-root", "children": [somechildren] } }
but what if I need 1+n roots?
I've tried to create tree without first module >
state = { tree: {"children": [somechildren] } }
and in the renderNode function added
if (!node.module) { return null; }
renders fine, but now draggable element has padding(shifted), because root doesn't contain node.
Need structure example:
state = { tree: [ { "module": "first-root", "children": [somechildren]}, { "module": "second-root", "children":[somechildren]}, etc. ]}

React 16

Hey, any plans to support React 16?

Is this project actively maintained?

We are evaluating using this project for our menu. There is couple items that we want solved, with pending PR. We also are ready to make some new PRs.

  • Ability to disable drag'n'drop #66
  • Ability to specify the handle for the drag'n'drop #54
  • Collapse hook #62
  • Notify only on real change #45

Some users created a fork to maintain this project (@dansumption and 167 others). I feel that these PR should be merged asap in this project but if you guys @wangzuo @robertlong @GA-MO don't have the time to manage this properly - which happen to all of us, please add maintainers. A few people have made clear that they would like to help, including me, and I feel it would be a great start.
@phraniiac @kaare @whortaneto @matthiaskrieft @ghemingway @alfonsogarciacaro @whitejava @frankPairs @tunanut @gabchang @matiasgarcia @dannav

there are errors in console, and no icon and draggable?

screen shot 2018-02-08 at 2 11 53 pm

When I immediately apply the following code, there is one error. Besides, there is no icon for three node. And when I drag the root node, the second error appears.

`

renderNode(node) {
console.log(node);
return
{node.module}
;
}

`

How do you avoid rendering first tree node

Thank you so much for this wonderful library! I'm getting this to work really well for my use-case. I have one problem to ask:

Currently, tree requires an initial first node with children e.g.

rootFolder
  fileA.js
  fileB.js
  folderA
    fileC.js

I want to be able to just render the flat entries (excluding rootFolder)

fileA.js
fileB.js
folderA
  fileC.js

Here is my codesandbox.io: https://codesandbox.io/s/j35ynz58q9.

I tried to play around with data.js but I could not get it to work well for me. Please let me know what I have to do to get this working. Thank you!

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.