fix attempting to focus disabled textinputs (#30695)

Summary:
when we call `focus()` upon a TextInput ref which has prop `editable=false` it marks the textinput as focused in `TextInputState` even though the focus is rejected by textinput itself because it is not editable.

then, when you change `editable` prop to `true` and call `focus` again, [this condition](e912c462eb/Libraries/Components/TextInput/TextInputState.js (L46)) or rather [this one](1b2b2198e1/Libraries/Components/TextInput/TextInputState.js (L89)) will evaluate to `false` and focus will not happen even though it can and should happen.

see also https://github.com/facebook/react-native/blob/0.64-stable/Libraries/Renderer/implementations/ReactNativeRenderer-dev.js#L3895

## Changelog

<!-- Help reviewers and the release process by writing your own changelog entry. For an example, see:
https://github.com/facebook/react-native/wiki/Changelog
-->

[General] [Fixed] - `focus()` on TextInput to respect its `editable` state

Pull Request resolved: https://github.com/facebook/react-native/pull/30695

Test Plan: Create a `TextInput` with prop `editable=false` and call `ref.current.focus()` upon its ref. TextInput should not be marked as focused in `TextInputState`.

Reviewed By: yungsters

Differential Revision: D34357913

Pulled By: lunaleaps

fbshipit-source-id: 9a2fb819bbb05ef213c9b5d739dec583ae0a3e6f
This commit is contained in:
Vojtech Novak 2022-03-22 11:43:57 -07:00 коммит произвёл Facebook GitHub Bot
Родитель 83ab3615c5
Коммит 8a5460ce80
2 изменённых файлов: 29 добавлений и 4 удалений

Просмотреть файл

@ -73,7 +73,7 @@ function blurField(textFieldID: ?number) {
/** /**
* @param {number} TextInputID id of the text field to focus * @param {number} TextInputID id of the text field to focus
* Focuses the specified text field * Focuses the specified text field
* noop if the text field was already focused * noop if the text field was already focused or if the field is not editable
*/ */
function focusTextInput(textField: ?ComponentRef) { function focusTextInput(textField: ?ComponentRef) {
if (typeof textField === 'number') { if (typeof textField === 'number') {
@ -86,7 +86,15 @@ function focusTextInput(textField: ?ComponentRef) {
return; return;
} }
if (currentlyFocusedInputRef !== textField && textField != null) { if (textField != null) {
const fieldCanBeFocused =
currentlyFocusedInputRef !== textField &&
// $FlowFixMe - `currentProps` is missing in `NativeMethods`
textField.currentProps?.editable !== false;
if (!fieldCanBeFocused) {
return;
}
focusInput(textField); focusInput(textField);
if (Platform.OS === 'ios') { if (Platform.OS === 'ios') {
// This isn't necessarily a single line text input // This isn't necessarily a single line text input

Просмотреть файл

@ -79,9 +79,26 @@ describe('TextInput tests', () => {
}); });
}); });
it('should have support being focused and unfocused', () => { function createTextInput(extraProps) {
const textInputRef = React.createRef(null); const textInputRef = React.createRef(null);
ReactTestRenderer.create(<TextInput ref={textInputRef} value="value1" />); ReactTestRenderer.create(
<TextInput ref={textInputRef} value="value1" {...extraProps} />,
);
return textInputRef;
}
it('focus() should not do anything if the TextInput is not editable', () => {
const textInputRef = createTextInput({editable: false});
// currentProps is the property actually containing props at runtime
textInputRef.current.currentProps = textInputRef.current.props;
expect(textInputRef.current.isFocused()).toBe(false);
TextInput.State.focusTextInput(textInputRef.current);
expect(textInputRef.current.isFocused()).toBe(false);
});
it('should have support for being focused and blurred', () => {
const textInputRef = createTextInput();
expect(textInputRef.current.isFocused()).toBe(false); expect(textInputRef.current.isFocused()).toBe(false);
ReactNative.findNodeHandle = jest.fn().mockImplementation(ref => { ReactNative.findNodeHandle = jest.fn().mockImplementation(ref => {