1
1
import { Layers } from "constants/Layers" ;
2
- import React , { ReactNode , useCallback , useRef , useState , useEffect } from "react" ;
2
+ import React , { ReactNode , useCallback , useRef , useEffect } from "react" ;
3
3
4
4
export type CheckSelectFn = (
5
5
item ?: HTMLDivElement | null ,
@@ -41,7 +41,7 @@ const createInitialState = (): SectionState => ({
41
41
42
42
export const DragSelector = React . memo ( ( props : SectionProps ) => {
43
43
const selectAreaRef = useRef < HTMLDivElement > ( null ) ;
44
- const [ state , setState ] = useState < SectionState > ( createInitialState ( ) ) ;
44
+ const stateRef = useRef < SectionState > ( createInitialState ( ) ) ;
45
45
const mountedRef = useRef ( true ) ;
46
46
47
47
// Cleanup on unmount
@@ -54,18 +54,62 @@ export const DragSelector = React.memo((props: SectionProps) => {
54
54
} ;
55
55
} , [ ] ) ;
56
56
57
+ const rectIntersect = useCallback ( (
58
+ selectionBox : Rect | undefined ,
59
+ item : HTMLElement | null | undefined
60
+ ) : boolean => {
61
+ if ( ! selectionBox || ! item || ! selectAreaRef . current ) return false ;
62
+
63
+ const containerRect = selectAreaRef . current . getBoundingClientRect ( ) ;
64
+ const itemBox = {
65
+ top : item . getBoundingClientRect ( ) . top - containerRect . top ,
66
+ left : item . getBoundingClientRect ( ) . left - containerRect . left ,
67
+ width : item . getBoundingClientRect ( ) . width ,
68
+ height : item . getBoundingClientRect ( ) . height ,
69
+ } ;
70
+
71
+ return (
72
+ selectionBox . left <= itemBox . left + itemBox . width &&
73
+ selectionBox . left + selectionBox . width >= itemBox . left &&
74
+ selectionBox . top <= itemBox . top + itemBox . height &&
75
+ selectionBox . top + selectionBox . height >= itemBox . top
76
+ ) ;
77
+ } , [ ] ) ;
78
+
79
+ const calculateSelectionBox = useCallback ( ( startPoint : Point | undefined , endPoint : Point ) => {
80
+ if ( ! stateRef . current . mouseDown || ! startPoint || ! endPoint ) return undefined ;
81
+
82
+ return {
83
+ left : Math . min ( startPoint . x , endPoint . x ) ,
84
+ top : Math . min ( startPoint . y , endPoint . y ) ,
85
+ width : Math . abs ( startPoint . x - endPoint . x ) ,
86
+ height : Math . abs ( startPoint . y - endPoint . y ) ,
87
+ } ;
88
+ } , [ ] ) ;
89
+
90
+ const childrenViewCheckFunc = useCallback ( (
91
+ item ?: HTMLDivElement | null ,
92
+ afterCheck ?: ( checkResult : boolean ) => void
93
+ ) => {
94
+ const result = rectIntersect ( stateRef . current . selectionBox , item ) ;
95
+ if ( afterCheck ) {
96
+ afterCheck ( result ) ;
97
+ }
98
+ return result ;
99
+ } , [ rectIntersect ] ) ;
100
+
57
101
const handleMouseMove = useCallback ( ( e : MouseEvent ) => {
58
- if ( ! mountedRef . current || ! state . mouseDown ) return ;
102
+ if ( ! mountedRef . current || ! stateRef . current . mouseDown ) return ;
59
103
60
104
const endPoint = {
61
105
x : e . pageX - ( selectAreaRef . current ?. getBoundingClientRect ( ) . left ?? 0 ) ,
62
106
y : e . pageY - ( selectAreaRef . current ?. getBoundingClientRect ( ) . top ?? 0 ) ,
63
107
} ;
64
108
65
- setState ( prevState => ( {
66
- ...prevState ,
67
- selectionBox : calculateSelectionBox ( prevState . startPoint , endPoint ) ,
68
- } ) ) ;
109
+ stateRef . current = {
110
+ ...stateRef . current ,
111
+ selectionBox : calculateSelectionBox ( stateRef . current . startPoint , endPoint ) ,
112
+ } ;
69
113
70
114
// Clean up selection properly
71
115
const selection = window . getSelection ( ) ;
@@ -74,83 +118,37 @@ export const DragSelector = React.memo((props: SectionProps) => {
74
118
}
75
119
76
120
props . onMouseMove ( childrenViewCheckFunc ) ;
77
- } , [ state . mouseDown , state . startPoint , props . onMouseMove ] ) ;
121
+ } , [ props . onMouseMove , calculateSelectionBox , childrenViewCheckFunc ] ) ;
78
122
79
123
const handleMouseUp = useCallback ( ( ) => {
80
- if ( ! mountedRef . current ) return ;
81
-
82
124
window . document . removeEventListener ( "mousemove" , handleMouseMove ) ;
83
125
window . document . removeEventListener ( "mouseup" , handleMouseUp ) ;
84
126
props . onMouseUp ( ) ;
85
- setState ( createInitialState ( ) ) ;
127
+ stateRef . current = createInitialState ( ) ;
86
128
} , [ handleMouseMove , props . onMouseUp ] ) ;
87
129
88
130
const handleMouseDown = useCallback ( ( e : React . MouseEvent < HTMLDivElement > ) => {
89
- if ( ! mountedRef . current || e . button === 2 || e . nativeEvent . which === 2 ) return ;
131
+ if ( e . button === 2 || e . nativeEvent . which === 2 ) return ;
90
132
91
133
const startPoint = {
92
134
x : e . pageX - ( selectAreaRef . current ?. getBoundingClientRect ( ) . left ?? 0 ) ,
93
135
y : e . pageY - ( selectAreaRef . current ?. getBoundingClientRect ( ) . top ?? 0 ) ,
94
136
} ;
95
137
96
- setState ( {
138
+ stateRef . current = {
97
139
mouseDown : true ,
98
140
startPoint,
99
141
selectionBox : undefined ,
100
142
appendMode : false ,
101
- } ) ;
143
+ } ;
102
144
103
145
window . document . addEventListener ( "mousemove" , handleMouseMove ) ;
104
146
window . document . addEventListener ( "mouseup" , handleMouseUp ) ;
105
147
props . onMouseDown ( ) ;
106
148
} , [ handleMouseMove , handleMouseUp , props . onMouseDown ] ) ;
107
149
108
- const rectIntersect = useCallback ( (
109
- selectionBox : Rect | undefined ,
110
- item : HTMLElement | null | undefined
111
- ) : boolean => {
112
- if ( ! selectionBox || ! item || ! selectAreaRef . current ) return false ;
113
-
114
- const containerRect = selectAreaRef . current . getBoundingClientRect ( ) ;
115
- const itemBox = {
116
- top : item . getBoundingClientRect ( ) . top - containerRect . top ,
117
- left : item . getBoundingClientRect ( ) . left - containerRect . left ,
118
- width : item . getBoundingClientRect ( ) . width ,
119
- height : item . getBoundingClientRect ( ) . height ,
120
- } ;
121
-
122
- return (
123
- selectionBox . left <= itemBox . left + itemBox . width &&
124
- selectionBox . left + selectionBox . width >= itemBox . left &&
125
- selectionBox . top <= itemBox . top + itemBox . height &&
126
- selectionBox . top + selectionBox . height >= itemBox . top
127
- ) ;
128
- } , [ ] ) ;
129
-
130
- const childrenViewCheckFunc = useCallback ( (
131
- item ?: HTMLDivElement | null ,
132
- afterCheck ?: ( checkResult : boolean ) => void
133
- ) => {
134
- const result = rectIntersect ( state . selectionBox , item ) ;
135
- if ( afterCheck ) {
136
- afterCheck ( result ) ;
137
- }
138
- return result ;
139
- } , [ state . selectionBox , rectIntersect ] ) ;
140
-
141
- const calculateSelectionBox = useCallback ( ( startPoint : Point | undefined , endPoint : Point ) => {
142
- if ( ! state . mouseDown || ! startPoint || ! endPoint ) return undefined ;
143
-
144
- return {
145
- left : Math . min ( startPoint . x , endPoint . x ) ,
146
- top : Math . min ( startPoint . y , endPoint . y ) ,
147
- width : Math . abs ( startPoint . x - endPoint . x ) ,
148
- height : Math . abs ( startPoint . y - endPoint . y ) ,
149
- } ;
150
- } , [ state . mouseDown ] ) ;
151
-
152
150
const renderSelectionBox = useCallback ( ( ) => {
153
- if ( ! state . mouseDown || ! state . startPoint || ! state . selectionBox || ! selectAreaRef . current ) {
151
+ if ( ! stateRef . current . mouseDown || ! stateRef . current . startPoint || ! stateRef . current . selectionBox || ! selectAreaRef . current ) {
154
152
return null ;
155
153
}
156
154
@@ -160,14 +158,14 @@ export const DragSelector = React.memo((props: SectionProps) => {
160
158
background : "rgba(51, 119, 255, 0.1)" ,
161
159
position : "absolute" ,
162
160
zIndex : Layers . dragSelectBox ,
163
- left : state . selectionBox . left ,
164
- top : state . selectionBox . top ,
165
- height : state . selectionBox . height ,
166
- width : state . selectionBox . width ,
161
+ left : stateRef . current . selectionBox . left ,
162
+ top : stateRef . current . selectionBox . top ,
163
+ height : stateRef . current . selectionBox . height ,
164
+ width : stateRef . current . selectionBox . width ,
167
165
} }
168
166
/>
169
167
) ;
170
- } , [ state . mouseDown , state . startPoint , state . selectionBox ] ) ;
168
+ } , [ ] ) ;
171
169
172
170
return (
173
171
< div
0 commit comments