@@ -22,6 +22,7 @@ type FocusProps = {
22
22
23
23
type FocusState = {
24
24
isFocused : boolean ,
25
+ focusTarget : null | Element | Document ,
25
26
} ;
26
27
27
28
type FocusEventType = 'focus' | 'blur' | 'focuschange' ;
@@ -47,54 +48,87 @@ function createFocusEvent(
47
48
}
48
49
49
50
function dispatchFocusInEvents (
50
- event : ReactResponderEvent ,
51
+ event : null | ReactResponderEvent ,
51
52
context : ReactResponderContext ,
52
53
props : FocusProps ,
54
+ state : FocusState ,
53
55
) {
54
- const { nativeEvent, target} = event ;
55
- if ( context . isTargetWithinEventComponent ( ( nativeEvent : any ) . relatedTarget ) ) {
56
- return ;
56
+ if ( event != null ) {
57
+ const { nativeEvent} = event ;
58
+ if (
59
+ context . isTargetWithinEventComponent ( ( nativeEvent : any ) . relatedTarget )
60
+ ) {
61
+ return ;
62
+ }
57
63
}
58
64
if ( props . onFocus ) {
59
- const syntheticEvent = createFocusEvent ( 'focus' , target ) ;
65
+ const syntheticEvent = createFocusEvent (
66
+ 'focus' ,
67
+ ( ( state . focusTarget : any ) : Element | Document ) ,
68
+ ) ;
60
69
context . dispatchEvent ( syntheticEvent , props . onFocus , { discrete : true } ) ;
61
70
}
62
71
if ( props . onFocusChange ) {
63
72
const listener = ( ) => {
64
73
props . onFocusChange ( true ) ;
65
74
} ;
66
- const syntheticEvent = createFocusEvent ( 'focuschange' , target ) ;
75
+ const syntheticEvent = createFocusEvent (
76
+ 'focuschange' ,
77
+ ( ( state . focusTarget : any ) : Element | Document ) ,
78
+ ) ;
67
79
context . dispatchEvent ( syntheticEvent , listener , { discrete : true } ) ;
68
80
}
69
81
}
70
82
71
83
function dispatchFocusOutEvents (
72
- event : ReactResponderEvent ,
84
+ event : null | ReactResponderEvent ,
73
85
context : ReactResponderContext ,
74
86
props : FocusProps ,
87
+ state : FocusState ,
75
88
) {
76
- const { nativeEvent , target } = event ;
77
- if ( context . isTargetWithinEventComponent ( ( nativeEvent : any ) . relatedTarget ) ) {
78
- return ;
89
+ if ( event != null ) {
90
+ const { nativeEvent } = event ;
91
+ if (
92
+ context . isTargetWithinEventComponent ( ( nativeEvent : any ) . relatedTarget )
93
+ ) {
94
+ return ;
95
+ }
79
96
}
80
97
if ( props . onBlur ) {
81
- const syntheticEvent = createFocusEvent ( 'blur' , target ) ;
98
+ const syntheticEvent = createFocusEvent (
99
+ 'blur' ,
100
+ ( ( state . focusTarget : any ) : Element | Document ) ,
101
+ ) ;
82
102
context . dispatchEvent ( syntheticEvent , props . onBlur , { discrete : true } ) ;
83
103
}
84
104
if ( props . onFocusChange ) {
85
105
const listener = ( ) = > {
86
106
props . onFocusChange ( false ) ;
87
107
} ;
88
- const syntheticEvent = createFocusEvent ( 'focuschange' , target ) ;
108
+ const syntheticEvent = createFocusEvent (
109
+ 'focuschange' ,
110
+ ( ( state . focusTarget : any ) : Element | Document ) ,
111
+ ) ;
89
112
context . dispatchEvent ( syntheticEvent , listener , { discrete : true } ) ;
90
113
}
91
114
}
92
115
116
+ function unmountResponder (
117
+ context : ReactResponderContext ,
118
+ props : FocusProps ,
119
+ state : FocusState ,
120
+ ) : void {
121
+ if ( state . isFocused ) {
122
+ dispatchFocusOutEvents ( null , context , props , state ) ;
123
+ }
124
+ }
125
+
93
126
const FocusResponder = {
94
127
targetEventTypes ,
95
128
createInitialState ( ) : FocusState {
96
129
return {
97
130
isFocused : false ,
131
+ focusTarget : null ,
98
132
} ;
99
133
} ,
100
134
onEvent (
@@ -103,25 +137,41 @@ const FocusResponder = {
103
137
props : Object ,
104
138
state : FocusState ,
105
139
) : void {
106
- const { type } = event ;
140
+ const { type , target } = event ;
107
141
108
142
switch ( type ) {
109
143
case 'focus ': {
110
144
if ( ! state . isFocused && ! context . hasOwnership ( ) ) {
111
- dispatchFocusInEvents ( event , context , props ) ;
145
+ state . focusTarget = target ;
146
+ dispatchFocusInEvents ( event , context , props , state ) ;
112
147
state . isFocused = true ;
113
148
}
114
149
break ;
115
150
}
116
151
case 'blur' : {
117
152
if ( state . isFocused ) {
118
- dispatchFocusOutEvents ( event , context , props ) ;
153
+ dispatchFocusOutEvents ( event , context , props , state ) ;
119
154
state . isFocused = false ;
155
+ state . focusTarget = null ;
120
156
}
121
157
break ;
122
158
}
123
159
}
124
160
} ,
161
+ onUnmount (
162
+ context : ReactResponderContext ,
163
+ props : FocusProps ,
164
+ state : FocusState ,
165
+ ) {
166
+ unmountResponder ( context , props , state ) ;
167
+ } ,
168
+ onOwnershipChange (
169
+ context : ReactResponderContext ,
170
+ props : FocusProps ,
171
+ state : FocusState ,
172
+ ) {
173
+ unmountResponder ( context , props , state ) ;
174
+ } ,
125
175
} ;
126
176
127
177
export default {
0 commit comments