Skip to content

Commit c70c4e4

Browse files
committed
replace deprecated dependency react-beautiful-dnd
1 parent f0ceb47 commit c70c4e4

4 files changed

Lines changed: 256 additions & 143 deletions

File tree

package-lock.json

Lines changed: 56 additions & 45 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,9 @@
3232
"dependencies": {
3333
"@apollo/client": "^3.5.4",
3434
"@changey/react-leaflet-markercluster": "^4.0.0-rc1",
35+
"@dnd-kit/core": "^6.3.1",
36+
"@dnd-kit/sortable": "^10.0.0",
37+
"@dnd-kit/utilities": "^3.2.2",
3538
"@mapbox/geo-viewport": "^0.4.0",
3639
"@nivo/bar": "^0.98.0",
3740
"@nivo/core": "^0.98.0",
@@ -78,7 +81,6 @@
7881
"prop-types": "^15.6.0",
7982
"query-string": "^6.13.1",
8083
"react": "^17.0.2",
81-
"react-beautiful-dnd": "^13.0.0",
8284
"react-burger-menu": "^3.1.0",
8385
"react-calendar-heatmap": "^1.6.3",
8486
"react-copy-to-clipboard": "^5.0.1",

src/components/ConfigureColumnsModal/ConfigureColumnsModal.jsx

Lines changed: 101 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,64 +1,131 @@
11
import _map from "lodash/map";
22
import PropTypes from "prop-types";
33
import { Component } from "react";
4-
import { DragDropContext, Draggable, Droppable } from "react-beautiful-dnd";
4+
import {
5+
DndContext,
6+
closestCenter,
7+
KeyboardSensor,
8+
PointerSensor,
9+
useSensor,
10+
useSensors,
11+
} from "@dnd-kit/core";
12+
import {
13+
arrayMove,
14+
SortableContext,
15+
sortableKeyboardCoordinates,
16+
useSortable,
17+
verticalListSortingStrategy,
18+
} from "@dnd-kit/sortable";
19+
import { CSS } from "@dnd-kit/utilities";
520
import { FormattedMessage } from "react-intl";
621
import External from "../External/External";
722
import Modal from "../Modal/Modal";
823
import messages from "./Messages";
924

25+
// SortableItem component for draggable columns
26+
const SortableItem = ({ column, columnKey, onRemove }) => {
27+
const { attributes, listeners, setNodeRef, transform, transition } = useSortable({
28+
id: columnKey,
29+
});
30+
31+
const style = {
32+
transform: CSS.Transform.toString(transform),
33+
transition,
34+
};
35+
36+
return (
37+
<div ref={setNodeRef} style={style} {...attributes} {...listeners}>
38+
<div className="mr-flex">
39+
<div className="mr-flex-grow mr-text-base mr-text-white mr-my-2">{column.message}</div>
40+
41+
{!column.permanent && (
42+
<div className="mr-text-sm mr-text-green-lighter mr-my-2">
43+
<button className="mr-text-current" onClick={() => onRemove(columnKey)}>
44+
<FormattedMessage {...messages.removeLabel} />
45+
</button>
46+
</div>
47+
)}
48+
</div>
49+
</div>
50+
);
51+
};
52+
1053
/**
1154
* ConfigureColumnsModal renders a modal for configuring table columns
1255
*
1356
* @author [Kelli Rotstan](https://github.com/krotstan)
1457
*/
1558
export default class ConfigureColumnsModal extends Component {
16-
onDragEnd = (result) => {
17-
// dropped outside the list or on itself
18-
if (!result.destination || result.source.index === result.destination.index) {
59+
handleDragEnd = (event) => {
60+
const { active, over } = event;
61+
62+
if (!over || active.id === over.id) {
1963
return;
2064
}
2165

22-
this.props.reorderAddedColumn(result.source.index, result.destination.index);
66+
// Find indexes for the source and destination
67+
let sourceIndex = -1;
68+
let destinationIndex = -1;
69+
70+
Object.keys(this.props.addedColumns).forEach((key, index) => {
71+
if (key === active.id) sourceIndex = index;
72+
if (key === over.id) destinationIndex = index;
73+
});
74+
75+
if (sourceIndex !== -1 && destinationIndex !== -1) {
76+
this.props.reorderAddedColumn(sourceIndex, destinationIndex);
77+
}
2378
};
2479

2580
close = () => {
2681
this.props.saveColumnSettings();
2782
this.props.onClose();
2883
};
2984

30-
buildDraggableColumnList() {
31-
let index = -1;
32-
return _map(this.props.addedColumns, (column, key) => {
33-
index += 1;
34-
return (
35-
<Draggable key={`added-${key}`} draggableId={key} index={index}>
36-
{(provided) => (
37-
<div ref={provided.innerRef} {...provided.draggableProps} {...provided.dragHandleProps}>
38-
<div className="mr-flex">
39-
<div className="mr-flex-grow mr-text-base mr-text-white mr-my-2">
40-
{column.message}
41-
</div>
42-
43-
{!column.permanent && (
44-
<div className="mr-text-sm mr-text-green-lighter mr-my-2">
45-
<button
46-
className="mr-text-current"
47-
onClick={() => this.props.removeColumn(key)}
48-
>
49-
<FormattedMessage {...messages.removeLabel} />
50-
</button>
51-
</div>
52-
)}
53-
</div>
54-
</div>
55-
)}
56-
</Draggable>
85+
buildSortableColumnList() {
86+
const columnItems = [];
87+
const columnIds = [];
88+
89+
Object.entries(this.props.addedColumns).forEach(([key, column]) => {
90+
columnItems.push(
91+
<SortableItem
92+
key={`added-${key}`}
93+
column={column}
94+
columnKey={key}
95+
onRemove={this.props.removeColumn}
96+
/>,
5797
);
98+
columnIds.push(key);
5899
});
100+
101+
return { columnItems, columnIds };
59102
}
60103

61104
render() {
105+
// Wrap DndContext in a function component since hooks can't be used in class components
106+
const DraggableColumnList = () => {
107+
const sensors = useSensors(
108+
useSensor(PointerSensor),
109+
useSensor(KeyboardSensor, {
110+
coordinateGetter: sortableKeyboardCoordinates,
111+
}),
112+
);
113+
114+
const { columnItems, columnIds } = this.buildSortableColumnList();
115+
116+
return (
117+
<DndContext
118+
sensors={sensors}
119+
collisionDetection={closestCenter}
120+
onDragEnd={this.handleDragEnd}
121+
>
122+
<SortableContext items={columnIds} strategy={verticalListSortingStrategy}>
123+
{columnItems}
124+
</SortableContext>
125+
</DndContext>
126+
);
127+
};
128+
62129
const availableColumns = _map(this.props.availableColumns, (column, key) => (
63130
<li key={`available-${key}`} className="mr-flex mr-my-4">
64131
<div className="mr-flex-grow mr-text-base mr-text-white">{column.message}</div>
@@ -103,16 +170,7 @@ export default class ConfigureColumnsModal extends Component {
103170
</div>
104171
</header>
105172
<div className="mr-card-widget__content">
106-
<DragDropContext onDragEnd={this.onDragEnd}>
107-
<Droppable droppableId="added-column-droppable">
108-
{(provided) => (
109-
<div {...provided.droppableProps} ref={provided.innerRef}>
110-
{this.buildDraggableColumnList(provided)}
111-
{provided.placeholder}
112-
</div>
113-
)}
114-
</Droppable>
115-
</DragDropContext>
173+
<DraggableColumnList />
116174
</div>
117175
</section>
118176
</div>
@@ -135,4 +193,5 @@ ConfigureColumnsModal.propTypes = {
135193
addedColumns: PropTypes.object.isRequired,
136194
availableColumns: PropTypes.object.isRequired,
137195
reorderAddedColumn: PropTypes.func.isRequired,
196+
removeColumn: PropTypes.func.isRequired,
138197
};

0 commit comments

Comments
 (0)