From 2cbb54e9566d393981f87efe14e9712c9a9a7fc0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dawid=20Ma=C5=82ecki?= Date: Thu, 6 Mar 2025 08:54:21 -0800 Subject: [PATCH] Add TextInput to buildTypes and align Flow with TS types (#49720) Summary: Pull Request resolved: https://github.com/facebook/react-native/pull/49720 Changelog: [Internal] - Added TextInput to buildTypes and aligned Flow with TS types Reviewed By: huntie Differential Revision: D70180918 fbshipit-source-id: 2ea815153cbff47af534d80faec5db98e4a4a0e8 --- .../Components/TextInput/TextInput.flow.js | 39 +++++- .../Components/TextInput/TextInput.js | 116 +++++++++++++++--- .../__snapshots__/public-api-test.js.snap | 57 ++++++--- .../types/__typetests__/index.tsx | 6 +- scripts/build/build-types/buildTypes.js | 2 + 5 files changed, 181 insertions(+), 39 deletions(-) diff --git a/packages/react-native/Libraries/Components/TextInput/TextInput.flow.js b/packages/react-native/Libraries/Components/TextInput/TextInput.flow.js index 53d63372be2d6b..6a675e4839b799 100644 --- a/packages/react-native/Libraries/Components/TextInput/TextInput.flow.js +++ b/packages/react-native/Libraries/Components/TextInput/TextInput.flow.js @@ -88,12 +88,30 @@ export type TextInputKeyPressEventData = $ReadOnly<{ export type TextInputKeyPressEvent = NativeSyntheticEvent; +/** + * @see TextInputProps.onEndEditing + */ export type TextInputEndEditingEventData = $ReadOnly<{ ...TargetEvent, eventCount: number, text: string, }>; +export type TextInputEndEditingEvent = + NativeSyntheticEvent; + +/** + * @see TextInputProps.onSubmitEditing + */ +export type TextInputSubmitEditingEventData = $ReadOnly<{ + ...TargetEvent, + eventCount: number, + text: string, +}>; + +export type TextInputSubmitEditingEvent = + NativeSyntheticEvent; + export type TextInputEditingEvent = NativeSyntheticEvent; @@ -389,6 +407,21 @@ export type TextInputAndroidProps = $ReadOnly<{ */ disableFullscreenUI?: ?boolean, + /** + * Determines whether the individual fields in your app should be included in a + * view structure for autofill purposes on Android API Level 26+. Defaults to auto. + * To disable auto complete, use `off`. + * + * *Android Only* + * + * The following values work on Android only: + * + * - `auto` - let Android decide + * - `no` - not important for autofill + * - `noExcludeDescendants` - this view and its children aren't important for autofill + * - `yes` - is important for autofill + * - `yesExcludeDescendants` - this view is important for autofill but its children aren't + */ importantForAutofill?: ?( | 'auto' | 'no' @@ -783,7 +816,7 @@ export type TextInputProps = $ReadOnly<{ /** * Callback that is called when text input ends. */ - onEndEditing?: ?(e: TextInputEditingEvent) => mixed, + onEndEditing?: ?(e: TextInputEndEditingEvent) => mixed, /** * Callback that is called when the text input is focused. @@ -840,7 +873,7 @@ export type TextInputProps = $ReadOnly<{ * Callback that is called when the text input's submit button is pressed. * Invalid if `multiline={true}` is specified. */ - onSubmitEditing?: ?(e: TextInputEditingEvent) => mixed, + onSubmitEditing?: ?(e: TextInputSubmitEditingEvent) => mixed, /** * Invoked on content scroll with `{ nativeEvent: { contentOffset: { x, y } } }`. @@ -1109,7 +1142,7 @@ export interface TextInputInstance extends HostInstance { * */ type InternalTextInput = component( - ref: React.RefSetter, + ref?: React.RefSetter, ...TextInputProps ); diff --git a/packages/react-native/Libraries/Components/TextInput/TextInput.js b/packages/react-native/Libraries/Components/TextInput/TextInput.js index a2f20815b36c41..203e483d093153 100644 --- a/packages/react-native/Libraries/Components/TextInput/TextInput.js +++ b/packages/react-native/Libraries/Components/TextInput/TextInput.js @@ -58,6 +58,9 @@ if (Platform.OS === 'android') { require('./RCTMultilineTextInputNativeComponent').Commands; } +/** + * @see TextInputProps.onChange + */ export type TextInputChangeEventData = $ReadOnly<{ eventCount: number, target: number, @@ -80,6 +83,9 @@ export type TextInputEvent = NativeSyntheticEvent< }>, >; +/** + * @see TextInputProps.onContentSizeChange + */ export type TextInputContentSizeChangeEventData = $ReadOnly<{ target: number, contentSize: $ReadOnly<{ @@ -95,16 +101,29 @@ export type TargetEvent = $ReadOnly<{ target: number, }>; +/** + * @see TextInputProps.onFocus + */ export type TextInputFocusEventData = TargetEvent; export type TextInputBlurEvent = NativeSyntheticEvent; export type TextInputFocusEvent = NativeSyntheticEvent; +/** + * @see TextInputProps.onScroll + */ +export type TextInputScrollEventData = { + contentOffset: {x: number, y: number}, +}; + type Selection = $ReadOnly<{ start: number, end: number, }>; +/** + * @see TextInputProps.onSelectionChange + */ export type TextInputSelectionChangeEventData = $ReadOnly<{ ...TargetEvent, selection: Selection, @@ -113,7 +132,10 @@ export type TextInputSelectionChangeEventData = $ReadOnly<{ export type TextInputSelectionChangeEvent = NativeSyntheticEvent; -type TextInputKeyPressEventData = $ReadOnly<{ +/** + * @see TextInputProps.onKeyPress + */ +export type TextInputKeyPressEventData = $ReadOnly<{ ...TargetEvent, key: string, target?: ?number, @@ -123,12 +145,30 @@ type TextInputKeyPressEventData = $ReadOnly<{ export type TextInputKeyPressEvent = NativeSyntheticEvent; +/** + * @see TextInputProps.onEndEditing + */ export type TextInputEndEditingEventData = $ReadOnly<{ ...TargetEvent, eventCount: number, text: string, }>; +export type TextInputEndEditingEvent = + NativeSyntheticEvent; + +/** + * @see TextInputProps.onSubmitEditing + */ +export type TextInputSubmitEditingEventData = $ReadOnly<{ + ...TargetEvent, + eventCount: number, + text: string, +}>; + +export type TextInputSubmitEditingEvent = + NativeSyntheticEvent; + export type TextInputEditingEvent = NativeSyntheticEvent; @@ -419,6 +459,21 @@ export type TextInputAndroidProps = $ReadOnly<{ */ disableFullscreenUI?: ?boolean, + /** + * Determines whether the individual fields in your app should be included in a + * view structure for autofill purposes on Android API Level 26+. Defaults to auto. + * To disable auto complete, use `off`. + * + * *Android Only* + * + * The following values work on Android only: + * + * - `auto` - let Android decide + * - `no` - not important for autofill + * - `noExcludeDescendants` - this view and its children aren't important for autofill + * - `yes` - is important for autofill + * - `yesExcludeDescendants` - this view is important for autofill but its children aren't + */ importantForAutofill?: ?( | 'auto' | 'no' @@ -486,11 +541,7 @@ export type TextInputAndroidProps = $ReadOnly<{ underlineColorAndroid?: ?ColorValue, }>; -export type TextInputProps = $ReadOnly<{ - ...$Diff>, - ...TextInputIOSProps, - ...TextInputAndroidProps, - +type TextInputBaseProps = $ReadOnly<{ /** * Can tell `TextInput` to automatically capitalize certain characters. * @@ -792,7 +843,7 @@ export type TextInputProps = $ReadOnly<{ /** * Callback that is called when text input ends. */ - onEndEditing?: ?(e: TextInputEditingEvent) => mixed, + onEndEditing?: ?(e: TextInputEndEditingEvent) => mixed, /** * Callback that is called when the text input is focused. @@ -834,7 +885,7 @@ export type TextInputProps = $ReadOnly<{ * Callback that is called when the text input's submit button is pressed. * Invalid if `multiline={true}` is specified. */ - onSubmitEditing?: ?(e: TextInputEditingEvent) => mixed, + onSubmitEditing?: ?(e: TextInputSubmitEditingEvent) => mixed, /** * Invoked on content scroll with `{ nativeEvent: { contentOffset: { x, y } } }`. @@ -915,7 +966,9 @@ export type TextInputProps = $ReadOnly<{ selectionColor?: ?ColorValue, /** - * The text selection handle color. + * When provided it will set the color of the selection handles when highlighting text. + * Unlike the behavior of `selectionColor` the handle color will be set independently + * from the color of the text selection box. * @platform android */ selectionHandleColor?: ?ColorValue, @@ -990,6 +1043,42 @@ export type TextInputProps = $ReadOnly<{ value?: ?Stringish, }>; +export type TextInputProps = $ReadOnly<{ + ...$Diff>, + ...TextInputIOSProps, + ...TextInputAndroidProps, + ...TextInputBaseProps, +}>; + +type TextInputStateType = $ReadOnly<{ + /** + * @deprecated Use currentlyFocusedInput + * Returns the ID of the currently focused text field, if one exists + * If no text field is focused it returns null + */ + currentlyFocusedField: () => ?number, + + /** + * Returns the ref of the currently focused text field, if one exists + * If no text field is focused it returns null + */ + currentlyFocusedInput: () => ?HostInstance, + + /** + * @param textField ref of the text field to focus + * Focuses the specified text field + * noop if the text field was already focused + */ + focusTextInput: (textField: ?HostInstance) => void, + + /** + * @param textField ref of the text field to focus + * Unfocuses the specified text field + * noop if it wasn't focused + */ + blurTextInput: (textField: ?HostInstance) => void, +}>; + type ViewCommands = $NonMaybeType< | typeof AndroidTextInputCommands | typeof RCTMultilineTextInputNativeCommands @@ -1806,7 +1895,7 @@ const autoCompleteWebToTextContentTypeMap = { }; const ExportedForwardRef: component( - ref: React.RefSetter, + ref?: React.RefSetter, ...props: React.ElementConfig ) = React.forwardRef(function TextInput( { @@ -1878,12 +1967,7 @@ ExportedForwardRef.State = { }; export type TextInputComponentStatics = $ReadOnly<{ - State: $ReadOnly<{ - currentlyFocusedInput: typeof TextInputState.currentlyFocusedInput, - currentlyFocusedField: typeof TextInputState.currentlyFocusedField, - focusTextInput: typeof TextInputState.focusTextInput, - blurTextInput: typeof TextInputState.blurTextInput, - }>, + State: TextInputStateType, }>; const styles = StyleSheet.create({ diff --git a/packages/react-native/Libraries/__tests__/__snapshots__/public-api-test.js.snap b/packages/react-native/Libraries/__tests__/__snapshots__/public-api-test.js.snap index 475b7feb832edf..8808755bebf01e 100644 --- a/packages/react-native/Libraries/__tests__/__snapshots__/public-api-test.js.snap +++ b/packages/react-native/Libraries/__tests__/__snapshots__/public-api-test.js.snap @@ -2656,6 +2656,15 @@ export type TextInputEndEditingEventData = $ReadOnly<{ eventCount: number, text: string, }>; +export type TextInputEndEditingEvent = + NativeSyntheticEvent; +export type TextInputSubmitEditingEventData = $ReadOnly<{ + ...TargetEvent, + eventCount: number, + text: string, +}>; +export type TextInputSubmitEditingEvent = + NativeSyntheticEvent; export type TextInputEditingEvent = NativeSyntheticEvent; type DataDetectorTypesType = @@ -2898,7 +2907,7 @@ export type TextInputProps = $ReadOnly<{ onChangeText?: ?(text: string) => mixed, unstable_onChangeTextSync?: ?(text: string) => mixed, onContentSizeChange?: ?(e: TextInputContentSizeChangeEvent) => mixed, - onEndEditing?: ?(e: TextInputEditingEvent) => mixed, + onEndEditing?: ?(e: TextInputEndEditingEvent) => mixed, onFocus?: ?(e: TextInputFocusEvent) => mixed, onKeyPress?: ?(e: TextInputKeyPressEvent) => mixed, unstable_onKeyPressSync?: ?(e: TextInputKeyPressEvent) => mixed, @@ -2906,7 +2915,7 @@ export type TextInputProps = $ReadOnly<{ onPressIn?: ?(event: GestureResponderEvent) => mixed, onPressOut?: ?(event: GestureResponderEvent) => mixed, onSelectionChange?: ?(e: TextInputSelectionChangeEvent) => mixed, - onSubmitEditing?: ?(e: TextInputEditingEvent) => mixed, + onSubmitEditing?: ?(e: TextInputSubmitEditingEvent) => mixed, onScroll?: ?(e: ScrollEvent) => mixed, placeholder?: ?Stringish, placeholderTextColor?: ?ColorValue, @@ -2931,7 +2940,7 @@ export interface TextInputInstance extends HostInstance { +setSelection: (start: number, end: number) => void; } type InternalTextInput = component( - ref: React.RefSetter, + ref?: React.RefSetter, ...TextInputProps ); export type TextInputComponentStatics = $ReadOnly<{ @@ -2981,6 +2990,9 @@ export type TargetEvent = $ReadOnly<{ export type TextInputFocusEventData = TargetEvent; export type TextInputBlurEvent = NativeSyntheticEvent; export type TextInputFocusEvent = NativeSyntheticEvent; +export type TextInputScrollEventData = { + contentOffset: { x: number, y: number }, +}; type Selection = $ReadOnly<{ start: number, end: number, @@ -2991,7 +3003,7 @@ export type TextInputSelectionChangeEventData = $ReadOnly<{ }>; export type TextInputSelectionChangeEvent = NativeSyntheticEvent; -type TextInputKeyPressEventData = $ReadOnly<{ +export type TextInputKeyPressEventData = $ReadOnly<{ ...TargetEvent, key: string, target?: ?number, @@ -3004,6 +3016,15 @@ export type TextInputEndEditingEventData = $ReadOnly<{ eventCount: number, text: string, }>; +export type TextInputEndEditingEvent = + NativeSyntheticEvent; +export type TextInputSubmitEditingEventData = $ReadOnly<{ + ...TargetEvent, + eventCount: number, + text: string, +}>; +export type TextInputSubmitEditingEvent = + NativeSyntheticEvent; export type TextInputEditingEvent = NativeSyntheticEvent; type DataDetectorTypesType = @@ -3161,10 +3182,7 @@ export type TextInputAndroidProps = $ReadOnly<{ textBreakStrategy?: ?(\\"simple\\" | \\"highQuality\\" | \\"balanced\\"), underlineColorAndroid?: ?ColorValue, }>; -export type TextInputProps = $ReadOnly<{ - ...$Diff>, - ...TextInputIOSProps, - ...TextInputAndroidProps, +type TextInputBaseProps = $ReadOnly<{ autoCapitalize?: ?AutoCapitalize, autoComplete?: ?( | \\"additional-name\\" @@ -3243,14 +3261,14 @@ export type TextInputProps = $ReadOnly<{ onChange?: ?(e: TextInputChangeEvent) => mixed, onChangeText?: ?(text: string) => mixed, onContentSizeChange?: ?(e: TextInputContentSizeChangeEvent) => mixed, - onEndEditing?: ?(e: TextInputEditingEvent) => mixed, + onEndEditing?: ?(e: TextInputEndEditingEvent) => mixed, onFocus?: ?(e: TextInputFocusEvent) => mixed, onKeyPress?: ?(e: TextInputKeyPressEvent) => mixed, onPress?: ?(event: GestureResponderEvent) => mixed, onPressIn?: ?(event: GestureResponderEvent) => mixed, onPressOut?: ?(event: GestureResponderEvent) => mixed, onSelectionChange?: ?(e: TextInputSelectionChangeEvent) => mixed, - onSubmitEditing?: ?(e: TextInputEditingEvent) => mixed, + onSubmitEditing?: ?(e: TextInputSubmitEditingEvent) => mixed, onScroll?: ?(e: ScrollEvent) => mixed, placeholder?: ?Stringish, placeholderTextColor?: ?ColorValue, @@ -3269,13 +3287,20 @@ export type TextInputProps = $ReadOnly<{ style?: ?TextStyleProp, value?: ?Stringish, }>; +export type TextInputProps = $ReadOnly<{ + ...$Diff>, + ...TextInputIOSProps, + ...TextInputAndroidProps, + ...TextInputBaseProps, +}>; +type TextInputStateType = $ReadOnly<{ + currentlyFocusedField: () => ?number, + currentlyFocusedInput: () => ?HostInstance, + focusTextInput: (textField: ?HostInstance) => void, + blurTextInput: (textField: ?HostInstance) => void, +}>; export type TextInputComponentStatics = $ReadOnly<{ - State: $ReadOnly<{ - currentlyFocusedInput: typeof TextInputState.currentlyFocusedInput, - currentlyFocusedField: typeof TextInputState.currentlyFocusedField, - focusTextInput: typeof TextInputState.focusTextInput, - blurTextInput: typeof TextInputState.blurTextInput, - }>, + State: TextInputStateType, }>; declare export default TextInputType; " diff --git a/packages/react-native/types/__typetests__/index.tsx b/packages/react-native/types/__typetests__/index.tsx index 18fd0a30e4a412..1a3d6f9401b3f9 100644 --- a/packages/react-native/types/__typetests__/index.tsx +++ b/packages/react-native/types/__typetests__/index.tsx @@ -1189,7 +1189,7 @@ const customEventEmitter = new CustomEventEmitter(); customEventEmitter.addListener('event', () => {}); class TextInputTest extends React.Component<{}, {username: string}> { - username: TextInput | null = null; + username: React.ElementRef | null = null; handleUsernameChange = (text: string) => { console.log(`text: ${text}`); @@ -1292,9 +1292,7 @@ class TextInputTest extends React.Component<{}, {username: string}> { onContentSizeChange={this.handleOnContentSizeChange} /> - - - + ); } diff --git a/scripts/build/build-types/buildTypes.js b/scripts/build/build-types/buildTypes.js index d9cea911e88054..59e160b037085a 100644 --- a/scripts/build/build-types/buildTypes.js +++ b/scripts/build/build-types/buildTypes.js @@ -29,6 +29,8 @@ const IGNORE_PATTERNS = [ 'packages/react-native/Libraries/StyleSheet/PlatformColorValueTypesIOS.js', 'packages/react-native/Libraries/StyleSheet/processColor.js', 'packages/react-native/Libraries/StyleSheet/StyleSheet.js', + 'packages/react-native/Libraries/Components/TextInput/TextInput.js', + 'packages/react-native/Libraries/Components/TextInput/InputAccessoryView.js', ]; const ENTRY_POINTS = ['packages/react-native/index.js.flow'];