-
Notifications
You must be signed in to change notification settings - Fork 1.4k
Expand file tree
/
Copy pathDragBetweenListsExample.tsx
More file actions
126 lines (118 loc) · 3.87 KB
/
DragBetweenListsExample.tsx
File metadata and controls
126 lines (118 loc) · 3.87 KB
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
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
'use client';
import {ListBox, ListBoxItem} from 'vanilla-starter/ListBox';
import {Folder, File} from 'lucide-react';
import {useDragAndDrop, isTextDropItem} from 'react-aria-components';
import {useListData} from 'react-stately';
import React from 'react';
function BidirectionalDnDListBox(props) {
let {list} = props;
let {dragAndDropHooks} = useDragAndDrop({
acceptedDragTypes: ['custom-app-type-bidirectional'],
// Only allow move operations
getAllowedDropOperations: () => ['move'],
getItems(keys) {
return [...keys].map(key => {
let item = list.getItem(key);
// Setup the drag types and associated info for each dragged item.
return {
'custom-app-type-bidirectional': JSON.stringify(item),
'text/plain': item.name
};
});
},
onInsert: async (e) => {
let {
items,
target
} = e;
let processedItems = await Promise.all(
items
.filter(isTextDropItem)
.map(async item => JSON.parse(await item.getText('custom-app-type-bidirectional')))
);
if (target.dropPosition === 'before') {
list.insertBefore(target.key, ...processedItems);
} else if (target.dropPosition === 'after') {
list.insertAfter(target.key, ...processedItems);
}
},
onReorder: (e) => {
let {
keys,
target
} = e;
if (target.dropPosition === 'before') {
list.moveBefore(target.key, [...keys]);
} else if (target.dropPosition === 'after') {
list.moveAfter(target.key, [...keys]);
}
},
onRootDrop: async (e) => {
let {
items
} = e;
let processedItems = await Promise.all(
items
.filter(isTextDropItem)
.map(async item => JSON.parse(await item.getText('custom-app-type-bidirectional')))
);
list.append(...processedItems);
},
/*- begin highlight -*/
onDragEnd: (e) => {
let {
dropOperation,
keys,
isInternal
} = e;
// Only remove the dragged items if they aren't dropped inside the source list
if (dropOperation === 'move' && !isInternal) {
list.remove(...keys);
}
}
/*- end highlight -*/
});
return (
<ListBox
aria-label={props['aria-label']}
selectionMode="multiple"
items={list.items}
dragAndDropHooks={dragAndDropHooks}
style={{width: 300, height: 300, overflow: 'auto'}}>
{item => (
<ListBoxItem textValue={item.name} style={{display: 'flex', alignItems: 'center', gap: 8, flexDirection: 'row', justifyContent: 'flex-start'}}>
{item.type === 'folder' ? <Folder /> : <File />}
<span>{item.name}</span>
</ListBoxItem>
)}
</ListBox>
);
}
export default function DragBetweenListsExample() {
let list1 = useListData({
initialItems: [
{id: '1', type: 'file', name: 'Adobe Photoshop'},
{id: '2', type: 'file', name: 'Adobe XD'},
{id: '3', type: 'folder', name: 'Documents'},
{id: '4', type: 'file', name: 'Adobe InDesign'},
{id: '5', type: 'folder', name: 'Utilities'},
{id: '6', type: 'file', name: 'Adobe AfterEffects'}
]
});
let list2 = useListData({
initialItems: [
{id: '7', type: 'folder', name: 'Pictures'},
{id: '8', type: 'file', name: 'Adobe Fresco'},
{id: '9', type: 'folder', name: 'Apps'},
{id: '10', type: 'file', name: 'Adobe Illustrator'},
{id: '11', type: 'file', name: 'Adobe Lightroom'},
{id: '12', type: 'file', name: 'Adobe Dreamweaver'}
]
});
return (
<div style={{display: 'flex', justifyContent: 'center', flexWrap: 'wrap', gap: 8}}>
<BidirectionalDnDListBox list={list1} aria-label="First ListBox in drag between list example" />
<BidirectionalDnDListBox list={list2} aria-label="Second ListBox in drag between list example" />
</div>
);
}