[fix] TextInput focus management

Defer to the browser's native handling of 'blur' and 'focus'; directly
update the internal state of TextInputState. Fixes an issue with
preserving focus when the tab is backgrounded.

Also ensure the TextInputState is correctly set when a component mounts.
When 'autoFocus' is true, 'onFocus' can be called before the internal
ref is set.

Fix #880
This commit is contained in:
Nicolas Gallagher
2018-03-31 13:57:31 -07:00
parent 8fb9a88ee6
commit 5d77d6e30f
2 changed files with 18 additions and 2 deletions

View File

@@ -1,6 +1,7 @@
/* eslint-env jasmine, jest */
import React from 'react';
import ReactDOM from 'react-dom';
import TextInput from '..';
import { mount, shallow } from 'enzyme';
@@ -112,8 +113,14 @@ describe('components/TextInput', () => {
test('prop "onBlur"', () => {
const onBlur = jest.fn();
const input = findNativeInput(mount(<TextInput onBlur={onBlur} />));
const node = ReactDOM.findDOMNode(input.instance());
// more accurate blur simulation
input.simulate('blur');
node.blur();
expect(onBlur).toHaveBeenCalledTimes(1);
expect(TextInput.State.currentlyFocusedField()).toBe(null);
});
test('prop "onChange"', () => {
@@ -135,8 +142,14 @@ describe('components/TextInput', () => {
test('prop "onFocus"', () => {
const onFocus = jest.fn();
const input = findNativeInput(mount(<TextInput onFocus={onFocus} />));
const node = ReactDOM.findDOMNode(input.instance());
// more accurate focus simulation
input.simulate('focus');
node.focus();
expect(onFocus).toHaveBeenCalledTimes(1);
expect(TextInput.State.currentlyFocusedField()).toBe(node);
});
describe('prop "onKeyPress"', () => {

View File

@@ -161,6 +161,9 @@ class TextInput extends Component<*> {
componentDidMount() {
setSelection(this._node, this.props.selection);
if (document.activeElement === this._node) {
TextInputState._currentlyFocusedNode = this._node;
}
}
componentDidUpdate() {
@@ -263,7 +266,7 @@ class TextInput extends Component<*> {
_handleBlur = e => {
const { onBlur } = this.props;
TextInputState.blurTextInput(this._node);
TextInputState._currentlyFocusedNode = null;
if (onBlur) {
onBlur(e);
}
@@ -283,7 +286,7 @@ class TextInput extends Component<*> {
_handleFocus = e => {
const { clearTextOnFocus, onFocus, selectTextOnFocus } = this.props;
const node = this._node;
TextInputState.focusTextInput(this._node);
TextInputState._currentlyFocusedNode = this._node;
if (onFocus) {
onFocus(e);
}