react-native-macos/React/Fabric/Mounting
Shuhao Zhang f3b8d4976f Bug fix: <TextInput> content is reset when emoji is entered at the max length
Summary:
When maxLength is defined in <TextInput>, if the last character at max length is an emoji, the content of the input is cleared:

{F620865178} {F620865237}

Related Github issues:

https://github.com/facebook/react-native/issues/10929
https://github.com/facebook/react-native/issues/10964

## Root cause:

When NSString was created, unicode characters were 16-bit long, so Objective-C considers every unicode character as 16-bit. However, unicode was later extended to more than 16bit, for example, emojis, which causes NSString substring method cuts off at the wrong position.

Example:

```
NSString *s = @"abc{emoji:1f601}";
NSInteger len = s.length; //length is 5 (as {emoji:1f601} occupies two 16-bit characters)
NSString *s3 = [s substringToIndex: 3]; //s3 is "abc"
NSString *s4 = [s substringToIndex: 4]; //s4 is null!
```

If string s, "abc{emoji:1f601}", is entered in <TextInput>, which has max length 4, it will truncate the string to the first 4 characters, "cutting" the emoji in half which causes encoding error and returns null. The text input is cleared.

## Solution:

If the character at max length is longer than 16-bit, truncate the character BEFORE it instead. In the previous example, truncate till index 3 instead of 4. The end result will be "abc" and the emoji is dropped.

## Changelog:

[iOS] [Fixed] - <TextInput> content is reset when emoji is entered at the max length

Reviewed By: p-sun

Differential Revision: D28821909

fbshipit-source-id: 4720d864970b554160ed5388f65b352ce95a6199
2021-06-04 13:40:42 -07:00
..
ComponentViews Bug fix: <TextInput> content is reset when emoji is entered at the max length 2021-06-04 13:40:42 -07:00
RCTComponentViewClassDescriptor.h Fabric: Implementation of `RCTMountingTransactionObserving` protocol 2019-11-01 09:38:25 -07:00
RCTComponentViewDescriptor.h Fabric: Attempt to fix a crash in RCTMountingTransactionObserverCoordinator 2019-11-19 09:50:52 -08:00
RCTComponentViewFactory.h Introduce RCTInstallNativeComponentRegistryBinding 2021-03-15 03:39:13 -07:00
RCTComponentViewFactory.mm Introduce RCTInstallNativeComponentRegistryBinding 2021-03-15 03:39:13 -07:00
RCTComponentViewProtocol.h Fabric: Support for `setIsJSResponder`, all the native changes 2021-02-04 13:16:29 -08:00
RCTComponentViewRegistry.h move fabric to ReactCommon/react/renderer 2020-07-31 13:34:29 -07:00
RCTComponentViewRegistry.mm Remove clean up resources when the app is backgrounded experiment 2021-04-07 17:01:04 -07:00
RCTMountingManager.h Pass "blockNativeResponder" param to RCTMountingManager 2021-04-29 09:29:45 -07:00
RCTMountingManager.mm Pass "blockNativeResponder" param to RCTMountingManager 2021-04-29 09:29:45 -07:00
RCTMountingManagerDelegate.h Tidy up license headers [2/n] 2019-10-16 10:06:34 -07:00
RCTMountingTransactionObserverCoordinator.h move fabric to ReactCommon/react/renderer 2020-07-31 13:34:29 -07:00
RCTMountingTransactionObserverCoordinator.mm Fabric: More asserts in RCTMountingTransactionObserverCoordinator 2019-11-18 18:25:01 -08:00
RCTMountingTransactionObserving.h move fabric to ReactCommon/react/renderer 2020-07-31 13:34:29 -07:00
UIView+ComponentViewProtocol.h Fabric: Support for `setIsJSResponder`, all the native changes 2021-02-04 13:16:29 -08:00
UIView+ComponentViewProtocol.mm Mounting: log more information in iOS-only REMOVE assert 2021-04-14 10:34:57 -07:00