Skip to content

Commit 58e909b

Browse files
fix(ios): center TextInput typed text when lineHeight > fontSize on Fabric
Port the Paper-only fix from facebook#38359 to the Fabric path. When lineHeight > fontSize on iOS, UIKit anchors glyphs to the bottom of the attributed-string line box, making typed text render visually too low. The RCTApplyBaselineOffset helper already ships in Fabric (used by <Text> in RCTTextLayoutManager) but was never wired into the <TextInput> path. Call it inside RCTTextInputComponentView._setAttributedString:. To avoid an extra mutableCopy on every programmatic text update, also widen RCTNSAttributedStringFromAttributedString[Box] to return NSMutableAttributedString *. The Value-mode path already built a mutable and returned it typed as immutable; the OpaquePointer-mode path now mutableCopy's explicitly. Tracked by facebook#39145.
1 parent 38aa705 commit 58e909b

3 files changed

Lines changed: 10 additions & 8 deletions

File tree

packages/react-native/React/Fabric/Mounting/ComponentViews/TextInput/RCTTextInputComponentView.mm

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -575,8 +575,8 @@ - (void)setTextAndSelection:(NSInteger)eventCount
575575
}
576576
_comingFromJS = YES;
577577
if (value && ![value isEqualToString:_backedTextInputView.attributedText.string]) {
578-
NSAttributedString *attributedString =
579-
[[NSAttributedString alloc] initWithString:value attributes:_backedTextInputView.defaultTextAttributes];
578+
NSMutableAttributedString *attributedString =
579+
[[NSMutableAttributedString alloc] initWithString:value attributes:_backedTextInputView.defaultTextAttributes];
580580
[self _setAttributedString:attributedString];
581581
[self _updateState];
582582
}
@@ -766,8 +766,10 @@ - (void)_restoreTextSelectionAndIgnoreCaretChange:(BOOL)ignore
766766
[_backedTextInputView setSelectedTextRange:range notifyDelegate:YES];
767767
}
768768

769-
- (void)_setAttributedString:(NSAttributedString *)attributedString
769+
- (void)_setAttributedString:(NSMutableAttributedString *)attributedString
770770
{
771+
RCTApplyBaselineOffset(attributedString);
772+
771773
if ([self _textOf:attributedString equals:_backedTextInputView.attributedText]) {
772774
return;
773775
}

packages/react-native/ReactCommon/react/renderer/textlayoutmanager/platform/ios/react/renderer/textlayoutmanager/RCTAttributedTextUtils.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,10 @@ NSMutableDictionary<NSAttributedStringKey, id> *RCTNSTextAttributesFromTextAttri
2828
/*
2929
* Conversions amond `NSAttributedString`, `AttributedString` and `AttributedStringBox`.
3030
*/
31-
NSAttributedString *RCTNSAttributedStringFromAttributedString(
31+
NSMutableAttributedString *RCTNSAttributedStringFromAttributedString(
3232
const facebook::react::AttributedString &attributedString);
3333

34-
NSAttributedString *RCTNSAttributedStringFromAttributedStringBox(
34+
NSMutableAttributedString *RCTNSAttributedStringFromAttributedStringBox(
3535
const facebook::react::AttributedStringBox &attributedStringBox);
3636

3737
facebook::react::AttributedStringBox RCTAttributedStringBoxFromNSAttributedString(

packages/react-native/ReactCommon/react/renderer/textlayoutmanager/platform/ios/react/renderer/textlayoutmanager/RCTAttributedTextUtils.mm

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -405,7 +405,7 @@ void RCTApplyBaselineOffset(NSMutableAttributedString *attributedText)
405405
return nsAttributedStringFragment;
406406
}
407407

408-
NSAttributedString *RCTNSAttributedStringFromAttributedString(const AttributedString &attributedString)
408+
NSMutableAttributedString *RCTNSAttributedStringFromAttributedString(const AttributedString &attributedString)
409409
{
410410
static UIImage *placeholderImage;
411411
static dispatch_once_t onceToken;
@@ -428,13 +428,13 @@ void RCTApplyBaselineOffset(NSMutableAttributedString *attributedText)
428428
return nsAttributedString;
429429
}
430430

431-
NSAttributedString *RCTNSAttributedStringFromAttributedStringBox(const AttributedStringBox &attributedStringBox)
431+
NSMutableAttributedString *RCTNSAttributedStringFromAttributedStringBox(const AttributedStringBox &attributedStringBox)
432432
{
433433
switch (attributedStringBox.getMode()) {
434434
case AttributedStringBox::Mode::Value:
435435
return RCTNSAttributedStringFromAttributedString(attributedStringBox.getValue());
436436
case AttributedStringBox::Mode::OpaquePointer:
437-
return (NSAttributedString *)unwrapManagedObject(attributedStringBox.getOpaquePointer());
437+
return [(NSAttributedString *)unwrapManagedObject(attributedStringBox.getOpaquePointer()) mutableCopy];
438438
}
439439
}
440440

0 commit comments

Comments
 (0)