1
1
import { XYCoord } from "react-dnd" ;
2
2
import { NodeApi } from "../interfaces/node-api" ;
3
- import { bound , indexOf , isClosed , isItem } from "../utils" ;
3
+ import {
4
+ bound ,
5
+ indexOf ,
6
+ isClosed ,
7
+ isItem ,
8
+ isOpenWithEmptyChildren ,
9
+ } from "../utils" ;
4
10
import { DropResult } from "./drop-hook" ;
5
11
6
12
function measureHover ( el : HTMLElement , offset : XYCoord ) {
@@ -56,28 +62,6 @@ type Args = {
56
62
nextNode : NodeApi | null ;
57
63
} ;
58
64
59
- function getDropLevel (
60
- hovering : HoverData ,
61
- aboveCursor : NodeApi | null ,
62
- belowCursor : NodeApi | null ,
63
- indent : number
64
- ) {
65
- const hoverLevel = Math . round ( Math . max ( 0 , hovering . x - indent ) / indent ) ;
66
- let min , max ;
67
- if ( ! aboveCursor ) {
68
- max = 0 ;
69
- min = 0 ;
70
- } else if ( ! belowCursor ) {
71
- max = aboveCursor . level ;
72
- min = 0 ;
73
- } else {
74
- max = aboveCursor . level ;
75
- min = belowCursor . level ;
76
- }
77
-
78
- return bound ( hoverLevel , min , max ) ;
79
- }
80
-
81
65
export type ComputedDrop = {
82
66
drop : DropResult | null ;
83
67
cursor : Cursor | null ;
@@ -128,10 +112,11 @@ export type Cursor = LineCursor | NoCursor | HighlightCursor;
128
112
129
113
/**
130
114
* This is the most complex, tricky function in the whole repo.
131
- * It could be simplified and made more understandable.
132
115
*/
133
116
export function computeDrop ( args : Args ) : ComputedDrop {
134
117
const hover = measureHover ( args . element , args . offset ) ;
118
+ const indent = args . indent ;
119
+ const hoverLevel = Math . round ( Math . max ( 0 , hover . x - indent ) / indent ) ;
135
120
const { node, nextNode, prevNode } = args ;
136
121
const [ above , below ] = getNodesAroundCursor ( node , prevNode , nextNode , hover ) ;
137
122
@@ -143,24 +128,56 @@ export function computeDrop(args: Args): ComputedDrop {
143
128
} ;
144
129
}
145
130
146
- /* At the top of the list */
131
+ /*
132
+ * Now we only need to care about the node above the cursor
133
+ * ----------- -------
134
+ */
135
+
136
+ /* There is no node above the cursor line */
147
137
if ( ! above ) {
148
138
return {
149
139
drop : dropAt ( below ?. parent ?. id , 0 ) ,
150
140
cursor : lineCursor ( 0 , 0 ) ,
151
141
} ;
152
142
}
153
143
154
- /* The above node is an item or a closed folder */
155
- if ( isItem ( above ) || isClosed ( above ) ) {
156
- const level = getDropLevel ( hover , above , below , args . indent ) ;
144
+ /* The node above the cursor line is an item */
145
+ if ( isItem ( above ) ) {
146
+ const level = bound ( hoverLevel , below ?. level || 0 , above . level ) ;
147
+ return {
148
+ drop : walkUpFrom ( above , level ) ,
149
+ cursor : lineCursor ( above . rowIndex ! + 1 , level ) ,
150
+ } ;
151
+ }
152
+
153
+ /* The node above the cursor line is a closed folder */
154
+ if ( isClosed ( above ) ) {
155
+ const level = bound ( hoverLevel , below ?. level || 0 , above . level ) ;
157
156
return {
158
157
drop : walkUpFrom ( above , level ) ,
159
158
cursor : lineCursor ( above . rowIndex ! + 1 , level ) ,
160
159
} ;
161
160
}
162
161
163
- /* The above node is an open folder */
162
+ /* The node above the cursor line is an open folder with no children */
163
+ if ( isOpenWithEmptyChildren ( above ) ) {
164
+ const level = bound ( hoverLevel , 0 , above . level + 1 ) ;
165
+ if ( level > above . level ) {
166
+ /* Will be the first child of the empty folder */
167
+ return {
168
+ drop : dropAt ( above . id , 0 ) ,
169
+ cursor : lineCursor ( above . rowIndex ! + 1 , level ) ,
170
+ } ;
171
+ } else {
172
+ /* Will be a sibling or grandsibling of the empty folder */
173
+ return {
174
+ drop : walkUpFrom ( above , level ) ,
175
+ cursor : lineCursor ( above . rowIndex ! + 1 , level ) ,
176
+ } ;
177
+ }
178
+ }
179
+
180
+ /* The node above the cursor is a an open folder with children */
164
181
return {
165
182
drop : dropAt ( above ?. id , 0 ) ,
166
183
cursor : lineCursor ( above . rowIndex ! + 1 , above . level + 1 ) ,
0 commit comments