-
Notifications
You must be signed in to change notification settings - Fork 587
/
Copy pathuse-item-click.ts
112 lines (93 loc) · 3.94 KB
/
use-item-click.ts
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
import {SUPPORTED_ARCHIVE_EXTRACT_EXTENSIONS} from '@/features/files/constants'
import {useFilesOperations} from '@/features/files/hooks/use-files-operations'
import {useIsTouchDevice} from '@/features/files/hooks/use-is-touch-device'
import {useNavigate} from '@/features/files/hooks/use-navigate'
import {useFilesStore} from '@/features/files/store/use-files-store'
import {FileSystemItem} from '@/features/files/types'
export const useItemClick = () => {
const {selectedItems, setSelectedItems, isSelectingOnMobile, setViewerItem} = useFilesStore()
const {extractSelectedItems} = useFilesOperations()
const {navigateToDirectory} = useNavigate()
const isTouchDevice = useIsTouchDevice()
const handleClick = (e: React.MouseEvent, item: FileSystemItem, items: FileSystemItem[]) => {
if (isTouchDevice) {
return handleClickOnMobile(item)
}
return handleClickOnDesktop(e, item, items)
}
const handleClickOnMobile = (item: FileSystemItem) => {
// if not selecting, mimic a double click
if (!isSelectingOnMobile) {
return handleDoubleClick(item)
}
// if selecting on mobile, toggle the item's selection
if (selectedItems.some((selectedItem: FileSystemItem) => selectedItem.path === item.path)) {
return setSelectedItems(selectedItems.filter((i: FileSystemItem) => i.path !== item.path))
}
return setSelectedItems([...selectedItems, item])
}
const handleClickOnDesktop = (e: React.MouseEvent, item: FileSystemItem, items: FileSystemItem[]) => {
e.stopPropagation()
// Disable selection if item is uploading
if ('isUploading' in item && item.isUploading) return
// if no items are selected, select the clicked item
if (selectedItems.length === 0) {
return setSelectedItems([item])
}
// if no modifiers are pressed, select the clicked item
if (!e.shiftKey && !e.ctrlKey && !e.metaKey) {
return setSelectedItems([item])
}
// if cmd or ctrl key is pressed, toggle the clicked item's selection
if (e.metaKey || e.ctrlKey) {
let newSelectedItems = Array.from(selectedItems)
if (newSelectedItems.some((selectedItem: FileSystemItem) => selectedItem.path === item.path)) {
newSelectedItems = newSelectedItems.filter((i: FileSystemItem) => i.path !== item.path)
} else {
newSelectedItems = [...selectedItems, item]
}
return setSelectedItems(newSelectedItems)
}
// if shift key is pressed, select a range of items
if (e.shiftKey) {
// get indices for range selection
const lastSelectedItem = selectedItems[selectedItems.length - 1]
const lastSelectedIndex = items.findIndex((i: FileSystemItem) => i.path === lastSelectedItem.path)
const clickedIndex = items.findIndex((i: FileSystemItem) => i.path === item.path)
// determine range bounds
const start = Math.min(lastSelectedIndex, clickedIndex)
const end = Math.max(lastSelectedIndex, clickedIndex)
// get items in range
const itemsInRange = items.slice(start, end + 1)
// combine existing selections with the new range, removing duplicates
const combinedItems = [...selectedItems, ...itemsInRange]
const uniqueItems = Array.from(new Map(combinedItems.map((item) => [item.path, item])).values())
return setSelectedItems(uniqueItems)
}
}
const handleDoubleClick = (item: FileSystemItem) => {
// if touch device and the user is selecting, do nothing
if (isTouchDevice && isSelectingOnMobile) {
return
}
// disable double click if the item is uploading
if ('isUploading' in item && item.isUploading) {
return
}
// if the item is a directory, navigate to it
if (item.type === 'directory') {
return navigateToDirectory(item.path)
}
// if the item is an archive file, extract it
if (SUPPORTED_ARCHIVE_EXTRACT_EXTENSIONS.some((ext) => item.name.toLowerCase().endsWith(ext))) {
return extractSelectedItems()
}
// else set the item as the viewer item
// the viewer will either render it, or show a download dialog if it's not supported
setViewerItem(item)
}
return {
handleClick,
handleDoubleClick,
}
}