1
- import { useId , useRef , useState } from 'react' ;
1
+ import { useRef , useState } from 'react' ;
2
+ import { flushSync } from 'react-dom' ;
2
3
import { css } from '@linaria/core' ;
3
4
4
5
import { useRovingTabIndex } from './hooks' ;
@@ -63,6 +64,7 @@ const dragImageClassname = css`
63
64
border-radius : 4px ;
64
65
width : fit-content;
65
66
outline : 2px solid hsl (207 , 100% , 50% );
67
+ outline-offset : -2px ;
66
68
}
67
69
` ;
68
70
@@ -102,6 +104,7 @@ export default function HeaderCell<R, SR>({
102
104
setDraggedColumnKey
103
105
} : HeaderCellProps < R , SR > ) {
104
106
const [ isOver , setIsOver ] = useState ( false ) ;
107
+ const dragImageRef = useRef < HTMLDivElement > ( null ) ;
105
108
const isDragging = draggedColumnKey === column . key ;
106
109
const rowSpan = getHeaderCellRowSpan ( column , rowIdx ) ;
107
110
const { tabIndex, childTabIndex, onFocus } = useRovingTabIndex ( isCellSelected ) ;
@@ -113,7 +116,6 @@ export default function HeaderCell<R, SR>({
113
116
const ariaSort =
114
117
sortDirection && ! priority ? ( sortDirection === 'ASC' ? 'ascending' : 'descending' ) : undefined ;
115
118
const { sortable, resizable, draggable } = column ;
116
- const dragImageId = useId ( ) ;
117
119
118
120
const className = getCellClassname ( column , column . headerCellClass , {
119
121
[ cellSortableClassname ] : sortable ,
@@ -195,18 +197,16 @@ export default function HeaderCell<R, SR>({
195
197
}
196
198
197
199
function onDragStart ( event : React . DragEvent < HTMLDivElement > ) {
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 ) ;
200
+ // need flushSync to make sure the drag image is rendered before the drag starts
201
+ flushSync ( ( ) => {
202
+ setDraggedColumnKey ( column . key ) ;
203
+ } ) ;
204
+ event . dataTransfer . setDragImage ( dragImageRef . current ! , 0 , 0 ) ;
203
205
event . dataTransfer . dropEffect = 'move' ;
204
- setDraggedColumnKey ( column . key ) ;
205
206
}
206
207
207
208
function onDragEnd ( ) {
208
209
setDraggedColumnKey ( undefined ) ;
209
- document . getElementById ( dragImageId ) ?. remove ( ) ;
210
210
}
211
211
212
212
function onDragOver ( event : React . DragEvent < HTMLDivElement > ) {
@@ -253,43 +253,58 @@ export default function HeaderCell<R, SR>({
253
253
}
254
254
}
255
255
256
+ const style : React . CSSProperties = {
257
+ ...getHeaderCellStyle ( column , rowIdx , rowSpan ) ,
258
+ ...getCellStyle ( column , colSpan )
259
+ } ;
260
+
261
+ const content = column . renderHeaderCell ( {
262
+ column,
263
+ sortDirection,
264
+ priority,
265
+ tabIndex : childTabIndex
266
+ } ) ;
267
+
256
268
return (
257
- < div
258
- role = "columnheader"
259
- aria-colindex = { column . idx + 1 }
260
- aria-colspan = { colSpan }
261
- aria-rowspan = { rowSpan }
262
- aria-selected = { isCellSelected }
263
- aria-sort = { ariaSort }
264
- tabIndex = { tabIndex }
265
- className = { className }
266
- style = { {
267
- ...getHeaderCellStyle ( column , rowIdx , rowSpan ) ,
268
- ...getCellStyle ( column , colSpan )
269
- } }
270
- onMouseDown = { onMouseDown }
271
- onFocus = { onFocus }
272
- onClick = { onClick }
273
- onKeyDown = { onKeyDown }
274
- { ...dragTargetProps }
275
- { ...dropTargetProps }
276
- >
277
- { column . renderHeaderCell ( {
278
- column,
279
- sortDirection,
280
- priority,
281
- tabIndex : childTabIndex
282
- } ) }
283
-
284
- { resizable && (
285
- < ResizeHandle
286
- direction = { direction }
287
- column = { column }
288
- onColumnResize = { onColumnResize }
289
- onColumnResizeEnd = { onColumnResizeEnd }
290
- />
269
+ < >
270
+ { isDragging && (
271
+ < div
272
+ ref = { dragImageRef }
273
+ style = { style }
274
+ className = { getCellClassname ( column , column . headerCellClass , dragImageClassname ) }
275
+ >
276
+ { content }
277
+ </ div >
291
278
) }
292
- </ div >
279
+ < div
280
+ role = "columnheader"
281
+ aria-colindex = { column . idx + 1 }
282
+ aria-colspan = { colSpan }
283
+ aria-rowspan = { rowSpan }
284
+ aria-selected = { isCellSelected }
285
+ aria-sort = { ariaSort }
286
+ tabIndex = { tabIndex }
287
+ className = { className }
288
+ style = { style }
289
+ onMouseDown = { onMouseDown }
290
+ onFocus = { onFocus }
291
+ onClick = { onClick }
292
+ onKeyDown = { onKeyDown }
293
+ { ...dragTargetProps }
294
+ { ...dropTargetProps }
295
+ >
296
+ { content }
297
+
298
+ { resizable && (
299
+ < ResizeHandle
300
+ direction = { direction }
301
+ column = { column }
302
+ onColumnResize = { onColumnResize }
303
+ onColumnResizeEnd = { onColumnResizeEnd }
304
+ />
305
+ ) }
306
+ </ div >
307
+ </ >
293
308
) ;
294
309
}
295
310
0 commit comments