mirror of
https://github.com/facebook/react-native.git
synced 2025-11-01 09:14:26 +00:00
Genalize focus/blur behavior in JS (#53829)
Summary: Pull Request resolved: https://github.com/facebook/react-native/pull/53829 Forwards along focus and blur calls to their respective native commands, leaving the TextInput path intact for now. There are a few ways places to implement this, all with different trade offs. I decided to leave TextInputState.js intact and instead only go down the original path if the focused/blurred element is a TextInput by using the registered inputs in TextInputState. This revealed a subtle issue where the TextInputs aren't registered in time for the ref callback, meaning you can't focus them there if you rely on the registered list. Changelog: [Internal] Reviewed By: shwanton Differential Revision: D82676628 fbshipit-source-id: d39c92dfc99ec4b5e100203bb43c8a4f9c80a649
This commit is contained in:
committed by
Facebook GitHub Bot
parent
22002bb70c
commit
14dc03e2bd
@@ -449,6 +449,12 @@ function InternalTextInput(props: TextInputProps): React.Node {
|
||||
before we can get to the long term breaking change.
|
||||
*/
|
||||
if (instance != null) {
|
||||
// Register the input immediately when the ref is set so that focus()
|
||||
// can be called from ref callbacks
|
||||
// Double registering during useLayoutEffect is fine, because the underlying
|
||||
// state is a Set.
|
||||
TextInputState.registerInput(instance);
|
||||
|
||||
// $FlowFixMe[prop-missing] - See the explanation above.
|
||||
// $FlowFixMe[unsafe-object-assign]
|
||||
Object.assign(instance, {
|
||||
|
||||
@@ -21,8 +21,8 @@ const ViewNativeComponent: HostComponent<Props> =
|
||||
}));
|
||||
|
||||
interface NativeCommands {
|
||||
+focus: () => void;
|
||||
+blur: () => void;
|
||||
+focus: (viewRef: HostInstance) => void;
|
||||
+blur: (viewRef: HostInstance) => void;
|
||||
+hotspotUpdate: (viewRef: HostInstance, x: number, y: number) => void;
|
||||
+setPressed: (viewRef: HostInstance, pressed: boolean) => void;
|
||||
}
|
||||
|
||||
+3
-2
@@ -14,6 +14,7 @@ import '@react-native/fantom/src/setUpDefaultReactNativeEnvironment';
|
||||
import type {HostInstance} from 'react-native';
|
||||
|
||||
import ReactNativeElement from '../../../../src/private/webapis/dom/nodes/ReactNativeElement';
|
||||
import TextInput from '../../../Components/TextInput/TextInput';
|
||||
import TextInputState from '../../../Components/TextInput/TextInputState';
|
||||
import View from '../../../Components/View/View';
|
||||
import ReactFabricHostComponent from '../ReactFabricHostComponent';
|
||||
@@ -48,7 +49,7 @@ describe('ReactFabricPublicInstance', () => {
|
||||
const nodeRef = createRef<HostInstance>();
|
||||
|
||||
Fantom.runTask(() => {
|
||||
root.render(<View ref={nodeRef} />);
|
||||
root.render(<TextInput ref={nodeRef} />);
|
||||
});
|
||||
|
||||
const node = nullthrows(nodeRef.current);
|
||||
@@ -73,7 +74,7 @@ describe('ReactFabricPublicInstance', () => {
|
||||
const ref = createRef<HostInstance>();
|
||||
|
||||
Fantom.runTask(() => {
|
||||
root.render(<View ref={ref} />);
|
||||
root.render(<TextInput ref={ref} />);
|
||||
});
|
||||
|
||||
const node = nullthrows(ref.current);
|
||||
|
||||
@@ -25,8 +25,10 @@ import type {InstanceHandle} from './internals/NodeInternals';
|
||||
import type ReactNativeDocument from './ReactNativeDocument';
|
||||
|
||||
import TextInputState from '../../../../../Libraries/Components/TextInput/TextInputState';
|
||||
import {Commands as ViewCommands} from '../../../../../Libraries/Components/View/ViewNativeComponent';
|
||||
import {create as createAttributePayload} from '../../../../../Libraries/ReactNative/ReactFabricPublicInstance/ReactNativeAttributePayload';
|
||||
import warnForStyleProps from '../../../../../Libraries/ReactNative/ReactFabricPublicInstance/warnForStyleProps';
|
||||
import * as ReactNativeFeatureFlags from '../../../featureflags/ReactNativeFeatureFlags';
|
||||
import {
|
||||
getNativeElementReference,
|
||||
getPublicInstanceFromInstanceHandle,
|
||||
@@ -140,11 +142,19 @@ class ReactNativeElement extends ReadOnlyElement implements NativeMethods {
|
||||
*/
|
||||
|
||||
blur(): void {
|
||||
TextInputState.blurTextInput(this);
|
||||
if (TextInputState.isTextInput(this)) {
|
||||
TextInputState.blurTextInput(this);
|
||||
} else if (ReactNativeFeatureFlags.enableImperativeFocus()) {
|
||||
ViewCommands.blur(this);
|
||||
}
|
||||
}
|
||||
|
||||
focus() {
|
||||
TextInputState.focusTextInput(this);
|
||||
if (TextInputState.isTextInput(this)) {
|
||||
TextInputState.focusTextInput(this);
|
||||
} else if (ReactNativeFeatureFlags.enableImperativeFocus()) {
|
||||
ViewCommands.focus(this);
|
||||
}
|
||||
}
|
||||
|
||||
measure(callback: MeasureOnSuccessCallback) {
|
||||
|
||||
Reference in New Issue
Block a user