lexical icon indicating copy to clipboard operation
lexical copied to clipboard

Bug: Korean consonant disappears when succeeded by a number or special character in Chrome

Open hyunjaesung opened this issue 1 year ago • 7 comments

I am currently using Lexical.js as the input system for our project. We have discovered an issue that occurs in the Chrome browser on desktop environments. When a user types a Korean consonant followed by a number or a special character, the consonant disappears, leaving only the number or special character. This behavior differs from a standard browser textarea, where the consonant remains and the number or special character is inserted alongside it.

As a temporary workaround, we have implemented a solution in our project where we create a space before receiving input to avoid this issue. We have identified that this problem arises due to the different handling of the compositionEnd event between Chrome and Safari. In Safari, the compositionEnd event does not trigger when a Korean consonant is followed by a number or a special character, whereas in Chrome, the compositionEnd event is fired in this scenario.

Our investigation has led us to believe that the issue occurs when the compositionEnd event is triggered in Chrome, causing $setCompositionKey(null) to be called within Lexical.js. Additionally, the e.preventDefault in the onBeforeInput event seems to contribute to this problem.

Thank you for your attention to this matter.

Lexical version: 0.13.1 later

Steps To Reproduce

  1. type Korean consonant
  2. type number or special character

The current behavior

Apr-12-2024 11-00-30

The expected behavior

Apr-12-2024 11-01-44

hyunjaesung avatar Apr 12 '24 02:04 hyunjaesung

Hi !

The way I see it,

In Safari, the compositionEnd event does not trigger when a Korean consonant is followed by a number or a special character, whereas in Chrome, the compositionEnd event is fired in this scenario.

In both browsers, the following events occurs during composition:

  • insertCompositionText: when inputting during composing
  • compositionEnd: when the composition ends

However, in Safari, there are additional events that occur before compositionEnd:

  • deleteCompositionText: removes the composing character
  • insertFromComposition: inserts the composed character at the original composition start position
  • Just FYI, these 2 are eliminated from W3C Input Events Level 2 (related PR: https://github.com/w3c/input-events/pull/122)

This is why the key of the textNode is updated here:

https://github.com/facebook/lexical/assets/40269597/933ed2aa-7497-474b-8121-0fd3c03e129f

  • deletion and insertion occur at the collapsed position
  • the composing character is only textContent

It ends up deleting the textNode and creates a new one with , then adds starting new composition cycle.

In Safari, when numbers or special characters follow, leading to the end of composition, it closes composition directly. The character that ends composition comes as separate input from the composition (keyCode is not 229) with insertText event.

In Chrome, the character leading to the end of composition is input as the last input of the composition (keyCode 229). compositionEnd comes after this.

The issue arises in a certain condition where the IME discards the character being composed, which should have been followed by the character ending the composition (such as numbers or special characters, ...).

For instance: => input 1 => 가1 should have been input as the composed result, then composition to be ended. The issue is => input 1 => 1 ( disappeared) situation.

Our investigation has led us to believe that the issue occurs when the compositionEnd event is triggered in Chrome, causing $setCompositionKey(null) to be called within Lexical.js.

I think you might guess $setCompositoniKey(null) makes the IME discard that here. However, $setCompositoniKey(null) is fired after 1 is input instead of 가1 already. IMO, the issue is not in incorrectly clearing Lexical's composition data but in Chrome IME's composing stack (?) clearing being triggered unexpectedly.

I suspect there might be a trigger during beginUpdate or commitPendingUpdates ...though I couldn't identify what it is.

Additionally, the e.preventDefault in the onBeforeInput event seems to contribute to this problem.

If you have a snippet of a valid workaround, would you mind sharing it?

The narrower condition to reproduce this:

  • It happens at the offset 0
  • After BACKSPACE or selecting a range

It works correctly after clicking the editor or on the inputs following a new line break on ENTER. Plus, it can happen with either a consonant or a combined alphabet.

https://github.com/facebook/lexical/assets/40269597/490ed328-259b-4829-b695-a53a82c442eb

2wheeh avatar Apr 13 '24 01:04 2wheeh

@2wheeh

Thank you for your response. It seems that the solution I had found earlier might not have worked properly.

I noticed that the related code has also been significantly modified in the meantime.

Based on the insights you provided, I will continue to search for a solution and keep updating my approach.

hyunjaesung avatar Apr 15 '24 02:04 hyunjaesung

Facebook editor has the same problem. @hyunjaesung Did you find the solution? I use Edge in Ubuntu(mantic).

appkery avatar Jun 25 '24 21:06 appkery

Facebook editor has the same problem. @hyunjaesung Did you find the solution? I use Edge in Ubuntu(mantic).

Sorry, I still can't find that, I have just added blank block in front of textNode for avoiding that situation now

hyunjaesung avatar Jun 28 '24 04:06 hyunjaesung

Thanks for reporting the issue, could you help a bit with steps to repro as I was trying to do it in Chrome and it seems to work fine (although I likely used wrong keyboard layout or sequence).

So my setup "2-Set Korean" as input source and typing "ㅇ1" ("D" key in English layout) followed by "1" seem to keep both:

https://github.com/facebook/lexical/assets/132642/c4a100a1-c9c0-45d6-ac37-bea1af1120cb

fantactuka avatar Jul 01 '24 17:07 fantactuka

Thank you for your response. If you write more than 2~3 letters in Korean without having to mix numbers, it will be automatically erased. I wonder if the editor has the function of erasing the first blank when saving and recognizes Korean as a blank. I'm using Edge in Ubuntu(mantic). Facebook editor has the same problem.

스크린캐스트 2024-07-02 05-17-21.webm

appkery avatar Jul 01 '24 20:07 appkery

@fantactuka @appkery

The narrower condition to reproduce this:

  • It happens at the offset 0
  • After BACKSPACE or selecting a range

It works correctly after clicking the editor or on the inputs following a new line break on ENTER. Plus, it can happen with either a consonant or a combined alphabet.

I described some more details: https://github.com/facebook/lexical/issues/5877#issuecomment-2052872849

In certain situations, IME somehow clears its stack(?) when it ends composition by inputting number or special character:

  • + 1 => 가1 should have been input as the composed result, then composition to be ended.
  • But in the problematic conditions, is cleared and just 1 is input.

2wheeh avatar Jul 02 '24 02:07 2wheeh