Skip to content

Commit

Permalink
Add TextInput.setSelection method
Browse files Browse the repository at this point in the history
Summary:
Adds a `setSelection` imperative method to `TextInput`.

Changelog:
[General][Added] - Adds a setSelection imperative method to TextInput

Reviewed By: JoshuaGross

Differential Revision: D32186514

fbshipit-source-id: 549a7d93b1c55363cf01d804b1e3d735e55c4481
  • Loading branch information
lyahdav authored and facebook-github-bot committed Dec 3, 2021
1 parent 0aee733 commit 771ca92
Show file tree
Hide file tree
Showing 2 changed files with 43 additions and 3 deletions.
14 changes: 14 additions & 0 deletions Libraries/Components/TextInput/TextInput.js
Original file line number Diff line number Diff line change
Expand Up @@ -766,6 +766,7 @@ type ImperativeMethods = $ReadOnly<{|
clear: () => void,
isFocused: () => boolean,
getNativeRef: () => ?React.ElementRef<HostComponent<mixed>>,
setSelection: (start: number, end: number) => void,
|}>;

const emptyFunctionThatReturnsTrue = () => true;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -1049,6 +1062,7 @@ function InternalTextInput(props: Props): React.Node {
ref.clear = clear;
ref.isFocused = isFocused;
ref.getNativeRef = getNativeRef;
ref.setSelection = setSelection;
}
},
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -377,7 +377,7 @@ class SelectionExample extends React.Component<
$FlowFixMeProps,
SelectionExampleState,
> {
_textInput: any;
_textInput: React.ElementRef<typeof TextInput> | null = null;

constructor(props) {
super(props);
Expand All @@ -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() {
Expand Down Expand Up @@ -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}
/>
Expand Down Expand Up @@ -666,4 +669,27 @@ module.exports = ([
);
},
},
{
title: 'Text selection & cursor placement (imperative)',
name: 'cursorPlacementImperative',
render: function (): React.Node {
return (
<View>
<SelectionExample
testID="singlelineImperative"
style={styles.default}
value="text selection can be changed imperatively"
imperative={true}
/>
<SelectionExample
testID="multilineImperative"
multiline
style={styles.multiline}
value={'multiline text selection\ncan also be changed imperatively'}
imperative={true}
/>
</View>
);
},
},
]: Array<RNTesterModuleExample>);

0 comments on commit 771ca92

Please sign in to comment.