Skip to content

Conversation

@bibixx
Copy link
Contributor

@bibixx bibixx commented Jul 14, 2025

Description
When using an IME, the first character's composition gets interrupted.

Root Cause:
1. Immediate Selection Updates During Composition
When insertCompositionText events occurred, the code would:

  1. ✅ Correctly store the composition text as a pending diff with storeDiff()
  2. ❌ Immediately call scheduleAction() to update selection
  3. scheduleAction() would set actionTimeoutId = setTimeout(flush)
  4. ❌ This caused pending diffs to be flushed almost immediately

2. Selection-Triggered Flush Timeouts
During IME composition, selection changes are common as the cursor position updates. The handleUserSelect function would:

  1. Detect selection changes during composition
  2. Schedule a 200ms flush timeout with setTimeout(flush, FLUSH_DELAY)
  3. This would "auto-accept" the composition before the user could continue typing

Issue
Fixes: #5883

Example

Before After
CleanShot.2025-07-14.at.12.37.57.mp4
CleanShot.2025-07-14.at.12.36.38.mp4

Context

If your change is non-trivial, please include a description of how the new logic works, and why you decided to solve it the way you did. (This is incredibly helpful so that reviewers don't have to guess your intentions based on the code, and without it your pull request will likely not be reviewed as quickly.)

Checks

  • The new code matches the existing patterns and styles.
  • The tests pass with yarn test.
  • The linter passes with yarn lint. (Fix errors with yarn fix.)
  • The relevant examples still work. (Run examples with yarn start.)
  • You've added a changeset if changing functionality. (Add one with yarn changeset add.)

@changeset-bot
Copy link

changeset-bot bot commented Jul 14, 2025

🦋 Changeset detected

Latest commit: 758fa3b

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
slate-react Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@12joan
Copy link
Contributor

12joan commented Jul 14, 2025

Thanks for finding a solution to this one! I couldn't get to the bottom of it when I tried.

To make sure this doesn't cause any regressions, please could you go to /examples/android-tests and try out each of the test cases? Best to try it on a phone that uses composition for English (indicated by the underline while typing; recent versions of Gboard don't use it anymore).

@12joan
Copy link
Contributor

12joan commented Jul 14, 2025

Actually, could you also add a new test case to android-tests.tsx explaining how others in the future can verify that this still works?

I've got plans to introduce a suite of automated Android tests using Appium and BrowserStack, although I haven't had time to work on that yet. In the meantime, adding to the suite of manual Android tests is the best way of making sure issues like this stay fixed.

@bibixx
Copy link
Contributor Author

bibixx commented Jul 14, 2025

Thanks for finding a solution to this one! I couldn't get to the bottom of it when I tried.

To make sure this doesn't cause any regressions, please could you go to /examples/android-tests and try out each of the test cases? Best to try it on a phone that uses composition for English (indicated by the underline while typing; recent versions of Gboard don't use it anymore).

Yup verified all of those already on a physical device (OnePlus 10T 5G w/ Android 15).

Actually, could you also add a new test case to android-tests.tsx explaining how others in the future can verify that this still works?

I've got plans to introduce a suite of automated Android tests using Appium and BrowserStack, although I haven't had time to work on that yet. In the meantime, adding to the suite of manual Android tests is the best way of making sure issues like this stay fixed.

Will do tomorrow 🫡


Also one of our QAs found one more problem around this in the internal build. I haven't verified it yet though, so I need to check if it is ours of Slate's issue

@12joan
Copy link
Contributor

12joan commented Jul 20, 2025

I've got plans to introduce a suite of automated Android tests using Appium and BrowserStack

I've made some progrss with the automated Android tests, and I tried them out on the code in this PR.

For some reason, it doesn't fix the issue in the Android Studio emulator I'm using (Gboard 12.4.05.482060964, Android 14, Pixel 3a). Composition still ends after typing the first character.

In addition, it causes a regression. Before, the Slate value was updated immediately on every compositionupdate. Now, it's only updated when composition finishes.

@12joan
Copy link
Contributor

12joan commented Jul 20, 2025

Actually, it looks like this does fix it, but only when the editor is non-empty.

@12joan
Copy link
Contributor

12joan commented Jul 20, 2025

Here are the tests I'm running: https://github.com/12joan/slate-android-tests/blob/a43e787fe74ba962e7b538560afc73a8850710b0/appium/ime.spec.tsx

Before this PR, types a simple sentence and updates the Slate value during composition pass and the other two tests fail.

With the code in this PR, composes correctly at the start of a block now passes, composes correctly at the start of the editor continues to fail, and updates the Slate value during composition newly fails.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Composition interrupted in empty text nodes on Android IME

2 participants