11import { Layers } from "constants/Layers" ;
2- import React , { ReactNode , useCallback , useRef , useState , useEffect } from "react" ;
2+ import React , { ReactNode , useCallback , useRef , useEffect } from "react" ;
33
44export type CheckSelectFn = (
55 item ?: HTMLDivElement | null ,
@@ -41,7 +41,7 @@ const createInitialState = (): SectionState => ({
4141
4242export const DragSelector = React . memo ( ( props : SectionProps ) => {
4343 const selectAreaRef = useRef < HTMLDivElement > ( null ) ;
44- const [ state , setState ] = useState < SectionState > ( createInitialState ( ) ) ;
44+ const stateRef = useRef < SectionState > ( createInitialState ( ) ) ;
4545 const mountedRef = useRef ( true ) ;
4646
4747 // Cleanup on unmount
@@ -54,18 +54,62 @@ export const DragSelector = React.memo((props: SectionProps) => {
5454 } ;
5555 } , [ ] ) ;
5656
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+
57101 const handleMouseMove = useCallback ( ( e : MouseEvent ) => {
58- if ( ! mountedRef . current || ! state . mouseDown ) return ;
102+ if ( ! mountedRef . current || ! stateRef . current . mouseDown ) return ;
59103
60104 const endPoint = {
61105 x : e . pageX - ( selectAreaRef . current ?. getBoundingClientRect ( ) . left ?? 0 ) ,
62106 y : e . pageY - ( selectAreaRef . current ?. getBoundingClientRect ( ) . top ?? 0 ) ,
63107 } ;
64108
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+ } ;
69113
70114 // Clean up selection properly
71115 const selection = window . getSelection ( ) ;
@@ -74,83 +118,37 @@ export const DragSelector = React.memo((props: SectionProps) => {
74118 }
75119
76120 props . onMouseMove ( childrenViewCheckFunc ) ;
77- } , [ state . mouseDown , state . startPoint , props . onMouseMove ] ) ;
121+ } , [ props . onMouseMove , calculateSelectionBox , childrenViewCheckFunc ] ) ;
78122
79123 const handleMouseUp = useCallback ( ( ) => {
80- if ( ! mountedRef . current ) return ;
81-
82124 window . document . removeEventListener ( "mousemove" , handleMouseMove ) ;
83125 window . document . removeEventListener ( "mouseup" , handleMouseUp ) ;
84126 props . onMouseUp ( ) ;
85- setState ( createInitialState ( ) ) ;
127+ stateRef . current = createInitialState ( ) ;
86128 } , [ handleMouseMove , props . onMouseUp ] ) ;
87129
88130 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 ;
90132
91133 const startPoint = {
92134 x : e . pageX - ( selectAreaRef . current ?. getBoundingClientRect ( ) . left ?? 0 ) ,
93135 y : e . pageY - ( selectAreaRef . current ?. getBoundingClientRect ( ) . top ?? 0 ) ,
94136 } ;
95137
96- setState ( {
138+ stateRef . current = {
97139 mouseDown : true ,
98140 startPoint,
99141 selectionBox : undefined ,
100142 appendMode : false ,
101- } ) ;
143+ } ;
102144
103145 window . document . addEventListener ( "mousemove" , handleMouseMove ) ;
104146 window . document . addEventListener ( "mouseup" , handleMouseUp ) ;
105147 props . onMouseDown ( ) ;
106148 } , [ handleMouseMove , handleMouseUp , props . onMouseDown ] ) ;
107149
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-
152150 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 ) {
154152 return null ;
155153 }
156154
@@ -160,14 +158,14 @@ export const DragSelector = React.memo((props: SectionProps) => {
160158 background : "rgba(51, 119, 255, 0.1)" ,
161159 position : "absolute" ,
162160 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 ,
167165 } }
168166 />
169167 ) ;
170- } , [ state . mouseDown , state . startPoint , state . selectionBox ] ) ;
168+ } , [ ] ) ;
171169
172170 return (
173171 < div
0 commit comments