From cb70e175e530edee7973782e0846177f3f56f3f8 Mon Sep 17 00:00:00 2001 From: Oleksii Bulenok Date: Mon, 14 Sep 2026 17:22:05 +0200 Subject: [PATCH] fix: scrollRectToVisible on frame size change in RCTTextInputComponentView --- .../TextInput/RCTTextInputComponentView.mm | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/packages/react-native/React/Fabric/Mounting/ComponentViews/TextInput/RCTTextInputComponentView.mm b/packages/react-native/React/Fabric/Mounting/ComponentViews/TextInput/RCTTextInputComponentView.mm index 8f55121cd23d..25a283c80a29 100644 --- a/packages/react-native/React/Fabric/Mounting/ComponentViews/TextInput/RCTTextInputComponentView.mm +++ b/packages/react-native/React/Fabric/Mounting/ComponentViews/TextInput/RCTTextInputComponentView.mm @@ -381,6 +381,10 @@ - (void)updateLayoutMetrics:(const LayoutMetrics &)layoutMetrics _previousContentSize = _backedTextInputView.contentSize; static_cast(*_eventEmitter).onContentSizeChange([self _textInputMetrics]); } + + if (layoutMetrics.frame.size.height > oldLayoutMetrics.frame.size.height) { + [self _scrollCaretIntoEnclosingScrollView]; + } } - (void)prepareForRecycle @@ -843,6 +847,38 @@ - (void)scrollCursorIntoView } } +- (void)_scrollCaretIntoEnclosingScrollView +{ + if (![_backedTextInputView isKindOfClass:[UITextView class]] || !_backedTextInputView.isFirstResponder) { + return; + } + + UIScrollView *enclosingScrollView = nil; + for (UIView *view = self.superview; view != nil; view = view.superview) { + if ([view isKindOfClass:[UIScrollView class]]) { + enclosingScrollView = (UIScrollView *)view; + break; + } + } + if (enclosingScrollView == nil) { + return; + } + + UITextRange *selectedTextRange = _backedTextInputView.selectedTextRange; + if (selectedTextRange == nil) { + return; + } + + [_backedTextInputView layoutIfNeeded]; + CGRect caretRect = [_backedTextInputView caretRectForPosition:selectedTextRange.end]; + if (CGRectIsNull(caretRect) || CGRectIsInfinite(caretRect) || CGRectGetMaxY(caretRect) <= 0) { + return; + } + + CGRect caretRectInScrollView = [_backedTextInputView convertRect:caretRect toView:enclosingScrollView]; + [enclosingScrollView scrollRectToVisible:CGRectInset(caretRectInScrollView, 0, -4) animated:NO]; +} + - (void)_setMultiline:(BOOL)multiline { [_backedTextInputView removeFromSuperview];