diff --git a/ios/EnrichedTextInputView.mm b/ios/EnrichedTextInputView.mm index 66c22512..64b344e7 100644 --- a/ios/EnrichedTextInputView.mm +++ b/ios/EnrichedTextInputView.mm @@ -54,6 +54,7 @@ @implementation EnrichedTextInputView { NSMutableDictionary *_attachmentViews; NSArray *_contextMenuItems; NSString *_submitBehavior; + NSDictionary *_capturedAttributesBeforeChange; } // MARK: - Component utils @@ -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]; @@ -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). diff --git a/ios/attributesManager/AttributesManager.h b/ios/attributesManager/AttributesManager.h index 8cd42503..1f20bbdb 100644 --- a/ios/attributesManager/AttributesManager.h +++ b/ios/attributesManager/AttributesManager.h @@ -14,4 +14,5 @@ - (void)clearRemovedTypingAttributes; - (void)manageTypingAttributesWithOnlySelection:(BOOL)onlySelectionChanged; - (void)handleDirtyRangesStyling; +- (NSSet *)customAttributesKeys; @end diff --git a/ios/attributesManager/AttributesManager.mm b/ios/attributesManager/AttributesManager.mm index acdf1683..fb4a692c 100644 --- a/ios/attributesManager/AttributesManager.mm +++ b/ios/attributesManager/AttributesManager.mm @@ -25,6 +25,9 @@ - (instancetype)initWithInput:(EnrichedTextInputView *)input { return self; } +- (NSSet *)customAttributesKeys { + return _customAttributesKeys; +} - (void)addDirtyRange:(NSRange)range { [_dirtyRanges addObject:[NSValue valueWithRange:range]];