From 085d02133e9e3b24ae548d89e4003899bf85022c Mon Sep 17 00:00:00 2001 From: Eli White Date: Wed, 19 Feb 2020 11:33:40 -0800 Subject: [PATCH] [Native] Migrate focus/blur to call TextInputState with the host component (#18068) --- .../src/ReactFabricHostConfig.js | 4 +- .../src/ReactNativeFiberHostComponent.js | 4 +- .../Libraries/ReactPrivate/TextInputState.js | 5 ++- .../__tests__/ReactFabric-test.internal.js | 37 +++++++++++++++++++ .../ReactNativeMount-test.internal.js | 37 +++++++++++++++++++ 5 files changed, 82 insertions(+), 5 deletions(-) diff --git a/packages/react-native-renderer/src/ReactFabricHostConfig.js b/packages/react-native-renderer/src/ReactFabricHostConfig.js index 959860bcf2cbb..6e371f9ff8cd0 100644 --- a/packages/react-native-renderer/src/ReactFabricHostConfig.js +++ b/packages/react-native-renderer/src/ReactFabricHostConfig.js @@ -104,11 +104,11 @@ class ReactFabricHostComponent { } blur() { - TextInputState.blurTextInput(this._nativeTag); + TextInputState.blurTextInput(this); } focus() { - TextInputState.focusTextInput(this._nativeTag); + TextInputState.focusTextInput(this); } measure(callback: MeasureOnSuccessCallback) { diff --git a/packages/react-native-renderer/src/ReactNativeFiberHostComponent.js b/packages/react-native-renderer/src/ReactNativeFiberHostComponent.js index ba316e010c7a5..c4c74462a4d7e 100644 --- a/packages/react-native-renderer/src/ReactNativeFiberHostComponent.js +++ b/packages/react-native-renderer/src/ReactNativeFiberHostComponent.js @@ -40,11 +40,11 @@ class ReactNativeFiberHostComponent { } blur() { - TextInputState.blurTextInput(this._nativeTag); + TextInputState.blurTextInput(this); } focus() { - TextInputState.focusTextInput(this._nativeTag); + TextInputState.focusTextInput(this); } measure(callback: MeasureOnSuccessCallback) { diff --git a/packages/react-native-renderer/src/__mocks__/react-native/Libraries/ReactPrivate/TextInputState.js b/packages/react-native-renderer/src/__mocks__/react-native/Libraries/ReactPrivate/TextInputState.js index cc97ef5b1852a..cad828edaea7e 100644 --- a/packages/react-native-renderer/src/__mocks__/react-native/Libraries/ReactPrivate/TextInputState.js +++ b/packages/react-native-renderer/src/__mocks__/react-native/Libraries/ReactPrivate/TextInputState.js @@ -10,6 +10,9 @@ // Mock of the Native Hooks // TODO: Should this move into the components themselves? E.g. focusable -const TextInputState = {}; +const TextInputState = { + blurTextInput: jest.fn(), + focusTextInput: jest.fn(), +}; module.exports = TextInputState; diff --git a/packages/react-native-renderer/src/__tests__/ReactFabric-test.internal.js b/packages/react-native-renderer/src/__tests__/ReactFabric-test.internal.js index 0929b80e36b56..2143957d19e5b 100644 --- a/packages/react-native-renderer/src/__tests__/ReactFabric-test.internal.js +++ b/packages/react-native-renderer/src/__tests__/ReactFabric-test.internal.js @@ -16,6 +16,7 @@ let ReactFeatureFlags; let createReactNativeComponentClass; let UIManager; let StrictMode; +let TextInputState; const SET_NATIVE_PROPS_NOT_SUPPORTED_MESSAGE = 'Warning: setNativeProps is not currently supported in Fabric'; @@ -42,6 +43,8 @@ describe('ReactFabric', () => { .UIManager; createReactNativeComponentClass = require('react-native/Libraries/ReactPrivate/ReactNativePrivateInterface') .ReactNativeViewConfigRegistry.register; + TextInputState = require('react-native/Libraries/ReactPrivate/ReactNativePrivateInterface') + .TextInputState; }); it('should be able to create and render a native component', () => { @@ -991,4 +994,38 @@ describe('ReactFabric', () => { ]); expect(match).toBe(child._nativeTag); }); + + it('blur on host component calls TextInputState', () => { + const View = createReactNativeComponentClass('RCTView', () => ({ + validAttributes: {foo: true}, + uiViewClassName: 'RCTView', + })); + + let viewRef = React.createRef(); + ReactFabric.render(, 11); + + expect(TextInputState.blurTextInput).not.toBeCalled(); + + viewRef.current.blur(); + + expect(TextInputState.blurTextInput).toHaveBeenCalledTimes(1); + expect(TextInputState.blurTextInput).toHaveBeenCalledWith(viewRef.current); + }); + + it('focus on host component calls TextInputState', () => { + const View = createReactNativeComponentClass('RCTView', () => ({ + validAttributes: {foo: true}, + uiViewClassName: 'RCTView', + })); + + let viewRef = React.createRef(); + ReactFabric.render(, 11); + + expect(TextInputState.focusTextInput).not.toBeCalled(); + + viewRef.current.focus(); + + expect(TextInputState.focusTextInput).toHaveBeenCalledTimes(1); + expect(TextInputState.focusTextInput).toHaveBeenCalledWith(viewRef.current); + }); }); diff --git a/packages/react-native-renderer/src/__tests__/ReactNativeMount-test.internal.js b/packages/react-native-renderer/src/__tests__/ReactNativeMount-test.internal.js index 395cac0c20d8c..75b2ce286c148 100644 --- a/packages/react-native-renderer/src/__tests__/ReactNativeMount-test.internal.js +++ b/packages/react-native-renderer/src/__tests__/ReactNativeMount-test.internal.js @@ -15,6 +15,7 @@ let StrictMode; let ReactNative; let createReactNativeComponentClass; let UIManager; +let TextInputState; const DISPATCH_COMMAND_REQUIRES_HOST_COMPONENT = "Warning: dispatchCommand was called with a ref that isn't a " + @@ -31,6 +32,8 @@ describe('ReactNative', () => { .UIManager; createReactNativeComponentClass = require('react-native/Libraries/ReactPrivate/ReactNativePrivateInterface') .ReactNativeViewConfigRegistry.register; + TextInputState = require('react-native/Libraries/ReactPrivate/ReactNativePrivateInterface') + .TextInputState; }); it('should be able to create and render a native component', () => { @@ -594,4 +597,38 @@ describe('ReactNative', () => { ]); expect(match).toBe(child._nativeTag); }); + + it('blur on host component calls TextInputState', () => { + const View = createReactNativeComponentClass('RCTView', () => ({ + validAttributes: {foo: true}, + uiViewClassName: 'RCTView', + })); + + let viewRef = React.createRef(); + ReactNative.render(, 11); + + expect(TextInputState.blurTextInput).not.toBeCalled(); + + viewRef.current.blur(); + + expect(TextInputState.blurTextInput).toHaveBeenCalledTimes(1); + expect(TextInputState.blurTextInput).toHaveBeenCalledWith(viewRef.current); + }); + + it('focus on host component calls TextInputState', () => { + const View = createReactNativeComponentClass('RCTView', () => ({ + validAttributes: {foo: true}, + uiViewClassName: 'RCTView', + })); + + let viewRef = React.createRef(); + ReactNative.render(, 11); + + expect(TextInputState.focusTextInput).not.toBeCalled(); + + viewRef.current.focus(); + + expect(TextInputState.focusTextInput).toHaveBeenCalledTimes(1); + expect(TextInputState.focusTextInput).toHaveBeenCalledWith(viewRef.current); + }); });