Skip to content

Commit 3abb8f3

Browse files
authored
Use React element for drag image (adazzle#3784)
1 parent d2f40f7 commit 3abb8f3

File tree

1 file changed

+59
-44
lines changed

1 file changed

+59
-44
lines changed

src/HeaderCell.tsx

Lines changed: 59 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
import { useId, useRef, useState } from 'react';
1+
import { useRef, useState } from 'react';
2+
import { flushSync } from 'react-dom';
23
import { css } from '@linaria/core';
34

45
import { useRovingTabIndex } from './hooks';
@@ -63,6 +64,7 @@ const dragImageClassname = css`
6364
border-radius: 4px;
6465
width: fit-content;
6566
outline: 2px solid hsl(207, 100%, 50%);
67+
outline-offset: -2px;
6668
}
6769
`;
6870

@@ -102,6 +104,7 @@ export default function HeaderCell<R, SR>({
102104
setDraggedColumnKey
103105
}: HeaderCellProps<R, SR>) {
104106
const [isOver, setIsOver] = useState(false);
107+
const dragImageRef = useRef<HTMLDivElement>(null);
105108
const isDragging = draggedColumnKey === column.key;
106109
const rowSpan = getHeaderCellRowSpan(column, rowIdx);
107110
const { tabIndex, childTabIndex, onFocus } = useRovingTabIndex(isCellSelected);
@@ -113,7 +116,6 @@ export default function HeaderCell<R, SR>({
113116
const ariaSort =
114117
sortDirection && !priority ? (sortDirection === 'ASC' ? 'ascending' : 'descending') : undefined;
115118
const { sortable, resizable, draggable } = column;
116-
const dragImageId = useId();
117119

118120
const className = getCellClassname(column, column.headerCellClass, {
119121
[cellSortableClassname]: sortable,
@@ -195,18 +197,16 @@ export default function HeaderCell<R, SR>({
195197
}
196198

197199
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);
203205
event.dataTransfer.dropEffect = 'move';
204-
setDraggedColumnKey(column.key);
205206
}
206207

207208
function onDragEnd() {
208209
setDraggedColumnKey(undefined);
209-
document.getElementById(dragImageId)?.remove();
210210
}
211211

212212
function onDragOver(event: React.DragEvent<HTMLDivElement>) {
@@ -253,43 +253,58 @@ export default function HeaderCell<R, SR>({
253253
}
254254
}
255255

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+
256268
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>
291278
)}
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+
</>
293308
);
294309
}
295310

0 commit comments

Comments
 (0)