forked from react-dnd/react-dnd
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Card.tsx
107 lines (91 loc) · 2.48 KB
/
Card.tsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
import { FC, useRef } from 'react'
import { useDrag, useDrop } from 'react-dnd'
import { ItemTypes } from './ItemTypes'
import { XYCoord, Identifier } from 'dnd-core'
const style = {
border: '1px dashed gray',
padding: '0.5rem 1rem',
marginBottom: '.5rem',
backgroundColor: 'white',
cursor: 'move',
}
export interface CardProps {
id: any
text: string
index: number
moveCard: (dragIndex: number, hoverIndex: number) => void
}
interface DragItem {
index: number
id: string
type: string
}
export const Card: FC<CardProps> = ({ id, text, index, moveCard }) => {
const ref = useRef<HTMLDivElement>(null)
const [{ handlerId }, drop] = useDrop<
DragItem,
void,
{ handlerId: Identifier | null }
>({
accept: ItemTypes.CARD,
collect(monitor) {
return {
handlerId: monitor.getHandlerId(),
}
},
hover(item: DragItem, monitor) {
if (!ref.current) {
return
}
const dragIndex = item.index
const hoverIndex = index
// Don't replace items with themselves
if (dragIndex === hoverIndex) {
return
}
// Determine rectangle on screen
const hoverBoundingRect = ref.current?.getBoundingClientRect()
// Get vertical middle
const hoverMiddleY =
(hoverBoundingRect.bottom - hoverBoundingRect.top) / 2
// Determine mouse position
const clientOffset = monitor.getClientOffset()
// Get pixels to the top
const hoverClientY = (clientOffset as XYCoord).y - hoverBoundingRect.top
// Only perform the move when the mouse has crossed half of the items height
// When dragging downwards, only move when the cursor is below 50%
// When dragging upwards, only move when the cursor is above 50%
// Dragging downwards
if (dragIndex < hoverIndex && hoverClientY < hoverMiddleY) {
return
}
// Dragging upwards
if (dragIndex > hoverIndex && hoverClientY > hoverMiddleY) {
return
}
// Time to actually perform the action
moveCard(dragIndex, hoverIndex)
// Note: we're mutating the monitor item here!
// Generally it's better to avoid mutations,
// but it's good here for the sake of performance
// to avoid expensive index searches.
item.index = hoverIndex
},
})
const [{ isDragging }, drag] = useDrag({
type: ItemTypes.CARD,
item: () => {
return { id, index }
},
collect: (monitor: any) => ({
isDragging: monitor.isDragging(),
}),
})
const opacity = isDragging ? 0 : 1
drag(drop(ref))
return (
<div ref={ref} style={{ ...style, opacity }} data-handler-id={handlerId}>
{text}
</div>
)
}