Skip to content

Commit

Permalink
Include existing attributes in newly typed text (#47018)
Browse files Browse the repository at this point in the history
Summary:
Pull Request resolved: #47018

This change makes it so that newly typed text in a TextInput will include the existing attributes present based on cursor position. E.g. if you type after an inner fragment with blue text, the next character will be blue (or, an event emitter specific to an inner fragment will also be expanded). This is a behavior change for the (admittedly rare) case of uncontrolled TextInput with initially present children AttributedText, but more often effect controlled components, before state update (we are after, less likely to need to reset AttributedString because of mismatch).

Originally included this in D64121570, but it's not needed to fix the common case since we include paragraph-level event emitter as part of default attributes, and has some of its own risk, so I decided it is better separate.

Changelog:
[iOS][Changed] - Include existing attributes in newly typed text

Reviewed By: cipolleschi

Differential Revision: D64352310

fbshipit-source-id: 90ef8c49f50186eadf777e81cf6af57e1aada207
  • Loading branch information
NickGerleman authored and facebook-github-bot committed Oct 15, 2024
1 parent 36fd553 commit 557e344
Showing 1 changed file with 18 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -443,6 +443,7 @@ - (void)textInputDidChange

- (void)textInputDidChangeSelection
{
[self _updateTypingAttributes];
if (_comingFromJS) {
return;
}
Expand Down Expand Up @@ -699,9 +700,26 @@ - (void)_setAttributedString:(NSAttributedString *)attributedString
[_backedTextInputView scrollRangeToVisible:NSMakeRange(offsetStart, 0)];
}
[self _restoreTextSelection];
[self _updateTypingAttributes];
_lastStringStateWasUpdatedWith = attributedString;
}

// Ensure that newly typed text will inherit any custom attributes. We follow the logic of RN Android, where attributes
// to the left of the cursor are copied into new text, unless we are at the start of the field, in which case we will
// copy the attributes from text to the right. This allows consistency between backed input and new AttributedText
// https://github.com/facebook/react-native/blob/3102a58df38d96f3dacef0530e4dbb399037fcd2/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/text/internal/span/SetSpanOperation.kt#L30
- (void)_updateTypingAttributes
{
if (_backedTextInputView.attributedText.length > 0) {
NSUInteger offsetStart = [_backedTextInputView offsetFromPosition:_backedTextInputView.beginningOfDocument
toPosition:_backedTextInputView.selectedTextRange.start];

NSUInteger samplePoint = offsetStart == 0 ? 0 : offsetStart - 1;
_backedTextInputView.typingAttributes = [_backedTextInputView.attributedText attributesAtIndex:samplePoint
effectiveRange:NULL];
}
}

- (void)_setMultiline:(BOOL)multiline
{
[_backedTextInputView removeFromSuperview];
Expand Down

0 comments on commit 557e344

Please sign in to comment.