Skip to content

Commit ca793dc

Browse files
fix(iOS): formatting stripped when autocorrect applied (#551)
# Summary Fixes: #548 This PR prevents iOS autocorrect from stripping formatting by capturing active meta-attributes in `shouldChangeTextInRange` and reapplying them in `didProcessEditing` ## Test Plan Run reproduction steps from #548, the issue should be resolved. ## Screenshots / Videos https://github.com/user-attachments/assets/dce5a5b5-0626-49bd-8fd1-1c8b34b19efc ## Compatibility | OS | Implemented | | ------- | :---------: | | iOS | ✅ | | Android | ❌ | ## Checklist - [ ] E2E tests are passing - [ ] Required E2E tests have been added (if applicable)
1 parent 0422faa commit ca793dc

3 files changed

Lines changed: 32 additions & 0 deletions

File tree

ios/EnrichedTextInputView.mm

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ @implementation EnrichedTextInputView {
5454
NSMutableDictionary<NSValue *, UIImageView *> *_attachmentViews;
5555
NSArray<NSDictionary *> *_contextMenuItems;
5656
NSString *_submitBehavior;
57+
NSDictionary<NSAttributedStringKey, id> *_capturedAttributesBeforeChange;
5758
}
5859

5960
// MARK: - Component utils
@@ -1994,6 +1995,15 @@ - (void)handleKeyPressInRange:(NSString *)text range:(NSRange)range {
19941995
- (bool)textView:(UITextView *)textView
19951996
shouldChangeTextInRange:(NSRange)range
19961997
replacementText:(NSString *)text {
1998+
// Capture the attributes at range.location that are being replaced
1999+
// (autocorrect / predictive) so didProcessEditing: can re-stamp them onto the
2000+
// replacement.
2001+
if (range.length > 0) {
2002+
_capturedAttributesBeforeChange =
2003+
[textView.textStorage attributesAtIndex:range.location
2004+
effectiveRange:NULL];
2005+
}
2006+
19972007
// Check if the user pressed "Enter"
19982008
if ([text isEqualToString:@"\n"]) {
19992009
const bool shouldSubmit = [self textInputShouldSubmitOnReturn];
@@ -2192,6 +2202,24 @@ - (void)textStorage:(NSTextStorage *)textStorage
21922202

21932203
// Needed dirty ranges adjustments happen on every character edition.
21942204
if ((editedMask & NSTextStorageEditedCharacters) != 0) {
2205+
// Re-stamp custom meta-attributes captured in shouldChangeTextInRange: onto
2206+
// the new range so autocorrect/predictive replacements keep their styling.
2207+
if (_capturedAttributesBeforeChange != nil) {
2208+
// Skip while an IME composition is in progress; restamp on commit.
2209+
if (textView.markedTextRange == nil) {
2210+
NSSet *customKeys = [attributesManager customAttributesKeys];
2211+
for (NSString *key in _capturedAttributesBeforeChange) {
2212+
if ([customKeys containsObject:key]) {
2213+
[textStorage addAttribute:key
2214+
value:_capturedAttributesBeforeChange[key]
2215+
range:editedRange];
2216+
}
2217+
}
2218+
}
2219+
2220+
// Clear after consuming
2221+
_capturedAttributesBeforeChange = nil;
2222+
}
21952223
// Always try shifting dirty ranges (happens only with delta != 0).
21962224
[attributesManager shiftDirtyRangesWithEditedRange:editedRange
21972225
changeInLength:delta];

ios/attributesManager/AttributesManager.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,4 +14,5 @@
1414
- (void)clearRemovedTypingAttributes;
1515
- (void)manageTypingAttributesWithOnlySelection:(BOOL)onlySelectionChanged;
1616
- (void)handleDirtyRangesStyling;
17+
- (NSSet<NSString *> *)customAttributesKeys;
1718
@end

ios/attributesManager/AttributesManager.mm

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,9 @@ - (instancetype)initWithInput:(EnrichedTextInputView *)input {
2525

2626
return self;
2727
}
28+
- (NSSet<NSString *> *)customAttributesKeys {
29+
return _customAttributesKeys;
30+
}
2831

2932
- (void)addDirtyRange:(NSRange)range {
3033
[_dirtyRanges addObject:[NSValue valueWithRange:range]];

0 commit comments

Comments
 (0)