@@ -24,6 +24,7 @@ type HoverProps = {
24
24
} ;
25
25
26
26
type HoverState = {
27
+ hoverTarget : null | Element | Document ,
27
28
isActiveHovered : boolean ,
28
29
isHovered : boolean ,
29
30
isInHitSlop : boolean ,
@@ -66,7 +67,6 @@ function createHoverEvent(
66
67
}
67
68
68
69
function dispatchHoverChangeEvent (
69
- event : ReactResponderEvent ,
70
70
context : ReactResponderContext ,
71
71
props : HoverProps ,
72
72
state : HoverState ,
@@ -75,7 +75,10 @@ function dispatchHoverChangeEvent(
75
75
const listener = ( ) => {
76
76
props . onHoverChange ( bool ) ;
77
77
} ;
78
- const syntheticEvent = createHoverEvent ( 'hoverchange' , event . target ) ;
78
+ const syntheticEvent = createHoverEvent (
79
+ 'hoverchange' ,
80
+ ( ( state . hoverTarget : any ) : Element | Document ) ,
81
+ ) ;
79
82
context . dispatchEvent ( syntheticEvent , listener , { discrete : true } ) ;
80
83
}
81
84
@@ -85,9 +88,14 @@ function dispatchHoverStartEvents(
85
88
props : HoverProps ,
86
89
state : HoverState ,
87
90
) : void {
88
- const { nativeEvent , target } = event ;
89
- if ( context . isTargetWithinEventComponent ( ( nativeEvent : any ) . relatedTarget ) ) {
90
- return ;
91
+ const target = state . hoverTarget ;
92
+ if ( event !== null ) {
93
+ const { nativeEvent } = event ;
94
+ if (
95
+ context . isTargetWithinEventComponent ( ( nativeEvent : any ) . relatedTarget )
96
+ ) {
97
+ return ;
98
+ }
91
99
}
92
100
93
101
state . isHovered = true ;
@@ -101,13 +109,16 @@ function dispatchHoverStartEvents(
101
109
state . isActiveHovered = true ;
102
110
103
111
if ( props . onHoverStart ) {
104
- const syntheticEvent = createHoverEvent ( 'hoverstart' , target ) ;
112
+ const syntheticEvent = createHoverEvent (
113
+ 'hoverstart' ,
114
+ ( ( target : any ) : Element | Document ) ,
115
+ ) ;
105
116
context . dispatchEvent ( syntheticEvent , props . onHoverStart , {
106
117
discrete : true ,
107
118
} ) ;
108
119
}
109
120
if ( props . onHoverChange ) {
110
- dispatchHoverChangeEvent ( event , context , props , state ) ;
121
+ dispatchHoverChangeEvent ( context , props , state ) ;
111
122
}
112
123
} ;
113
124
@@ -129,14 +140,19 @@ function dispatchHoverStartEvents(
129
140
}
130
141
131
142
function dispatchHoverEndEvents (
132
- event : ReactResponderEvent ,
143
+ event : null | ReactResponderEvent ,
133
144
context : ReactResponderContext ,
134
145
props : HoverProps ,
135
146
state : HoverState ,
136
147
) {
137
- const { nativeEvent , target } = event ;
138
- if ( context . isTargetWithinEventComponent ( ( nativeEvent : any ) . relatedTarget ) ) {
139
- return ;
148
+ const target = state . hoverTarget ;
149
+ if ( event !== null ) {
150
+ const { nativeEvent } = event ;
151
+ if (
152
+ context . isTargetWithinEventComponent ( ( nativeEvent : any ) . relatedTarget )
153
+ ) {
154
+ return ;
155
+ }
140
156
}
141
157
142
158
state . isHovered = false ;
@@ -150,11 +166,14 @@ function dispatchHoverEndEvents(
150
166
state . isActiveHovered = false ;
151
167
152
168
if ( props . onHoverEnd ) {
153
- const syntheticEvent = createHoverEvent ( 'hoverend' , target ) ;
169
+ const syntheticEvent = createHoverEvent (
170
+ 'hoverend' ,
171
+ ( ( target : any ) : Element | Document ) ,
172
+ ) ;
154
173
context . dispatchEvent ( syntheticEvent , props . onHoverEnd , { discrete : true } ) ;
155
174
}
156
175
if ( props . onHoverChange ) {
157
- dispatchHoverChangeEvent ( event , context , props , state ) ;
176
+ dispatchHoverChangeEvent ( context , props , state ) ;
158
177
}
159
178
} ;
160
179
@@ -179,6 +198,16 @@ function calculateDelayMS(delay: ?number, min = 0, fallback = 0) {
179
198
return Math . max ( min , maybeNumber != null ? maybeNumber : fallback ) ;
180
199
}
181
200
201
+ function unmountResponder (
202
+ context : ReactResponderContext ,
203
+ props : HoverProps ,
204
+ state : HoverState ,
205
+ ) : void {
206
+ if ( state . isHovered ) {
207
+ dispatchHoverEndEvents ( null , context , props , state ) ;
208
+ }
209
+ }
210
+
182
211
const HoverResponder = {
183
212
targetEventTypes,
184
213
createInitialState ( ) {
@@ -231,6 +260,7 @@ const HoverResponder = {
231
260
state . isInHitSlop = true ;
232
261
return ;
233
262
}
263
+ state . hoverTarget = target ;
234
264
dispatchHoverStartEvents ( event , context , props , state ) ;
235
265
}
236
266
break ;
@@ -241,6 +271,7 @@ const HoverResponder = {
241
271
dispatchHoverEndEvents ( event , context , props , state ) ;
242
272
}
243
273
state . isInHitSlop = false ;
274
+ state . hoverTarget = null ;
244
275
state . isTouched = false ;
245
276
state . skipMouseAfterPointer = false ;
246
277
break ;
@@ -293,12 +324,27 @@ const HoverResponder = {
293
324
case 'pointercancel ': {
294
325
if ( state . isHovered && ! state . isTouched ) {
295
326
dispatchHoverEndEvents ( event , context , props , state ) ;
327
+ state . hoverTarget = null ;
296
328
state . isTouched = false ;
297
329
}
298
330
break ;
299
331
}
300
332
}
301
333
} ,
334
+ onUnmount (
335
+ context : ReactResponderContext ,
336
+ props : HoverProps ,
337
+ state : HoverState ,
338
+ ) {
339
+ unmountResponder ( context , props , state ) ;
340
+ } ,
341
+ onOwnershipChange (
342
+ context : ReactResponderContext ,
343
+ props : HoverProps ,
344
+ state : HoverState ,
345
+ ) {
346
+ unmountResponder ( context , props , state ) ;
347
+ } ,
302
348
} ;
303
349
304
350
export default {
0 commit comments