facebook / react-native

A framework for building native applications using React
https://reactnative.dev
MIT License
119.13k stars 24.32k forks source link

In IOS TextInput does not update style if copy and pasted string is bigger then maxLength #46458

Open aureosouza opened 1 month ago

aureosouza commented 1 month ago

Description

In IOS the TextInput component does not update properly the style when copy and pasted string is bigger then maxLength, issue does not happen on Android. In the minimal reproducible example, there is a simple TextInput that should change text color to red, if text length is bigger or equal then 100 characters. If we copy and paste (using paste with long press) a string longer then 100, the color does not update to red. If user removes and adds last character manually, we can see color changing correctly to red.

Steps to reproduce

  1. Run yarn && npx pod-install && yarn ios
  2. Copy a string bigger then 100 characters
  3. Paste (using long press) the string
  4. Might be necessary to repeat steps 2 and 3 one more time
  5. Noticed color is still green and not red

React Native Version

0.75.2

Affected Platforms

Runtime - iOS

Output of npx react-native info

System:
  OS: macOS 14.5
  CPU: (12) arm64 Apple M2 Pro
  Memory: 91.03 MB / 32.00 GB
  Shell:
    version: "5.9"
    path: /bin/zsh
Binaries:
  Node:
    version: 18.12.1
    path: ~/.nvm/versions/node/v18.12.1/bin/node
  Yarn:
    version: 3.6.4
    path: ~/.nvm/versions/node/v18.12.1/bin/yarn
  npm:
    version: 8.19.2
    path: ~/.nvm/versions/node/v18.12.1/bin/npm
  Watchman: Not Found
Managers:
  CocoaPods:
    version: 1.15.2
    path: /opt/homebrew/bin/pod
SDKs:
  iOS SDK:
    Platforms:
      - DriverKit 23.5
      - iOS 17.5
      - macOS 14.5
      - tvOS 17.5
      - visionOS 1.2
      - watchOS 10.5
  Android SDK: Not Found
IDEs:
  Android Studio: 2024.1 AI-241.15989.150.2411.11948838
  Xcode:
    version: 15.4/15F31d
    path: /usr/bin/xcodebuild
Languages:
  Java:
    version: 17.0.10
    path: /usr/bin/javac
  Ruby:
    version: 2.6.10
    path: /Users/aureobeck/.rbenv/shims/ruby
npmPackages:
  "@react-native-community/cli": Not Found
  react:
    installed: 18.3.1
    wanted: 18.3.1
  react-native:
    installed: 0.75.2
    wanted: 0.75.2
  react-native-macos: Not Found
npmGlobalPackages:
  "*react-native*": Not Found
Android:
  hermesEnabled: true
  newArchEnabled: false
iOS:
  hermesEnabled: true
  newArchEnabled: false

Stacktrace or Logs

No logs

Reproducer

https://github.com/aureosouza/TextInputDemo

Screenshots and Videos

Simulator Screenshot - iPhone 15 Pro - 2024-09-12 at 17 17 19

react-native-bot commented 1 month ago
:warning: Newer Version of React Native is Available!
:information_source: You are on a supported minor version, but it looks like there's a newer patch available - 0.75.3. Please upgrade to the highest patch for your minor or latest and verify if the issue persists (alternatively, create a new project and repro the issue in it). If it does not repro, please let us know so we can close out this issue. This helps us ensure we are looking at issues that still exist in the most recent releases.
react-native-bot commented 1 month ago
:warning: Newer Version of React Native is Available!
:information_source: You are on a supported minor version, but it looks like there's a newer patch available - undefined. Please upgrade to the highest patch for your minor or latest and verify if the issue persists (alternatively, create a new project and repro the issue in it). If it does not repro, please let us know so we can close out this issue. This helps us ensure we are looking at issues that still exist in the most recent releases.
cipolleschi commented 1 month ago

@aureosouza thanks for the report! Can you check if the issues exists also in the New Architecture, please?

canpoyrazoglu commented 1 month ago

I also created a new project from scratch on 0.75.3, tried both old and new architecture, and have a couple of observations to add:

In new architecture on 0.75.3, pasting text behaves completely differently and text seems to be pasted black, completely ignoring style. Please note that I'm not pasting rich text. I've tried pasting it to a plain text editor without rich text support, then copied again just to be 100% sure that I'm not pasting rich text, and it is still pasted black.

When NOT on new architecture on 0.75.3, I had a stranger behavior: the text didn't obey the style regardless of any paste event even when there was no maxLength support. This is what happens in completely typed text with no pasting involved.

Here is my code:

const [text, setText] = useState('');
const style = text.length >= 200 ? {color: 'red'} : {color: 'green'};
console.log('style', style.color);
...
 <ScrollView
        contentInsetAdjustmentBehavior="automatic">
        <TextInput multiline placeholder="Paste some long text" onChangeText={setText} style={style} />
 </ScrollView>

This is the output on a freshly started (just to make sure everything gets reset) app with type only: Simulator Screenshot - iPhone 15 - 2024-09-13 at 07 47 09

The first 200 characters are green, and the rest are red.

After a deep dive into React Native's text handling at iOS side I've stumbled upon that the text is indeed composed of different attributed strings with different colors.

If I change RCTUITextView's - (void)textDidChange method to some ugly hack like this:

- (void)textDidChange
{
  _textWasPasted = NO;
    NSAttributedString *newString = [[NSAttributedString alloc] initWithString:self.attributedText.string attributes:self.defaultTextAttributes];
    if(![self.attributedText isEqualToAttributedString:newString]){
        self.attributedText = newString;
        [self _invalidatePlaceholderVisibility];
    }
}

Then the attributes are set correctly, whole text changes to correct color based on style and max length correctly (though placeholder disappears after the whole text is deleted, but this is a proof of concept anyway), and there are no longer fragments of text in different parts. Of course, this is definitely not a solution as we lose rich text support AND a new attributed string is constructed-and-assigned in every single text change.

At this point I don't know what the solution would be, because I can't manipulate entered text before it is entered as it seems to be handled natively and just dispatched a UITextViewTextDidChangeNotification event which calls textDidChange.

aureosouza commented 1 month ago

@cipolleschi I enabled the new arch with bundle install && RCT_NEW_ARCH_ENABLED=1 bundle exec pod install and it seems to be working now for me. But migrating to new arch in prod is not an option currently, we might try to help finding a fix for the old arch

cipolleschi commented 1 month ago

@aureosouza thanks for testing this out. Currently we don't have capacity to investigate bugs that happens only in the Old Architecture, as our priority is to rollout and stabilize the new one. If you manage to find the root cause and open a PR, I can help tho make sure it lands.

elencho commented 1 month ago

@aureosouza is it only iOS related? can you reproduce it on android?

aureosouza commented 1 month ago

@elencho this is exclusive on iOS, it works correctly on Android