Add support for numberOfLines for TextInput on iOS (#49549)

Summary:
`TextInput` component has been missing support for `numberOfLines` prop on iOS, this PR adds it.

## Changelog:

[IOS] [ADDED] - Add support for `numberOfLines` prop on `TextInput`

Pull Request resolved: https://github.com/facebook/react-native/pull/49549

Test Plan: Tested on RNTester and added a new case utilizing the prop

Reviewed By: cipolleschi

Differential Revision: D69915133

Pulled By: j-piasecki

fbshipit-source-id: b6a86bc64bd3c2129a64e99c9bcec9cf5bfde3bc
This commit is contained in:
Jakub Piasecki
2025-02-24 04:23:58 -08:00
committed by Facebook GitHub Bot
parent 53ff6133a7
commit dcaa33e6d9
4 changed files with 19 additions and 2 deletions
@@ -142,6 +142,7 @@ const RCTTextInputViewConfig = {
placeholder: true,
autoCorrect: true,
multiline: true,
numberOfLines: true,
textContentType: true,
maxLength: true,
autoCapitalize: true,
@@ -1626,6 +1626,7 @@ function InternalTextInput(props: TextInputProps): React.Node {
focusable={tabIndex !== undefined ? !tabIndex : focusable}
mostRecentEventCount={mostRecentEventCount}
nativeID={id ?? props.nativeID}
numberOfLines={props.rows ?? props.numberOfLines}
onBlur={_onBlur}
onChange={_onChange}
onContentSizeChange={props.onContentSizeChange}
@@ -232,6 +232,17 @@ static NSLineBreakMode RCTNSLineBreakModeFromEllipsizeMode(EllipsizeMode ellipsi
layoutManager.usesFontLeading = NO;
[layoutManager addTextContainer:textContainer];
// A workaround for the issue with empty line measurement:
// When maximumNumberOfLines is set to N and N+1 line is empty, the returned
// measurement is for N+1 lines. Adding any character to that line results
// in the correct measurement.
if (attributedString.length > 0 && [[attributedString string] characterAtIndex:attributedString.length - 1] == '\n') {
NSMutableAttributedString *mutableString =
[[NSMutableAttributedString alloc] initWithAttributedString:attributedString];
[mutableString replaceCharactersInRange:NSMakeRange(attributedString.length - 1, 1) withString:@"\n "];
attributedString = mutableString;
}
NSTextStorage *textStorage = [[NSTextStorage alloc] initWithAttributedString:attributedString];
RCTApplyBaselineOffset(textStorage);
@@ -304,7 +304,6 @@ function KeyboardShortcutsExample() {
const styles = StyleSheet.create({
multiline: {
height: 50,
marginBottom: 4,
},
multilinePlaceholderStyles: {
letterSpacing: 10,
@@ -598,7 +597,7 @@ const textInputExamples: Array<RNTesterModuleExample> = [
title: 'Multiline',
render: function (): React.Node {
return (
<View>
<View style={{gap: 4}}>
<ExampleTextInput
placeholder="multiline text input"
multiline={true}
@@ -620,6 +619,11 @@ const textInputExamples: Array<RNTesterModuleExample> = [
multiline={true}
style={styles.multiline}
/>
<ExampleTextInput
placeholder="multiline text input with max 4 lines"
numberOfLines={4}
multiline={true}
/>
<ExampleTextInput
placeholder="uneditable multiline text input"
editable={false}