diff --git a/example/theme.less b/example/theme.less
index 5c7f9386..e9097932 100644
--- a/example/theme.less
+++ b/example/theme.less
@@ -4,14 +4,12 @@
left: 0;
bottom: 0;
width: 300px;
- overflow-x: hidden;
- overflow-y: auto;
background-color: #21252B;
}
.m-node {
&.placeholder {
- border: 1px dashed #1385e5;
+ outline: 1px dashed #1385e5;
}
.inner {
diff --git a/example/tree.js b/example/tree.js
index 958dd15c..0562ea95 100644
--- a/example/tree.js
+++ b/example/tree.js
@@ -37,6 +37,9 @@ module.exports = {
{
module: 'index.html',
leaf: true
+ },
+ {
+ module: 'test-folder'
}
]
},
@@ -88,6 +91,9 @@ module.exports = {
{
module: 'webpack.config.js',
leaf: true
+ },
+ {
+ module: 'test-folder-2'
}
]
};
diff --git a/lib/react-ui-tree.js b/lib/react-ui-tree.js
index f63dbf1b..41956c6e 100644
--- a/lib/react-ui-tree.js
+++ b/lib/react-ui-tree.js
@@ -7,12 +7,16 @@ class UITree extends Component {
static propTypes = {
tree: PropTypes.object.isRequired,
paddingLeft: PropTypes.number,
+ scrollMargin: PropTypes.number,
+ scrollSpeed: PropTypes.number,
renderNode: PropTypes.func.isRequired,
draggable: PropTypes.bool
};
static defaultProps = {
paddingLeft: 20,
+ scrollMargin: 20,
+ scrollSpeed: 200,
draggable: true
};
@@ -20,6 +24,13 @@ class UITree extends Component {
super(props);
this.state = this.init(props);
+ this.treeEl = React.createRef();
+
+ this.startScrollHeight = null;
+ this.lastMousePos = { clientX: null, clientY: null };
+ this.scrollEnabled = false;
+ this.currentScrollSpeed = 0;
+ this.lastScrollTimestamp = null;
}
componentWillReceiveProps(nextProps) {
@@ -80,7 +91,7 @@ class UITree extends Component {
const draggingDom = this.getDraggingDom();
return (
-
+
{draggingDom}
{
if (e.button !== 0 || id === 1) return;
+ const { scrollHeight, scrollTop } = this.treeEl.current;
+
+ this.startScrollHeight = scrollHeight;
+
this.setState({
dragging: {
id: id,
w: dom.offsetWidth,
h: dom.offsetHeight,
+ ph: dom.parentNode.offsetHeight,
x: dom.offsetLeft,
y: dom.offsetTop,
},
@@ -110,18 +126,48 @@ class UITree extends Component {
x: dom.offsetLeft,
y: dom.offsetTop,
offsetX: e.clientX,
- offsetY: e.clientY
+ offsetY: e.clientY + scrollTop
}
});
window.addEventListener('mousemove', this.drag);
window.addEventListener('mouseup', this.dragEnd);
+
+ this.lastMousePos.clientX = e.clientX;
+ this.lastMousePos.clientY = e.clientY;
+ this.scrollEnabled = true;
+ requestAnimationFrame(this.scroll);
+ };
+
+ scroll = (timestamp) => {
+ if (!this.scrollEnabled) return;
+
+ if (this.lastScrollTimestamp === null || this.currentScrollSpeed === 0){
+ this.lastScrollTimestamp = timestamp;
+ requestAnimationFrame(this.scroll);
+ return;
+ }
+
+ const delta = timestamp - this.lastScrollTimestamp;
+ this.treeEl.current.scrollTop += this.currentScrollSpeed * delta / 1000;
+ this.drag(this.lastMousePos);
+
+ this.lastScrollTimestamp = timestamp;
+ requestAnimationFrame(this.scroll);
};
- drag = e => {
+ drag = (e) => {
+ if (e) {
+ this.lastMousePos.clientX = e.clientX;
+ this.lastMousePos.clientY = e.clientY;
+ } else {
+ e = this.lastMousePos;
+ }
+ const { clientX, clientY } = e;
+
const tree = this.state.tree;
const dragging = this.state.dragging;
- const paddingLeft = this.props.paddingLeft;
+ const { paddingLeft, scrollMargin, scrollSpeed } = this.props;
let newIndex = null;
let index = tree.getIndex(dragging.id);
@@ -134,9 +180,11 @@ class UITree extends Component {
const _offsetX = this.state.start.offsetX;
const _offsetY = this.state.start.offsetY;
+ const { scrollTop, clientHeight } = this.treeEl.current;
+
const pos = {
- x: _startX + e.clientX - _offsetX,
- y: _startY + e.clientY - _offsetY
+ x: _startX + clientX - _offsetX,
+ y: Math.min(this.startScrollHeight - dragging.ph, _startY + clientY + scrollTop - _offsetY)
};
dragging.x = pos.x;
dragging.y = pos.y;
@@ -198,7 +246,15 @@ class UITree extends Component {
newIndex.node.collapsed = collapsed;
dragging.id = newIndex.id;
}
-
+
+ if (dragging.y + dragging.ph > scrollTop + clientHeight - scrollMargin) {
+ this.currentScrollSpeed = scrollSpeed;
+ } else if (dragging.y < scrollTop + scrollMargin) {
+ this.currentScrollSpeed = -scrollSpeed;
+ } else {
+ this.currentScrollSpeed = 0;
+ }
+
this.setState({
tree: tree,
dragging: dragging
@@ -222,6 +278,10 @@ class UITree extends Component {
window.removeEventListener('mousemove', this.drag);
window.removeEventListener('mouseup', this.dragEnd);
+ this.lastMousePos.clientX = null;
+ this.lastMousePos.clientY = null;
+ this.scrollEnabled = false;
+
const index = this.state.tree.getIndex(draggingId);
if (index === undefined) return;
diff --git a/lib/react-ui-tree.less b/lib/react-ui-tree.less
index 3c255719..9fd9e0d4 100644
--- a/lib/react-ui-tree.less
+++ b/lib/react-ui-tree.less
@@ -8,7 +8,9 @@
.m-tree {
position: relative;
- overflow: hidden;
+ overflow-x: hidden;
+ overflow-y: auto;
+ height: 100%;
.f-no-select;
}
@@ -24,7 +26,7 @@
}
&.placeholder {
- border: 1px dashed #ccc;
+ outline: 1px dashed #ccc;
}
.inner {