diff --git a/Libraries/Components/TextInput/TextInput.js b/Libraries/Components/TextInput/TextInput.js index 53642621c58d75..96f64d82e9fa80 100644 --- a/Libraries/Components/TextInput/TextInput.js +++ b/Libraries/Components/TextInput/TextInput.js @@ -766,6 +766,7 @@ type ImperativeMethods = $ReadOnly<{| clear: () => void, isFocused: () => boolean, getNativeRef: () => ?React.ElementRef>, + setSelection: (start: number, end: number) => void, |}>; const emptyFunctionThatReturnsTrue = () => true; @@ -1009,6 +1010,18 @@ function InternalTextInput(props: Props): React.Node { } } + function setSelection(start: number, end: number): void { + if (inputRef.current != null) { + viewCommands.setTextAndSelection( + inputRef.current, + mostRecentEventCount, + null, + start, + end, + ); + } + } + // TODO: Fix this returning true on null === null, when no input is focused function isFocused(): boolean { return TextInputState.currentlyFocusedInput() === inputRef.current; @@ -1049,6 +1062,7 @@ function InternalTextInput(props: Props): React.Node { ref.clear = clear; ref.isFocused = isFocused; ref.getNativeRef = getNativeRef; + ref.setSelection = setSelection; } }, }); diff --git a/packages/rn-tester/js/examples/TextInput/TextInputSharedExamples.js b/packages/rn-tester/js/examples/TextInput/TextInputSharedExamples.js index 92115086f40793..25d228b2bc2a90 100644 --- a/packages/rn-tester/js/examples/TextInput/TextInputSharedExamples.js +++ b/packages/rn-tester/js/examples/TextInput/TextInputSharedExamples.js @@ -377,7 +377,7 @@ class SelectionExample extends React.Component< $FlowFixMeProps, SelectionExampleState, > { - _textInput: any; + _textInput: React.ElementRef | null = null; constructor(props) { super(props); @@ -397,8 +397,11 @@ class SelectionExample extends React.Component< } select(start, end) { - this._textInput.focus(); + this._textInput?.focus(); this.setState({selection: {start, end}}); + if (this.props.imperative) { + this._textInput?.setSelection(start, end); + } } selectRandom() { @@ -430,7 +433,7 @@ class SelectionExample extends React.Component< // $FlowFixMe[method-unbinding] added when improving typing for this parameters onSelectionChange={this.onSelectionChange.bind(this)} ref={textInput => (this._textInput = textInput)} - selection={this.state.selection} + selection={this.props.imperative ? undefined : this.state.selection} style={this.props.style} value={this.state.value} /> @@ -666,4 +669,27 @@ module.exports = ([ ); }, }, + { + title: 'Text selection & cursor placement (imperative)', + name: 'cursorPlacementImperative', + render: function (): React.Node { + return ( + + + + + ); + }, + }, ]: Array);