diff --git a/packages/react-native/Libraries/Text/TextInput/RCTBaseTextInputShadowView.mm b/packages/react-native/Libraries/Text/TextInput/RCTBaseTextInputShadowView.mm index 1f06b79070aa54..9455bd5734487d 100644 --- a/packages/react-native/Libraries/Text/TextInput/RCTBaseTextInputShadowView.mm +++ b/packages/react-native/Libraries/Text/TextInput/RCTBaseTextInputShadowView.mm @@ -158,6 +158,8 @@ - (void)uiManagerWillPerformMounting [attributedText insertAttributedString:propertyAttributedText atIndex:0]; } + [self postprocessAttributedText:attributedText]; + NSAttributedString *newAttributedText; if (![_previousAttributedText isEqualToAttributedString:attributedText]) { // We have to follow `set prop` pattern: @@ -191,6 +193,52 @@ - (void)uiManagerWillPerformMounting }]; } +- (void)postprocessAttributedText:(NSMutableAttributedString *)attributedText +{ + __block CGFloat maximumLineHeight = 0; + + [attributedText enumerateAttribute:NSParagraphStyleAttributeName + inRange:NSMakeRange(0, attributedText.length) + options:NSAttributedStringEnumerationLongestEffectiveRangeNotRequired + usingBlock:^(NSParagraphStyle *paragraphStyle, __unused NSRange range, __unused BOOL *stop) { + if (!paragraphStyle) { + return; + } + + maximumLineHeight = MAX(paragraphStyle.maximumLineHeight, maximumLineHeight); + }]; + + if (maximumLineHeight == 0) { + // `lineHeight` was not specified, nothing to do. + return; + } + + __block CGFloat maximumFontLineHeight = 0; + + [attributedText enumerateAttribute:NSFontAttributeName + inRange:NSMakeRange(0, attributedText.length) + options:NSAttributedStringEnumerationLongestEffectiveRangeNotRequired + usingBlock:^(UIFont *font, NSRange range, __unused BOOL *stop) { + if (!font) { + return; + } + + if (maximumFontLineHeight <= font.lineHeight) { + maximumFontLineHeight = font.lineHeight; + } + }]; + + if (maximumLineHeight < maximumFontLineHeight) { + return; + } + + CGFloat baseLineOffset = maximumLineHeight / 2.0 - maximumFontLineHeight / 2.0; + + [attributedText addAttribute:NSBaselineOffsetAttributeName + value:@(baseLineOffset) + range:NSMakeRange(0, attributedText.length)]; +} + #pragma mark - - (NSAttributedString *)measurableAttributedText