forked from petyosi/react-virtuoso
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathreact-beautiful-dnd-window-scroller.tsx
107 lines (99 loc) · 3.3 KB
/
react-beautiful-dnd-window-scroller.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 React, { useState } from 'react'
import { DropResult, DragDropContext, Draggable, Droppable, DraggableProvided } from 'react-beautiful-dnd'
import { Components, Virtuoso } from '../src'
type Item = { id: string; text: string }
export default function App() {
const [items, setItems] = useState(() => {
return Array.from({ length: 1000 }, (_, k) => ({
id: `id:${k}`,
text: `item ${k}`,
}))
})
const reorder = React.useCallback((list: Item[], startIndex: number, endIndex: number) => {
const result = Array.from(list)
const [removed] = result.splice(startIndex, 1)
result.splice(endIndex, 0, removed)
return result
}, [])
const onDragEnd = React.useCallback(
(result: DropResult) => {
if (!result.destination) {
return
}
if (result.source.index === result.destination.index) {
return
}
setItems((items) => reorder(items, result.source.index, result.destination!.index))
},
[setItems, reorder]
)
const Item = React.useMemo(() => {
return ({ provided, item, isDragging }: { provided: DraggableProvided; item: Item; isDragging: boolean }) => {
// For borders and visual space,
// use container with padding rather than a margin
// margins confuse virtuoso rendering
return (
<div
{...provided.draggableProps}
{...provided.dragHandleProps}
// eslint-disable-next-line @typescript-eslint/unbound-method
ref={provided.innerRef}
style={{ ...provided.draggableProps.style, paddingBottom: '8px' }}
>
<div
style={{
border: `1px solid ${isDragging ? 'red' : 'black'}`,
}}
>
{item.text}
</div>
</div>
)
}
}, [])
const HeightPreservingItem: Components['Item'] = React.useMemo(() => {
return ({ children, ...props }) => {
return (
// the height is necessary to prevent the item container from collapsing, which confuses Virtuoso measurements
<div {...props} style={{ height: props['data-known-size'] || undefined }}>
{children}
</div>
)
}
}, [])
return (
<div style={{ overflow: 'auto' }}>
<DragDropContext onDragEnd={onDragEnd}>
<Droppable
droppableId="droppable"
mode="virtual"
renderClone={(provided, snapshot, rubric) => (
<Item provided={provided} isDragging={snapshot.isDragging} item={items[rubric.source.index]} />
)}
>
{(provided) => {
return (
// eslint-disable-next-line
<div ref={provided.innerRef as any}>
<Virtuoso
components={{
Item: HeightPreservingItem,
}}
data={items}
itemContent={(index, item) => {
return (
<Draggable draggableId={item.id} index={index} key={item.id}>
{(provided) => <Item provided={provided} item={item} isDragging={false} />}
</Draggable>
)
}}
useWindowScroll={true}
/>
</div>
)
}}
</Droppable>
</DragDropContext>
</div>
)
}