1
- import { useRef , useState } from 'react' ;
1
+ import { useId , useRef , useState } from 'react' ;
2
2
import { css } from '@linaria/core' ;
3
3
4
4
import { useRovingTabIndex } from './hooks' ;
@@ -43,17 +43,29 @@ export const resizeHandleClassname = css`
43
43
const cellDraggableClassname = 'rdg-cell-draggable' ;
44
44
45
45
const cellDragging = css `
46
- opacity : 0.5 ;
46
+ @layer rdg.HeaderCell {
47
+ background-color : var (--rdg-header-draggable-background-color );
48
+ }
47
49
` ;
48
50
49
51
const cellDraggingClassname = `rdg-cell-dragging ${ cellDragging } ` ;
50
52
51
53
const cellOver = css `
52
- background-color : var (--rdg-header-draggable-background-color );
54
+ @layer rdg.HeaderCell {
55
+ background-color : var (--rdg-header-draggable-background-color );
56
+ }
53
57
` ;
54
58
55
59
const cellOverClassname = `rdg-cell-drag-over ${ cellOver } ` ;
56
60
61
+ const dragImageClassname = css `
62
+ @layer rdg.HeaderCell {
63
+ border-radius : 4px ;
64
+ width : fit-content;
65
+ outline : 2px solid hsl (207 , 100% , 50% );
66
+ }
67
+ ` ;
68
+
57
69
type SharedHeaderRowProps < R , SR > = Pick <
58
70
HeaderRowProps < R , SR , React . Key > ,
59
71
| 'sortColumns'
@@ -70,7 +82,8 @@ export interface HeaderCellProps<R, SR> extends SharedHeaderRowProps<R, SR> {
70
82
colSpan : number | undefined ;
71
83
rowIdx : number ;
72
84
isCellSelected : boolean ;
73
- dragDropKey : string ;
85
+ draggedColumnKey : string | undefined ;
86
+ setDraggedColumnKey : ( draggedColumnKey : string | undefined ) => void ;
74
87
}
75
88
76
89
export default function HeaderCell < R , SR > ( {
@@ -85,10 +98,11 @@ export default function HeaderCell<R, SR>({
85
98
onSortColumnsChange,
86
99
selectCell,
87
100
direction,
88
- dragDropKey
101
+ draggedColumnKey,
102
+ setDraggedColumnKey
89
103
} : HeaderCellProps < R , SR > ) {
90
- const [ isDragging , setIsDragging ] = useState ( false ) ;
91
104
const [ isOver , setIsOver ] = useState ( false ) ;
105
+ const isDragging = draggedColumnKey === column . key ;
92
106
const rowSpan = getHeaderCellRowSpan ( column , rowIdx ) ;
93
107
const { tabIndex, childTabIndex, onFocus } = useRovingTabIndex ( isCellSelected ) ;
94
108
const sortIndex = sortColumns ?. findIndex ( ( sort ) => sort . columnKey === column . key ) ;
@@ -99,6 +113,7 @@ export default function HeaderCell<R, SR>({
99
113
const ariaSort =
100
114
sortDirection && ! priority ? ( sortDirection === 'ASC' ? 'ascending' : 'descending' ) : undefined ;
101
115
const { sortable, resizable, draggable } = column ;
116
+ const dragImageId = useId ( ) ;
102
117
103
118
const className = getCellClassname ( column , column . headerCellClass , {
104
119
[ cellSortableClassname ] : sortable ,
@@ -180,13 +195,18 @@ export default function HeaderCell<R, SR>({
180
195
}
181
196
182
197
function onDragStart ( event : React . DragEvent < HTMLDivElement > ) {
183
- event . dataTransfer . setData ( dragDropKey , column . key ) ;
198
+ const dragImage = event . currentTarget . cloneNode ( true ) as HTMLDivElement ;
199
+ dragImage . classList . add ( dragImageClassname ) ;
200
+ dragImage . id = dragImageId ;
201
+ event . currentTarget . parentElement ! . insertBefore ( dragImage , event . currentTarget ) ;
202
+ event . dataTransfer . setDragImage ( dragImage , 0 , 0 ) ;
184
203
event . dataTransfer . dropEffect = 'move' ;
185
- setIsDragging ( true ) ;
204
+ setDraggedColumnKey ( column . key ) ;
186
205
}
187
206
188
207
function onDragEnd ( ) {
189
- setIsDragging ( false ) ;
208
+ setDraggedColumnKey ( undefined ) ;
209
+ document . getElementById ( dragImageId ) ?. remove ( ) ;
190
210
}
191
211
192
212
function onDragOver ( event : React . DragEvent < HTMLDivElement > ) {
@@ -197,18 +217,9 @@ export default function HeaderCell<R, SR>({
197
217
198
218
function onDrop ( event : React . DragEvent < HTMLDivElement > ) {
199
219
setIsOver ( false ) ;
200
- // The dragDropKey is derived from the useId() hook, which can sometimes generate keys with uppercase letters.
201
- // When setting data using event.dataTransfer.setData(), the key is automatically converted to lowercase in some browsers.
202
- // To ensure consistent comparison, we normalize the dragDropKey to lowercase before checking its presence in the event's dataTransfer types.
203
- // https://html.spec.whatwg.org/multipage/dnd.html#the-datatransfer-interface
204
- if ( event . dataTransfer . types . includes ( dragDropKey . toLowerCase ( ) ) ) {
205
- const sourceKey = event . dataTransfer . getData ( dragDropKey . toLowerCase ( ) ) ;
206
- if ( sourceKey !== column . key ) {
207
- // prevent the browser from redirecting in some cases
208
- event . preventDefault ( ) ;
209
- onColumnsReorder ?.( sourceKey , column . key ) ;
210
- }
211
- }
220
+ // prevent the browser from redirecting in some cases
221
+ event . preventDefault ( ) ;
222
+ onColumnsReorder ?.( draggedColumnKey ! , column . key ) ;
212
223
}
213
224
214
225
function onDragEnter ( event : React . DragEvent < HTMLDivElement > ) {
@@ -223,19 +234,23 @@ export default function HeaderCell<R, SR>({
223
234
}
224
235
}
225
236
226
- let draggableProps : React . ComponentProps < 'div' > | undefined ;
237
+ let dragTargetProps : React . ComponentProps < 'div' > | undefined ;
238
+ let dropTargetProps : React . ComponentProps < 'div' > | undefined ;
227
239
if ( draggable ) {
228
- draggableProps = {
240
+ dragTargetProps = {
229
241
draggable : true ,
230
- /* events fired on the draggable target */
231
242
onDragStart,
232
- onDragEnd,
233
- /* events fired on the drop targets */
234
- onDragOver,
235
- onDragEnter,
236
- onDragLeave,
237
- onDrop
243
+ onDragEnd
238
244
} ;
245
+
246
+ if ( draggedColumnKey !== undefined && draggedColumnKey !== column . key ) {
247
+ dropTargetProps = {
248
+ onDragOver,
249
+ onDragEnter,
250
+ onDragLeave,
251
+ onDrop
252
+ } ;
253
+ }
239
254
}
240
255
241
256
return (
@@ -256,7 +271,8 @@ export default function HeaderCell<R, SR>({
256
271
onFocus = { onFocus }
257
272
onClick = { onClick }
258
273
onKeyDown = { onKeyDown }
259
- { ...draggableProps }
274
+ { ...dragTargetProps }
275
+ { ...dropTargetProps }
260
276
>
261
277
{ column . renderHeaderCell ( {
262
278
column,
0 commit comments