Skip to content

Commit 478b0f3

Browse files
author
patricktr
committed
support multiple draggable enabled react tables at same time
update readme and changelog update storybook with mutlple table example
1 parent daaa459 commit 478b0f3

File tree

8 files changed

+183
-53
lines changed

8 files changed

+183
-53
lines changed

CHANGELOG.md

+3-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
# 1.2.0
22

3-
New prop `onDropSuccess` callback to obtain column information and indexes for the ondrop event
3+
New prop `onDropSuccess` callback to obtain column information and indexes for the ondrop event (probably more info than you want to know!)
4+
5+
Breaking Change: Headers are now wrapped by a `div` rather than `span`. This was necessary to support column.header defined as a component
46

57
# 1.1.6 (2019-09-23)
68

README.md

+14-13
Original file line numberDiff line numberDiff line change
@@ -60,19 +60,20 @@ render () {
6060

6161
## draggableColumns Prop
6262

63-
| Property | Description | Default value | Type | Required |
64-
| ------------------------------- | --------------------------------------------------------------------------------------- | -------------------- | ---------------- | -------- |
65-
| `mode` | mode to either 'reorder' the column or 'swap' column position on drop | 'reorder' | string | yes |
66-
| `draggable` | array of column accessors to allow drag and drop | | array of strings | |
67-
| `enableColumnWideDrag` | when {true} entire column is draggable. when {false} only header text is draggable | true | bool | |
68-
| `disableTableScroll` | disable ReactTable horizontal/vertical scrolling when dragging a column | false | bool | |
69-
| `overflow` | used with disableTableScroll={true} to reset ReactTable overflow style onDragEnd event | `auto` | string | |
70-
| `useDragImage` | clone dragged column element? useful for applying a different css class. | true | bool | |
71-
| `dragImageClassName` | dragImageClassName only applies when useDragImage={true} | `rt-dragged-item` | string | |
72-
| `onDragEnterClassName` | when mode={'swap'} - css class applied on dragged over column | `rt-drag-enter-item` | string | |
73-
| `onDraggedColumnChange` | callback method to be notified when column order changes - signature: function(columns) | | function | |
74-
| `reorderIndicatorUpClassName` | additional className for reorder indicator Up | | string | |
75-
| `reorderIndicatorDownClassName` | additional className for reorder indicator Down | | string | |
63+
| Property | Description | Default value | Type | Required |
64+
| ------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------- | ---------------- | -------- |
65+
| `mode` | mode to either 'reorder' the column or 'swap' column position on drop | 'reorder' | string | yes |
66+
| `draggable` | array of column accessors to allow drag and drop | | array of strings | |
67+
| `enableColumnWideDrag` | when {true} entire column is draggable. when {false} only header text is draggable | true | bool | |
68+
| `disableTableScroll` | disable ReactTable horizontal/vertical scrolling when dragging a column | false | bool | |
69+
| `overflow` | used with disableTableScroll={true} to reset ReactTable overflow style onDragEnd event | `auto` | string | |
70+
| `useDragImage` | clone dragged column element? useful for applying a different css class. | true | bool | |
71+
| `dragImageClassName` | dragImageClassName only applies when useDragImage={true} | `rt-dragged-item` | string | |
72+
| `onDragEnterClassName` | when mode={'swap'} - css class applied on dragged over column | `rt-drag-enter-item` | string | |
73+
| `onDraggedColumnChange` | callback method to be notified when column order changes - signature: function(columns) | | function | |
74+
| `onDropSuccess` | callback method to be notified when on column drop success - signature: function(draggedColumn, targetColumn, oldIndex, newIndex, oldOffset, newOffset) | | function | |
75+
| `reorderIndicatorUpClassName` | additional className for reorder indicator Up | | string | |
76+
| `reorderIndicatorDownClassName` | additional className for reorder indicator Down | | string | |
7677

7778
## License
7879

example/src/stories/check-bold.svg

+10
Loading

example/src/stories/index.js

+93-23
Original file line numberDiff line numberDiff line change
@@ -12,31 +12,94 @@ import SampleData from './sample-data';
1212
const stories = storiesOf('ReactTableDraggableColumns', module);
1313
stories.addDecorator(withKnobs);
1414
stories.addDecorator(storyFn => <div style={{ marginTop: '30px' }}>{storyFn()}</div>);
15+
stories.add('Reorder Columns', () => {
16+
const ReactTableDraggableColumns = withDraggableColumns(ReactTable);
17+
18+
return (
19+
<ReactTableDraggableColumns
20+
style={{
21+
width: '98vw',
22+
height: '500px'
23+
}}
24+
columns={SampleData.carColumns}
25+
data={SampleData.carData}
26+
showPagination={false}
27+
draggableColumns={{
28+
mode: DragMode.REORDER,
29+
draggable: text('draggable', ['vin', 'year', 'brand', 'color']),
30+
enableColumnWideDrag: boolean('enableColumnWideDrag', true),
31+
disableTableScroll: boolean('disableTableScroll', true),
32+
useDragImage: boolean('useDragImage', true),
33+
onDraggedColumnChange: cols => console.log('new order', cols),
34+
onDropSuccess: (draggedColumn, targetColumn, oldIndex, newIndex, oldOffset, newOffset) => {
35+
console.log(draggedColumn, targetColumn, oldIndex, newIndex, oldOffset, newOffset);
36+
}
37+
}}
38+
/>
39+
);
40+
});
1541
stories
16-
.add('Reorder Columns', () => {
42+
.add('Reorder Columns - Multiple Tables', () => {
1743
const ReactTableDraggableColumns = withDraggableColumns(ReactTable);
1844

1945
return (
20-
<ReactTableDraggableColumns
21-
style={{
22-
width: '98vw',
23-
height: '500px'
24-
}}
25-
columns={SampleData.carColumns}
26-
data={SampleData.carData}
27-
showPagination={false}
28-
draggableColumns={{
29-
mode: DragMode.REORDER,
30-
draggable: text('draggable', ['vin', 'year', 'brand', 'color']),
31-
enableColumnWideDrag: boolean('enableColumnWideDrag', true),
32-
disableTableScroll: boolean('disableTableScroll', true),
33-
useDragImage: boolean('useDragImage', true),
34-
onDraggedColumnChange: cols => console.log('new order', cols),
35-
onDropSuccess: (draggedColumn, targetColumn, oldIndex, newIndex) => {
36-
console.log(draggedColumn, targetColumn, oldIndex, newIndex);
37-
}
38-
}}
39-
/>
46+
<React.Fragment>
47+
<ReactTableDraggableColumns
48+
style={{
49+
width: '98vw',
50+
height: '300px'
51+
}}
52+
columns={SampleData.carColumns}
53+
data={SampleData.carData}
54+
showPagination={false}
55+
draggableColumns={{
56+
mode: DragMode.REORDER,
57+
draggable: text('draggable', ['vin', 'year', 'brand', 'color']),
58+
enableColumnWideDrag: boolean('enableColumnWideDrag', true),
59+
disableTableScroll: boolean('disableTableScroll', true),
60+
useDragImage: boolean('useDragImage', true),
61+
onDraggedColumnChange: cols => console.log('new order', cols),
62+
onDropSuccess: (
63+
draggedColumn,
64+
targetColumn,
65+
oldIndex,
66+
newIndex,
67+
oldOffset,
68+
newOffset
69+
) => {
70+
console.log(draggedColumn, targetColumn, oldIndex, newIndex, oldOffset, newOffset);
71+
}
72+
}}
73+
/>{' '}
74+
<br /> <br />
75+
<ReactTableDraggableColumns
76+
style={{
77+
width: '98vw',
78+
height: '300px'
79+
}}
80+
columns={SampleData.carColumns}
81+
data={SampleData.carData}
82+
showPagination={false}
83+
draggableColumns={{
84+
mode: DragMode.REORDER,
85+
draggable: text('draggable', ['vin', 'year', 'brand', 'color']),
86+
enableColumnWideDrag: boolean('enableColumnWideDrag', true),
87+
disableTableScroll: boolean('disableTableScroll', true),
88+
useDragImage: boolean('useDragImage', true),
89+
onDraggedColumnChange: cols => console.log('new order', cols),
90+
onDropSuccess: (
91+
draggedColumn,
92+
targetColumn,
93+
oldIndex,
94+
newIndex,
95+
oldOffset,
96+
newOffset
97+
) => {
98+
console.log(draggedColumn, targetColumn, oldIndex, newIndex, oldOffset, newOffset);
99+
}
100+
}}
101+
/>
102+
</React.Fragment>
40103
);
41104
})
42105
.add('Swap Columns', () => {
@@ -58,8 +121,15 @@ stories
58121
disableTableScroll: boolean('disableTableScroll', true),
59122
useDragImage: boolean('useDragImage', true),
60123
onDraggedColumnChange: cols => console.log('new order', cols),
61-
onDropSuccess: (draggedColumn, targetColumn, oldIndex, newIndex) => {
62-
console.log(draggedColumn, targetColumn, oldIndex, newIndex);
124+
onDropSuccess: (
125+
draggedColumn,
126+
targetColumn,
127+
oldIndex,
128+
newIndex,
129+
oldOffset,
130+
newOffset
131+
) => {
132+
console.log(draggedColumn, targetColumn, oldIndex, newIndex, oldOffset, newOffset);
63133
}
64134
}}
65135
/>

example/src/stories/sample-data.js

+4-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
1+
import React from 'react';
2+
import { ReactComponent as CheckMark } from './check-bold.svg';
3+
14
const carColumns = [
25
{
3-
Header: 'Vin',
6+
Header: (<div>Vin <CheckMark/></div>),
47
accessor: 'vin',
58
width: 300,
69
sortable: true

src/index.js

+55-14
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,25 @@ export const DragMode = {
88
SWAP: 'swap'
99
}
1010

11+
/**
12+
* Generate UuId
13+
* */
14+
const generateUuid = () => {
15+
let uuid = ''
16+
let i
17+
let random
18+
for (i = 0; i < 32; i++) {
19+
random = (Math.random() * 16) | 0
20+
21+
if (i === 8 || i === 12 || i === 16 || i === 20) {
22+
uuid += '-'
23+
}
24+
uuid += (i === 12 ? 4 : i === 16 ? (random & 3) | 8 : random).toString(16)
25+
}
26+
27+
return uuid
28+
}
29+
1130
export default Component => {
1231
const wrapper = class RTFixedDraggableColumn extends React.Component {
1332
getWrappedInstance() {
@@ -27,6 +46,8 @@ export default Component => {
2746
trigger: 0,
2847
firstLoad: true
2948
}
49+
50+
this.uniqueId = generateUuid()
3051
}
3152

3253
// helper methods
@@ -47,7 +68,7 @@ export default Component => {
4768
createDragEvents() {
4869
const headers = DomHelper.findChildrenWithClassName(
4970
this.containerRef.current,
50-
'draggable-header'
71+
`${this.uniqueId} draggable-header`
5172
)
5273

5374
headers.forEach((header, i) => {
@@ -158,6 +179,9 @@ export default Component => {
158179
headerParent.ondragover = e => {
159180
e.preventDefault()
160181

182+
// prevent bug when using multiple react tables
183+
if (!this.draggedColumn) return
184+
161185
const {
162186
draggableColumns: { mode = defaultProps.mode }
163187
} = this.props
@@ -202,8 +226,12 @@ export default Component => {
202226
this.dropPosition = -1
203227
}
204228

205-
if (DomHelper.parseStrDimensionToInt(this.reorderIndicatorUp.style.left) > maxVisibleXPos ||
206-
DomHelper.parseStrDimensionToInt(this.reorderIndicatorUp.style.left) < minVisibleXPos) {
229+
if (
230+
DomHelper.parseStrDimensionToInt(this.reorderIndicatorUp.style.left) >
231+
maxVisibleXPos ||
232+
DomHelper.parseStrDimensionToInt(this.reorderIndicatorUp.style.left) <
233+
minVisibleXPos
234+
) {
207235
// do not show indicators if position is outside leftmost or rightmost bounds of the react table
208236
this.reorderIndicatorUp.style.display = 'none'
209237
this.reorderIndicatorDown.style.display = 'none'
@@ -246,6 +274,9 @@ export default Component => {
246274
headerParent.ondrop = e => {
247275
e.preventDefault()
248276

277+
// prevent bug when using multiple react tables
278+
if (!this.draggedColumn) return
279+
249280
const {
250281
draggableColumns: { mode = defaultProps.mode, onDropSuccess }
251282
} = this.props
@@ -281,12 +312,25 @@ export default Component => {
281312
this.reorder.push({ a: dropIndex, b: this.dragged })
282313

283314
if (onDropSuccess) {
284-
// (draggedColumn, targetColumn, oldIndex, newIndex)
315+
const containerOffset = DomHelper.getOffset(this.containerRef.current)
316+
317+
// adjust offSets to be respective to the containerOffset
318+
const oldOffset = DomHelper.getOffset(this.draggedColumn)
319+
oldOffset.top = oldOffset.top - containerOffset.top
320+
oldOffset.left = oldOffset.left - containerOffset.left
321+
322+
const newOffset = DomHelper.getOffset(this.findParentHeader(e.target))
323+
newOffset.top = newOffset.top - containerOffset.top
324+
newOffset.left = newOffset.left - containerOffset.left
325+
326+
// (draggedColumn, targetColumn, oldIndex, newIndex, oldOffset, newOffset)
285327
onDropSuccess(
286328
this.currentColumnOrder[this.dragged],
287329
this.currentColumnOrder[dropIndex],
288330
this.dragged,
289-
dropIndex
331+
dropIndex,
332+
oldOffset,
333+
newOffset
290334
)
291335
}
292336

@@ -391,7 +435,7 @@ export default Component => {
391435
)
392436

393437
const cols = columns.map(col => {
394-
let headerClassName = 'draggable-header'
438+
let headerClassName = `${this.uniqueId} draggable-header`
395439

396440
// add additional className if column is draggable enabled
397441
if (
@@ -405,13 +449,13 @@ export default Component => {
405449
...col,
406450
Header:
407451
typeof col.Header === 'function' ? (
408-
<span onClick={this.stopPropagation} className={headerClassName}>
452+
<div onClick={this.stopPropagation} className={headerClassName}>
409453
{col.Header()}
410-
</span>
454+
</div>
411455
) : (
412-
<span onClick={this.stopPropagation} className={headerClassName}>
456+
<div onClick={this.stopPropagation} className={headerClassName}>
413457
{col.Header}
414-
</span>
458+
</div>
415459
)
416460
}
417461
})
@@ -500,7 +544,7 @@ export default Component => {
500544
dragImageClassName: PropTypes.string,
501545
/** Swap mode only - css class */
502546
onDragEnterClassName: PropTypes.string,
503-
/** callback method to be notified when on column drop success - signature: function(draggedColumn, targetColumn, oldIndex, newIndex) */
547+
/** callback method to be notified when on column drop success - signature: function(draggedColumn, targetColumn, oldIndex, newIndex, oldOffset, newOffset) */
504548
onDropSuccess: PropTypes.func,
505549
/** callback method to be notified when column order changes - signature: function(columns) */
506550
onDraggedColumnChange: PropTypes.func,
@@ -513,6 +557,3 @@ export default Component => {
513557

514558
return wrapper
515559
}
516-
517-
// todo - additionalDropZones prop? For columns that aren't draggable to but you want to allow other columns to be reordered before or after it?
518-
// (reorder mode only, doesn't make sense for swap mode)

src/styles.scss

+1-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
}
1313

1414
//add a little padding around header text to enlarge hover hotspot
15-
span.draggable-header.enable-drag {
15+
div.draggable-header.enable-drag {
1616
padding: 2px 8px;
1717
}
1818

todo.txt

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
1) future idea - additionalDropZones prop? For columns that aren't draggable to but you want to allow other columns to be reordered before or after it?
2+
https://developer.mozilla.org/en-US/docs/Web/API/HTML_Drag_and_Drop_API#Define_a_drop_zone
3+
(reorder mode only, doesn't make sense for swap mode)

0 commit comments

Comments
 (0)