Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[iOS][TextInput] Apply the fix for CJK languages on single-line text fields. #22546

Closed
wants to merge 2 commits into from

Conversation

mandrigin
Copy link

Follow-up to #19809

This fix generalizes the setAttributedString: fix to single-line text fields.

Fixes #19339

Pull requests that expand test coverage are more likely to get reviewed. Add a test case whenever possible!

Test Plan:

⚠️ Possible areas of regressions: formatting of single-line text fields.

The test app

import React, {Component} from 'react';
import {StyleSheet, Text, TextInput, View} from 'react-native';

type Props = {};
export default class App extends Component<Props> {
    constructor(props) {
        super(props);
        this.state = { text: '', textM: '' };
    }
    render() {
        return (
            <View style={styles.container}>
            <Text style={styles.instructions}>SINGLE_LINE</Text>
            <TextInput
                style={{height: 40, width: 200, borderWidth: 1}}
                onChangeText={(text) => this.setState({text: text})}
                value={this.state.text}
            />
            <Text style={styles.instructions}>MULTILINE</Text>
            <TextInput
                style={{height: 40, width: 200, borderWidth: 1}}
                multiline={true}
                onChangeText={(text) => this.setState({textM: text})}
                value={this.state.textM}
            />
            </View>
        );
    }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    paddingTop: 100,
    alignItems: 'center',
    backgroundColor: '#F5FCFF',
  },
  instructions: {
    textAlign: 'center',
    color: '#333333',
    marginBottom: 5,
    marginTop: 20,
  },
});

Essentially, the steps to reproduce are described in the issue:

  • For both single-line and multi-line text fields:
    • Type some Korean characters in TextInput, such as "하늘" (buttons ,,,,).
    • Then move the cursor to the beginning of the text, type "파란" (buttons ,,,,) this time.

Behaviour before this fix
Actual text (Single-line): ㅍㅏㄹㅏㄴ하늘.
Actual text (Multi-line): 파란하늘.
Expected text (both fields): 파란하늘.
Characters aren't combined properly in single-line.

Behaviour after this fix (correct)
Actual text (Single-line): 파란하늘.
Actual text (Multi-line): 파란하늘.
Expected text (both fields): 파란하늘.
Characters are combined correctly.

Changelog:

[IOS] [BUGFIX] [TextView] - Fix Korean/Chinese/Japanese input for single-line TextView on iOS.

@react-native-bot react-native-bot added 🔶Components Component: Text Component: TextInput Related to the TextInput component. Platform: iOS iOS applications. labels Dec 6, 2018
@facebook-github-bot facebook-github-bot added the CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. label Dec 6, 2018
@mandrigin mandrigin force-pushed the fix-cjk-single-line branch from f2ee775 to ad7bd64 Compare December 6, 2018 17:10
@cpojer cpojer requested a review from shergin December 7, 2018 03:32
@mandrigin mandrigin force-pushed the fix-cjk-single-line branch 2 times, most recently from a0a1f1c to bc35574 Compare December 7, 2018 11:19
Copy link
Contributor

@shergin shergin left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why can't we move all this logic inside -[RCTUITextView setAttributedText] (which might imply adding sanitizing inside the getter. And same thing for UITextField subclass.

There is a huge reason for that desire: This module is the most complex module in the whole RN rendering subsystem. We have to push all logic that might be considered as "improvements of core UIKit components" down to subclasses dedicated for that. The reason is that our RN-specific model of the world implies that our expectations about how UIKit works are correct. That's really challenging to implement the ideal modal itself, so we cannot afford polluting that with UIKit specific fixes. We have to decouple them in subclasses that "fix" UIKit stuff for us.

@shergin
Copy link
Contributor

shergin commented Dec 13, 2018

@mandrigin I deeply appreciate your effort and I am existed about those fixes. We struggled with them for so long time! But we really need to do it right to make it sustainable.

[_attributesHolder setAttributedString:super.attributedText];
}

