@samitouri / QOS-React-2 / commits / 805e7f8733

React events: add unmounting to Focus (#15396)

Nicolas Gallagher committed Apr 12, 2019 at 04:23 UTC 805e7f87334551c559ab5162c701f82c105ad0b9
1 file changed +65 -15
packages/react-events/src/Focus.js
+65 -15
@@ -22,6 +22,7 @@ type FocusProps = {
22
23 type FocusState = {
24 isFocused: boolean,
25 + focusTarget: null | Element | Document,
26 };
27
28 type FocusEventType = 'focus' | 'blur' | 'focuschange';
@@ -47,54 +48,87 @@ function createFocusEvent(
48 }
49
50 function dispatchFocusInEvents(
50 - event: ReactResponderEvent,
51 + event: null | ReactResponderEvent,
52 context: ReactResponderContext,
53 props: FocusProps,
54 + state: FocusState,
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 + }
63 }
64 if (props.onFocus) {
59 - const syntheticEvent = createFocusEvent('focus', target);
65 + const syntheticEvent = createFocusEvent(
66 + 'focus',
67 + ((state.focusTarget: any): Element | Document),
68 + );
69 context.dispatchEvent(syntheticEvent, props.onFocus, {discrete: true});
70 }
71 if (props.onFocusChange) {
72 const listener = () => {
73 props.onFocusChange(true);
74 };
66 - const syntheticEvent = createFocusEvent('focuschange', target);
75 + const syntheticEvent = createFocusEvent(
76 + 'focuschange',
77 + ((state.focusTarget: any): Element | Document),
78 + );
79 context.dispatchEvent(syntheticEvent, listener, {discrete: true});
80 }
81 }
82
83 function dispatchFocusOutEvents(
72 - event: ReactResponderEvent,
84 + event: null | ReactResponderEvent,
85 context: ReactResponderContext,
86 props: FocusProps,
87 + state: FocusState,
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 + }
96 }
97 if (props.onBlur) {
81 - const syntheticEvent = createFocusEvent('blur', target);
98 + const syntheticEvent = createFocusEvent(
99 + 'blur',
100 + ((state.focusTarget: any): Element | Document),
101 + );
102 context.dispatchEvent(syntheticEvent, props.onBlur, {discrete: true});
103 }
104 if (props.onFocusChange) {
105 const listener = () => {
106 props.onFocusChange(false);
107 };
88 - const syntheticEvent = createFocusEvent('focuschange', target);
108 + const syntheticEvent = createFocusEvent(
109 + 'focuschange',
110 + ((state.focusTarget: any): Element | Document),
111 + );
112 context.dispatchEvent(syntheticEvent, listener, {discrete: true});
113 }
114 }
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 +
126 const FocusResponder = {
127 targetEventTypes,
128 createInitialState(): FocusState {
129 return {
130 isFocused: false,
131 + focusTarget: null,
132 };
133 },
134 onEvent(
@@ -103,25 +137,41 @@ const FocusResponder = {
137 props: Object,
138 state: FocusState,
139 ): void {
106 - const {type} = event;
140 + const {type, target} = event;
141
142 switch (type) {
143 case 'focus': {
144 if (!state.isFocused && !context.hasOwnership()) {
111 - dispatchFocusInEvents(event, context, props);
145 + state.focusTarget = target;
146 + dispatchFocusInEvents(event, context, props, state);
147 state.isFocused = true;
148 }
149 break;
150 }
151 case 'blur': {
152 if (state.isFocused) {
118 - dispatchFocusOutEvents(event, context, props);
153 + dispatchFocusOutEvents(event, context, props, state);
154 state.isFocused = false;
155 + state.focusTarget = null;
156 }
157 break;
158 }
159 }
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 + },
175 };
176
177 export default {