Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions ios/EnrichedTextInputView.mm
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ @implementation EnrichedTextInputView {
NSMutableDictionary<NSValue *, UIImageView *> *_attachmentViews;
NSArray<NSDictionary *> *_contextMenuItems;
NSString *_submitBehavior;
NSDictionary<NSAttributedStringKey, id> *_capturedAttributesBeforeChange;
}

// MARK: - Component utils
Expand Down Expand Up @@ -1994,6 +1995,14 @@ - (void)handleKeyPressInRange:(NSString *)text range:(NSRange)range {
- (bool)textView:(UITextView *)textView
shouldChangeTextInRange:(NSRange)range
replacementText:(NSString *)text {
// Capture the attributes of the word being replaced (autocorrect /
// predictive) so didProcessEditing: can re-stamp them onto the replacement.
if (range.length > 0) {
_capturedAttributesBeforeChange =
[textView.textStorage attributesAtIndex:range.location
effectiveRange:NULL];
}

// Check if the user pressed "Enter"
if ([text isEqualToString:@"\n"]) {
const bool shouldSubmit = [self textInputShouldSubmitOnReturn];
Expand Down Expand Up @@ -2190,6 +2199,26 @@ - (void)textStorage:(NSTextStorage *)textStorage
editedRange:editedRange
delta:delta];

// Re-stamp custom meta-attributes captured in shouldChangeTextInRange: onto
// the new range so autocorrect/predictive replacements keep their styling.
if ((editedMask & NSTextStorageEditedCharacters) != 0 &&
_capturedAttributesBeforeChange != nil) {
// Skip while an IME composition is in progress; restamp on commit.
if (textView.markedTextRange == nil) {
NSSet *customKeys = [attributesManager customAttributesKeys];
for (NSString *key in _capturedAttributesBeforeChange) {
if ([customKeys containsObject:key]) {
[textStorage addAttribute:key
value:_capturedAttributesBeforeChange[key]
range:editedRange];
}
}
}

// Clear after consuming
_capturedAttributesBeforeChange = nil;
}

// Needed dirty ranges adjustments happen on every character edition.
if ((editedMask & NSTextStorageEditedCharacters) != 0) {
// Always try shifting dirty ranges (happens only with delta != 0).
Expand Down
1 change: 1 addition & 0 deletions ios/attributesManager/AttributesManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,5 @@
- (void)clearRemovedTypingAttributes;
- (void)manageTypingAttributesWithOnlySelection:(BOOL)onlySelectionChanged;
- (void)handleDirtyRangesStyling;
- (NSSet<NSString *> *)customAttributesKeys;
@end
3 changes: 3 additions & 0 deletions ios/attributesManager/AttributesManager.mm
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ - (instancetype)initWithInput:(EnrichedTextInputView *)input {

return self;
}
- (NSSet<NSString *> *)customAttributesKeys {
return _customAttributesKeys;
}

- (void)addDirtyRange:(NSRange)range {
[_dirtyRanges addObject:[NSValue valueWithRange:range]];
Expand Down
Loading