- (NSAttributedString *)attributedText {
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@shergin it is easier to me to comment here, to show why I did it this way.
UITextField is a very basic UI element. It doesn't expose any API to just change the string attributes without re-setting the attributed string completely (and breaking CJK input).
Luckily, it relies on it's own public (and overridable) property attributedText when rendering.

What I'm doing here is hijacking this property and replacing its value with the value I store locally, in NSMutableAttributedString, which I can replace without noticeable side-effects. So this override has to be here, if we want to continue to use UITextField. It's a hack and it can potentially break with new iOS releases, etc.

To be able to consolidate logic, we can just use UITextView everywhere, it provides all the necessary functionality as public APIs. What is the history between having 2 different implementations for single and multiline text views?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I mean why not consolidate all attribute specific-logic in this class making attributedText and setAttributedText behave as we want?

We have to have two different underlying components because they simply behave differently. There is no way to configure UITextView behave exactly as UITextField.

Copy link
Contributor

@shergin shergin Dec 13, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I mean we have an original problem: When we call setAttributedText, marked fragment gets reset. So, let's add all checks that prevents that into both RCTUITextField and RCTUITextView (iirc, now we have only one of them).

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ah, okay, I mistread your initial comment.
So you mean, just duplicate the logic and encapsulate it inside RCTUITextField and RCTUITextView classes separately, so we can call setAttributedString safely on both RCTUITextField and RCTUITextView?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should be fixed now

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(Let's continue discussion here.)
Now we are abstracted from anything else, so we can work on it. 😄

I think, it's great. ❤️

Nits:

  • Instead of referring issues and commenting every single line, we have to leave one comment that describe a problem and (most importantly) the change in the behavior of the methods. That's more sustainable and easy to understand for people from the future which don't have a full context.
  • Codestyle. (New line before { and spaces.)

Btw, I don't think it's only fix for CJK problem. It's more wide problem which happens when we are replacing some attributed string with completely new one without paying attention to what attributes were added to the string by active text input. So, if we can preserve those attributes, I bet full replacing will work with CJK. (The current solution is good enough though.)

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

pushed the fix to address this feedback

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@shergin is there anything else I need to fix in this PR?

// Search for `GH-19339` to see all code affected by this fix.

- (void)setAttributedText:(NSAttributedString *)attributedText {
[_attributesHolder setAttributedString:attributedText];

This comment was marked as outdated.

This comment was marked as outdated.

@mandrigin
Copy link
Author

@shergin I just simplified my fix to affect only one source file.

@facebook-github-bot facebook-github-bot added the Import Started This pull request has been imported. This does not imply the PR has been approved. label Feb 4, 2019
Copy link
Contributor

@facebook-github-bot facebook-github-bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@shergin is landing this pull request. If you are a Facebook employee, you can view this diff on Phabricator.

matt-oakes pushed a commit to matt-oakes/react-native that referenced this pull request Feb 7, 2019
…#22546)

Summary:
Follow-up to facebook#19809

This fix generalizes the `setAttributedString:` fix to single-line text fields.

Fixes facebook#19339

_Pull requests that expand test coverage are more likely to get reviewed. Add a test case whenever possible!_
Pull Request resolved: facebook#22546

Differential Revision: D13948951

Pulled By: shergin

fbshipit-source-id: 67992c02b32f33f6d61fac4554e4f46b973262c1
@PeteTheHeat
Copy link
Contributor

I'm going to have to revert this, it broke single line text inputs, sorry 😥

Repro:
In this playground https://gist.github.com/PeteTheHeat/52aef6290850b9840342e884325bdd0a type in the inputs, tap away, and watch them revert back to default text.

@mandrigin
Copy link
Author

Sure, I will take a look next week on what can be improved

facebook-github-bot pushed a commit that referenced this pull request Feb 22, 2019
…est fields.

Summary:
This PR (#22546) broke single line text inputs. After inputting some text and tapping away, the text input reverts back to default text.

Revert solved the issue.

Reviewed By: cpojer

Differential Revision: D14185897

fbshipit-source-id: cc7f0f2ebfb0494062afbc628c4fe27ad27fb1c6
@alsun2001
Copy link

I'm going to have to revert this, it broke single line text inputs, sorry 😥

Repro:
In this playground https://gist.github.com/PeteTheHeat/52aef6290850b9840342e884325bdd0a type in the inputs, tap away, and watch them revert back to default text.

By the way, this issue repros on iOS 9 and iOS 10 only.

@mandrigin were you able to make any progress on this? I'm interested in a fix for a related issue where the keyboard doesn't automatically switch back from numbers to letters on typing space.

@mandrigin
Copy link
Author

@alsun2001 sorry, was a bit busy at first and then I was on vacation. I'm back, I'll take a look at it this week. Knowing that that is iOS 9 and iOS 10 issue only helps a lot, thanks!

grabbou pushed a commit that referenced this pull request Mar 22, 2019
…est fields.

Summary:
This PR (#22546) broke single line text inputs. After inputting some text and tapping away, the text input reverts back to default text.

Revert solved the issue.

Reviewed By: cpojer

Differential Revision: D14185897

fbshipit-source-id: cc7f0f2ebfb0494062afbc628c4fe27ad27fb1c6
@mandrigin
Copy link
Author

@PeteTheHeat @alsun2001 I can't reproduce the original (CJK input) issue in 0.59.3.
I tried iOS Simulator with iOS 10.0 and 12.2.
So, I guess it is fixed?

@PeteTheHeat
Copy link
Contributor

There have been quite a few small changes to text inputs recently, so I wouldn't be surprised if it was fixed. Thanks for following up with this!!

facebook-github-bot pushed a commit that referenced this pull request Feb 10, 2022
Summary:
<!-- Explain the **motivation** for making this change. What existing problem does the pull request solve? -->

Fix #32503

Updating the attributed text in TextView/TextField while inputting Korean language will break input mechanism of the Korean alphabet. This results unexpected text input.

This PR supersedes the previous fixes: #19809, #22546

## Changelog

<!-- Help reviewers and the release process by writing your own changelog entry. For an example, see:
https://github.com/facebook/react-native/wiki/Changelog
-->

[iOS] [Fixed] - Fix a broken input for the Korean alphabet in TextInput

Pull Request resolved: #32523

Test Plan: https://user-images.githubusercontent.com/20317121/140013434-1674c391-54d6-4410-b4c1-c633697e639d.mov

Reviewed By: lunaleaps, sammy-SC

Differential Revision: D32470543

Pulled By: philIip

fbshipit-source-id: e7e34bd362fa2ab2ca579103db01ad8d1a891c35
ShikaSD pushed a commit that referenced this pull request Feb 22, 2022
Summary:
<!-- Explain the **motivation** for making this change. What existing problem does the pull request solve? -->

Fix #32503

Updating the attributed text in TextView/TextField while inputting Korean language will break input mechanism of the Korean alphabet. This results unexpected text input.

This PR supersedes the previous fixes: #19809, #22546

## Changelog

<!-- Help reviewers and the release process by writing your own changelog entry. For an example, see:
https://github.com/facebook/react-native/wiki/Changelog
-->

[iOS] [Fixed] - Fix a broken input for the Korean alphabet in TextInput

Pull Request resolved: #32523

Test Plan: https://user-images.githubusercontent.com/20317121/140013434-1674c391-54d6-4410-b4c1-c633697e639d.mov

Reviewed By: lunaleaps, sammy-SC

Differential Revision: D32470543

Pulled By: philIip

fbshipit-source-id: e7e34bd362fa2ab2ca579103db01ad8d1a891c35
ShikaSD pushed a commit that referenced this pull request Feb 24, 2022
Summary:
<!-- Explain the **motivation** for making this change. What existing problem does the pull request solve? -->

Fix #32503

Updating the attributed text in TextView/TextField while inputting Korean language will break input mechanism of the Korean alphabet. This results unexpected text input.

This PR supersedes the previous fixes: #19809, #22546

## Changelog

<!-- Help reviewers and the release process by writing your own changelog entry. For an example, see:
https://github.com/facebook/react-native/wiki/Changelog
-->

[iOS] [Fixed] - Fix a broken input for the Korean alphabet in TextInput

Pull Request resolved: #32523

Test Plan: https://user-images.githubusercontent.com/20317121/140013434-1674c391-54d6-4410-b4c1-c633697e639d.mov

Reviewed By: lunaleaps, sammy-SC

Differential Revision: D32470543

Pulled By: philIip

fbshipit-source-id: e7e34bd362fa2ab2ca579103db01ad8d1a891c35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. Component: Text Component: TextInput Related to the TextInput component. Import Started This pull request has been imported. This does not imply the PR has been approved. Platform: iOS iOS applications.
Projects
None yet
7 participants