1+ import {
2+ DndContext ,
3+ KeyboardSensor ,
4+ PointerSensor ,
5+ closestCenter ,
6+ useSensor ,
7+ useSensors ,
8+ } from "@dnd-kit/core" ;
9+ import {
10+ SortableContext ,
11+ sortableKeyboardCoordinates ,
12+ useSortable ,
13+ verticalListSortingStrategy ,
14+ } from "@dnd-kit/sortable" ;
15+ import { CSS } from "@dnd-kit/utilities" ;
116import _map from "lodash/map" ;
217import PropTypes from "prop-types" ;
318import { Component } from "react" ;
4- import { DragDropContext , Draggable , Droppable } from "react-beautiful-dnd" ;
519import { FormattedMessage } from "react-intl" ;
620import External from "../External/External" ;
721import Modal from "../Modal/Modal" ;
822import messages from "./Messages" ;
923
24+ // SortableItem component for draggable columns
25+ const SortableItem = ( { column, columnKey, onRemove } ) => {
26+ const { attributes, listeners, setNodeRef, transform, transition } = useSortable ( {
27+ id : columnKey ,
28+ } ) ;
29+
30+ const style = {
31+ transform : CSS . Transform . toString ( transform ) ,
32+ transition,
33+ } ;
34+
35+ return (
36+ < div ref = { setNodeRef } style = { style } { ...attributes } { ...listeners } >
37+ < div className = "mr-flex" >
38+ < div className = "mr-flex-grow mr-text-base mr-text-white mr-my-2" > { column . message } </ div >
39+
40+ { ! column . permanent && (
41+ < div className = "mr-text-sm mr-text-green-lighter mr-my-2" >
42+ < button className = "mr-text-current" onClick = { ( ) => onRemove ( columnKey ) } >
43+ < FormattedMessage { ...messages . removeLabel } />
44+ </ button >
45+ </ div >
46+ ) }
47+ </ div >
48+ </ div >
49+ ) ;
50+ } ;
51+
1052/**
1153 * ConfigureColumnsModal renders a modal for configuring table columns
1254 *
1355 * @author [Kelli Rotstan](https://github.com/krotstan)
1456 */
1557export 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 ) {
58+ handleDragEnd = ( event ) => {
59+ const { active, over } = event ;
60+
61+ if ( ! over || active . id === over . id ) {
1962 return ;
2063 }
2164
22- this . props . reorderAddedColumn ( result . source . index , result . destination . index ) ;
65+ // Find indexes for the source and destination
66+ let sourceIndex = - 1 ;
67+ let destinationIndex = - 1 ;
68+
69+ Object . keys ( this . props . addedColumns ) . forEach ( ( key , index ) => {
70+ if ( key === active . id ) sourceIndex = index ;
71+ if ( key === over . id ) destinationIndex = index ;
72+ } ) ;
73+
74+ if ( sourceIndex !== - 1 && destinationIndex !== - 1 ) {
75+ this . props . reorderAddedColumn ( sourceIndex , destinationIndex ) ;
76+ }
2377 } ;
2478
2579 close = ( ) => {
2680 this . props . saveColumnSettings ( ) ;
2781 this . props . onClose ( ) ;
2882 } ;
2983
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 >
84+ buildSortableColumnList ( ) {
85+ const columnItems = [ ] ;
86+ const columnIds = [ ] ;
87+
88+ Object . entries ( this . props . addedColumns ) . forEach ( ( [ key , column ] ) => {
89+ columnItems . push (
90+ < SortableItem
91+ key = { `added-${ key } ` }
92+ column = { column }
93+ columnKey = { key }
94+ onRemove = { this . props . removeColumn }
95+ /> ,
5796 ) ;
97+ columnIds . push ( key ) ;
5898 } ) ;
99+
100+ return { columnItems, columnIds } ;
59101 }
60102
61103 render ( ) {
104+ // Wrap DndContext in a function component since hooks can't be used in class components
105+ const DraggableColumnList = ( ) => {
106+ const sensors = useSensors (
107+ useSensor ( PointerSensor ) ,
108+ useSensor ( KeyboardSensor , {
109+ coordinateGetter : sortableKeyboardCoordinates ,
110+ } ) ,
111+ ) ;
112+
113+ const { columnItems, columnIds } = this . buildSortableColumnList ( ) ;
114+
115+ return (
116+ < DndContext
117+ sensors = { sensors }
118+ collisionDetection = { closestCenter }
119+ onDragEnd = { this . handleDragEnd }
120+ >
121+ < SortableContext items = { columnIds } strategy = { verticalListSortingStrategy } >
122+ { columnItems }
123+ </ SortableContext >
124+ </ DndContext >
125+ ) ;
126+ } ;
127+
62128 const availableColumns = _map ( this . props . availableColumns , ( column , key ) => (
63129 < li key = { `available-${ key } ` } className = "mr-flex mr-my-4" >
64130 < div className = "mr-flex-grow mr-text-base mr-text-white" > { column . message } </ div >
@@ -103,16 +169,7 @@ export default class ConfigureColumnsModal extends Component {
103169 </ div >
104170 </ header >
105171 < 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 >
172+ < DraggableColumnList />
116173 </ div >
117174 </ section >
118175 </ div >
@@ -135,4 +192,5 @@ ConfigureColumnsModal.propTypes = {
135192 addedColumns : PropTypes . object . isRequired ,
136193 availableColumns : PropTypes . object . isRequired ,
137194 reorderAddedColumn : PropTypes . func . isRequired ,
195+ removeColumn : PropTypes . func . isRequired ,
138196} ;
0 commit comments