@@ -116,7 +116,21 @@ - (void)setText:(NSString *)text
116
116
117
117
- (void )setAttributedText : (NSAttributedString *)attributedText
118
118
{
119
- [super setAttributedText: attributedText];
119
+ // Using `setAttributedString:` while user is typing breaks some internal mechanics
120
+ // when entering complex input languages such as Chinese, Korean or Japanese.
121
+ // see: https://github.com/facebook/react-native/issues/19339
122
+
123
+ // We try to avoid calling this method as much as we can.
124
+ // If the text has changed, there is nothing we can do.
125
+ if (![super .attributedText.string isEqualToString: attributedText.string]) {
126
+ [super setAttributedText: attributedText];
127
+ } else {
128
+ // But if the text is preserved, we just copying the attributes from the source string.
129
+ if (![super .attributedText isEqualToAttributedString: attributedText]) {
130
+ [self copyTextAttributesFrom: attributedText];
131
+ }
132
+ }
133
+
120
134
[self textDidChange ];
121
135
}
122
136
@@ -247,4 +261,20 @@ - (void)invalidatePlaceholderVisibility
247
261
_placeholderView.hidden = !isVisible;
248
262
}
249
263
264
+ #pragma mark - Utility Methods
265
+
266
+ - (void )copyTextAttributesFrom : (NSAttributedString *)sourceString
267
+ {
268
+ [self .textStorage beginEditing ];
269
+
270
+ NSTextStorage *textStorage = self.textStorage ;
271
+ [sourceString enumerateAttributesInRange: NSMakeRange (0 , sourceString.length)
272
+ options: NSAttributedStringEnumerationReverse
273
+ usingBlock: ^(NSDictionary <NSAttributedStringKey ,id > * _Nonnull attrs, NSRange range, BOOL * _Nonnull stop) {
274
+ [textStorage setAttributes: attrs range: range];
275
+ }];
276
+
277
+ [self .textStorage endEditing ];
278
+ }
279
+
250
280
@end
0 commit comments