Skip to content

Commit 18a6c74

Browse files
SaadnajmishwantonNick Lefever
authored
fix(fabric, textinput): implement selection properly (#2689)
## Summary: This is part of a series of PRs where we are cherry-picking fixes from #2117 to update our Fabric implementation on macOS. This is furthermore, a subset of commits from #2675 . This set specifically implements the text selection APIs on TextInput for macOS, along with another set of commits to reduce our diffs in `RCTCopyBackedTextInput` ## Test Plan: Tested the TextInput selection examples in RNTester. All seem to work well. --------- Co-authored-by: Shawn Dempsey <[email protected]> Co-authored-by: Nick Lefever <[email protected]>
1 parent 1211612 commit 18a6c74

File tree

3 files changed

+25
-18
lines changed

3 files changed

+25
-18
lines changed

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

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -679,7 +679,11 @@ - (void)setTextAndSelection:(NSInteger)eventCount
679679
UITextRange *range = [_backedTextInputView textRangeFromPosition:startPosition toPosition:endPosition];
680680
[_backedTextInputView setSelectedTextRange:range notifyDelegate:NO];
681681
}
682-
#endif // [macOS]
682+
#else // [macOS
683+
NSInteger startPosition = MIN(start, end);
684+
NSInteger endPosition = MAX(start, end);
685+
[_backedTextInputView setSelectedTextRange:NSMakeRange(startPosition, endPosition - startPosition) notifyDelegate:YES];
686+
#endif // macOS]
683687
_comingFromJS = NO;
684688
}
685689

@@ -835,8 +839,8 @@ - (void)_updateState
835839
toPosition:selectedTextRange.end];
836840
return AttributedString::Range{(int)start, (int)(end - start)};
837841
#else // [macOS
838-
// [Fabric] Placeholder till we implement selection in Fabric
839-
return AttributedString::Range({0, 1});
842+
NSRange selectedTextRange = [_backedTextInputView selectedTextRange];
843+
return AttributedString::Range{(int)selectedTextRange.location, (int)selectedTextRange.length};
840844
#endif // macOS]
841845
}
842846

@@ -862,8 +866,12 @@ - (void)_setAttributedString:(NSAttributedString *)attributedString
862866
}
863867
#if !TARGET_OS_OSX // [macOS]
864868
UITextRange *selectedRange = _backedTextInputView.selectedTextRange;
869+
#else
870+
NSRange selectedRange = [_backedTextInputView selectedTextRange];
871+
#endif // macOS]
865872
NSInteger oldTextLength = _backedTextInputView.attributedText.string.length;
866873
_backedTextInputView.attributedText = attributedString;
874+
#if !TARGET_OS_OSX // [macOS]
867875
// Updating the UITextView attributedText, for example changing the lineHeight, the color or adding
868876
// a new paragraph with \n, causes the cursor to move to the end of the Text and scroll.
869877
// This is fixed by restoring the cursor position and scrolling to that position (iOS issue 652653).
@@ -882,7 +890,16 @@ - (void)_setAttributedString:(NSAttributedString *)attributedString
882890
[self _restoreTextSelection];
883891
[self _updateTypingAttributes];
884892
_lastStringStateWasUpdatedWith = attributedString;
885-
#endif // [macOS]
893+
#else // [macOS
894+
if (selectedRange.length == 0) {
895+
// Maintaining a cursor position relative to the end of the old text.
896+
NSInteger start = selectedRange.location;
897+
NSInteger offsetFromEnd = oldTextLength - start;
898+
NSInteger newOffset = _backedTextInputView.attributedText.length - offsetFromEnd;
899+
[_backedTextInputView setSelectedTextRange:NSMakeRange(newOffset, 0)
900+
notifyDelegate:YES];
901+
}
902+
#endif // macOS]
886903
}
887904

888905
// Ensure that newly typed text will inherit any custom attributes. We follow the logic of RN Android, where attributes

packages/react-native/React/Fabric/Mounting/ComponentViews/TextInput/RCTTextInputUtils.h

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,8 @@
1818
NS_ASSUME_NONNULL_BEGIN
1919

2020
void RCTCopyBackedTextInput(
21-
#if !TARGET_OS_OSX // [macOS]
22-
RCTUIView<RCTBackedTextInputViewProtocol> *fromTextInput,
23-
RCTUIView<RCTBackedTextInputViewProtocol> *toTextInput
24-
#else // [macOS
25-
RCTUITextView<RCTBackedTextInputViewProtocol> *fromTextInput,
26-
RCTUITextView<RCTBackedTextInputViewProtocol> *toTextInput
27-
#endif // macOS]
21+
RCTPlatformView<RCTBackedTextInputViewProtocol> *fromTextInput,
22+
RCTPlatformView<RCTBackedTextInputViewProtocol> *toTextInput
2823
);
2924

3025
#if !TARGET_OS_OSX // [macOS]

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

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,8 @@
1919
}
2020

2121
void RCTCopyBackedTextInput(
22-
#if !TARGET_OS_OSX // [macOS]
23-
RCTUIView<RCTBackedTextInputViewProtocol> *fromTextInput,
24-
RCTUIView<RCTBackedTextInputViewProtocol> *toTextInput
25-
#else // [macOS
26-
RCTUITextView<RCTBackedTextInputViewProtocol> *fromTextInput,
27-
RCTUITextView<RCTBackedTextInputViewProtocol> *toTextInput
28-
#endif // macOS]
22+
RCTPlatformView<RCTBackedTextInputViewProtocol> *fromTextInput,
23+
RCTPlatformView<RCTBackedTextInputViewProtocol> *toTextInput
2924
)
3025
{
3126
toTextInput.attributedText = RCTSanitizeAttributedString(fromTextInput.attributedText);

0 commit comments

Comments
 (0)