11import _map from "lodash/map" ;
22import PropTypes from "prop-types" ;
33import { 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" ;
520import { FormattedMessage } from "react-intl" ;
621import External from "../External/External" ;
722import Modal from "../Modal/Modal" ;
823import 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 */
1558export 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