Skip to content

Commit

Permalink
React events: add unmounting to Focus (#15396)
Browse files Browse the repository at this point in the history
  • Loading branch information
necolas authored and trueadm committed Apr 12, 2019
1 parent 543353a commit 805e7f8
Showing 1 changed file with 65 additions and 15 deletions.
80 changes: 65 additions & 15 deletions packages/react-events/src/Focus.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ type FocusProps = {

type FocusState = {
isFocused: boolean,
focusTarget: null | Element | Document,
};

type FocusEventType = 'focus' | 'blur' | 'focuschange';
Expand All @@ -47,54 +48,87 @@ function createFocusEvent(
}

function dispatchFocusInEvents(
event: ReactResponderEvent,
event: null | ReactResponderEvent,
context: ReactResponderContext,
props: FocusProps,
state: FocusState,
) {
const {nativeEvent, target} = event;
if (context.isTargetWithinEventComponent((nativeEvent: any).relatedTarget)) {
return;
if (event != null) {
const {nativeEvent} = event;
if (
context.isTargetWithinEventComponent((nativeEvent: any).relatedTarget)
) {
return;
}
}
if (props.onFocus) {
const syntheticEvent = createFocusEvent('focus', target);
const syntheticEvent = createFocusEvent(
'focus',
((state.focusTarget: any): Element | Document),
);
context.dispatchEvent(syntheticEvent, props.onFocus, {discrete: true});
}
if (props.onFocusChange) {
const listener = () => {
props.onFocusChange(true);
};
const syntheticEvent = createFocusEvent('focuschange', target);
const syntheticEvent = createFocusEvent(
'focuschange',
((state.focusTarget: any): Element | Document),
);
context.dispatchEvent(syntheticEvent, listener, {discrete: true});
}
}

function dispatchFocusOutEvents(
event: ReactResponderEvent,
event: null | ReactResponderEvent,
context: ReactResponderContext,
props: FocusProps,
state: FocusState,
) {
const {nativeEvent, target} = event;
if (context.isTargetWithinEventComponent((nativeEvent: any).relatedTarget)) {
return;
if (event != null) {
const {nativeEvent} = event;
if (
context.isTargetWithinEventComponent((nativeEvent: any).relatedTarget)
) {
return;
}
}
if (props.onBlur) {
const syntheticEvent = createFocusEvent('blur', target);
const syntheticEvent = createFocusEvent(
'blur',
((state.focusTarget: any): Element | Document),
);
context.dispatchEvent(syntheticEvent, props.onBlur, {discrete: true});
}
if (props.onFocusChange) {
const listener = () => {
props.onFocusChange(false);
};
const syntheticEvent = createFocusEvent('focuschange', target);
const syntheticEvent = createFocusEvent(
'focuschange',
((state.focusTarget: any): Element | Document),
);
context.dispatchEvent(syntheticEvent, listener, {discrete: true});
}
}

function unmountResponder(
context: ReactResponderContext,
props: FocusProps,
state: FocusState,
): void {
if (state.isFocused) {
dispatchFocusOutEvents(null, context, props, state);
}
}

const FocusResponder = {
targetEventTypes,
createInitialState(): FocusState {
return {
isFocused: false,
focusTarget: null,
};
},
onEvent(
Expand All @@ -103,25 +137,41 @@ const FocusResponder = {
props: Object,
state: FocusState,
): void {
const {type} = event;
const {type, target} = event;

switch (type) {
case 'focus': {
if (!state.isFocused && !context.hasOwnership()) {
dispatchFocusInEvents(event, context, props);
state.focusTarget = target;
dispatchFocusInEvents(event, context, props, state);
state.isFocused = true;
}
break;
}
case 'blur': {
if (state.isFocused) {
dispatchFocusOutEvents(event, context, props);
dispatchFocusOutEvents(event, context, props, state);
state.isFocused = false;
state.focusTarget = null;
}
break;
}
}
},
onUnmount(
context: ReactResponderContext,
props: FocusProps,
state: FocusState,
) {
unmountResponder(context, props, state);
},
onOwnershipChange(
context: ReactResponderContext,
props: FocusProps,
state: FocusState,
) {
unmountResponder(context, props, state);
},
};

export default {
Expand Down

0 comments on commit 805e7f8

Please sign in to comment.