Skip to content

Commit aa9e547

Browse files
authored
Merge pull request #72 from NadavShaar/drag-and-drop
2 parents 2266d1c + 0c05ded commit aa9e547

14 files changed

Lines changed: 1752 additions & 9 deletions

File tree

package.json

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@nadavshaar/react-grid-table",
3-
"version": "0.2.2",
3+
"version": "0.3",
44
"description": "A modular table, based on a CSS grid layout, optimized for customization.",
55
"author": "Nadav Shaar",
66
"license": "MIT",
@@ -62,7 +62,8 @@
6262
},
6363
"peerDependencies": {
6464
"react": "^17.0.1",
65-
"react-dom": "^17.0.1"
65+
"react-dom": "^17.0.1",
66+
"prop-types": "^15.7.2"
6667
},
6768
"devDependencies": {
6869
"@babel/core": "^7.12.3",
@@ -74,6 +75,7 @@
7475
"cross-env": "^7.0.3",
7576
"css-loader": "^5.0.1",
7677
"gh-pages": "^3.1.0",
78+
"prop-types": "^15.7.2",
7779
"react": "^17.0.1",
7880
"react-dom": "^17.0.1",
7981
"react-is": "^17.0.1",
@@ -86,7 +88,6 @@
8688
"dist"
8789
],
8890
"dependencies": {
89-
"react-sortable-hoc": "^1.11.0",
9091
"react-virtual": "^2.3.0"
9192
}
9293
}

src/components/HeaderCellContainer.jsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
import React from 'react';
2-
import { SortableElement, SortableHandle } from 'react-sortable-hoc';
2+
import { SortableElement, SortableHandle } from '../drag-and-drop';
33

4-
const SortableItem = SortableElement(({children, columnId, className}) => (
5-
<div className={className} data-column-id={columnId}>{children}</div>
6-
));
4+
const SortableItem = SortableElement(React.forwardRef(({children, columnId, className}, ref) => (
5+
<div ref={ref} className={className} data-column-id={columnId}>{children}</div>
6+
)));
77

88
const SortableDragHandle = SortableHandle(({children, index}) => (
99
<React.Fragment>{children}</React.Fragment>
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
export default class AutoScroller {
2+
constructor(container, onScrollCallback) {
3+
this.container = container;
4+
this.onScrollCallback = onScrollCallback;
5+
}
6+
7+
clear() {
8+
if (this.interval == null) {
9+
return;
10+
}
11+
12+
clearInterval(this.interval);
13+
this.interval = null;
14+
}
15+
16+
update({translate, minTranslate, maxTranslate, width, height}) {
17+
const direction = {
18+
x: 0,
19+
y: 0,
20+
};
21+
const speed = {
22+
x: 1,
23+
y: 1,
24+
};
25+
const acceleration = {
26+
x: 10,
27+
y: 10,
28+
};
29+
30+
const {
31+
scrollTop,
32+
scrollLeft,
33+
scrollHeight,
34+
scrollWidth,
35+
clientHeight,
36+
clientWidth,
37+
} = this.container;
38+
39+
const isTop = scrollTop === 0;
40+
const isBottom = scrollHeight - scrollTop - clientHeight === 0;
41+
const isLeft = scrollLeft === 0;
42+
const isRight = scrollWidth - scrollLeft - clientWidth === 0;
43+
44+
if (translate.y >= maxTranslate.y - height / 2 && !isBottom) {
45+
// Scroll Down
46+
direction.y = 1;
47+
speed.y =
48+
acceleration.y *
49+
Math.abs((maxTranslate.y - height / 2 - translate.y) / height);
50+
} else if (translate.x >= maxTranslate.x - width / 2 && !isRight) {
51+
// Scroll Right
52+
direction.x = 1;
53+
speed.x =
54+
acceleration.x *
55+
Math.abs((maxTranslate.x - width / 2 - translate.x) / width);
56+
} else if (translate.y <= minTranslate.y + height / 2 && !isTop) {
57+
// Scroll Up
58+
direction.y = -1;
59+
speed.y =
60+
acceleration.y *
61+
Math.abs((translate.y - height / 2 - minTranslate.y) / height);
62+
} else if (translate.x <= minTranslate.x + width / 2 && !isLeft) {
63+
// Scroll Left
64+
direction.x = -1;
65+
speed.x =
66+
acceleration.x *
67+
Math.abs((translate.x - width / 2 - minTranslate.x) / width);
68+
}
69+
70+
if (this.interval) {
71+
this.clear();
72+
this.isAutoScrolling = false;
73+
}
74+
75+
if (direction.x !== 0 || direction.y !== 0) {
76+
this.interval = setInterval(() => {
77+
this.isAutoScrolling = true;
78+
const offset = {
79+
left: speed.x * direction.x,
80+
top: speed.y * direction.y,
81+
};
82+
this.container.scrollTop += offset.top;
83+
this.container.scrollLeft += offset.left;
84+
85+
this.onScrollCallback(offset);
86+
}, 5);
87+
}
88+
}
89+
}

src/drag-and-drop/Manager/index.js

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
export default class Manager {
2+
refs = {};
3+
4+
add(collection, ref) {
5+
if (!this.refs[collection]) {
6+
this.refs[collection] = [];
7+
}
8+
9+
this.refs[collection].push(ref);
10+
}
11+
12+
remove(collection, ref) {
13+
const index = this.getIndex(collection, ref);
14+
15+
if (index !== -1) {
16+
this.refs[collection].splice(index, 1);
17+
}
18+
}
19+
20+
isActive() {
21+
return this.active;
22+
}
23+
24+
getActive() {
25+
return this.refs[this.active.collection].find(
26+
// eslint-disable-next-line eqeqeq
27+
({node}) => node.sortableInfo.index == this.active.index,
28+
);
29+
}
30+
31+
getIndex(collection, ref) {
32+
return this.refs[collection].indexOf(ref);
33+
}
34+
35+
getOrderedRefs(collection = this.active.collection) {
36+
return this.refs[collection].sort(sortByIndex);
37+
}
38+
}
39+
40+
function sortByIndex(
41+
{
42+
node: {
43+
sortableInfo: {index: index1},
44+
},
45+
},
46+
{
47+
node: {
48+
sortableInfo: {index: index2},
49+
},
50+
},
51+
) {
52+
return index1 - index2;
53+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
export default function defaultGetHelperDimensions({node}) {
2+
return {
3+
height: node.offsetHeight,
4+
width: node.offsetWidth,
5+
};
6+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import {NodeType, closest} from '../utils';
2+
3+
export default function defaultShouldCancelStart(event) {
4+
// Cancel sorting if the event target is an `input`, `textarea`, `select` or `option`
5+
const interactiveElements = [
6+
NodeType.Input,
7+
NodeType.Textarea,
8+
NodeType.Select,
9+
NodeType.Option,
10+
NodeType.Button,
11+
];
12+
13+
if (interactiveElements.indexOf(event.target.tagName) !== -1) {
14+
// Return true to cancel sorting
15+
return true;
16+
}
17+
18+
if (closest(event.target, (el) => el.contentEditable === 'true')) {
19+
return true;
20+
}
21+
22+
return false;
23+
}

0 commit comments

Comments
 (0)