Skip to content

fix: drop a controlled selection rendered before the latest edits - #58

Merged
ronickg merged 1 commit into
mainfrom
fix/stale-selection
Sep 29, 2026
Merged

ronickg merged 1 commit into
mainfrom
fix/stale-selection

Conversation

@ronickg

@ronickg ronickg commented Sep 29, 2026

Copy link
Copy Markdown
Owner

Why

In Uno's manual testing on the Galaxy A22, the code field typed 123456 as 156234, and 12345 as 14253, whenever the digits came faster than JS could render.

The code field is Uno's SegmentedInput: a hidden NitroInput with a controlled value and a controlled selection that keeps the caret where the boxes say it is.

The text handshake (mostRecentEventCount) already holds back a value rendered before JS saw the latest edits, but the selection in that same render was still applied. So a caret computed for "1" landed in a field that already held "1234", and the next digits went in behind the first.

What

A controlled selection is now dropped under the same condition as text: JS's count is behind the native edit count. React Native's TextInput does the same (maybeSetSelection checks the event count).

  • Uncontrolled fields send a count of 0 and are applied as before.
  • A selection rendered after JS has caught up still applies.
  • setSelection() is unaffected.

Android (flushSelectionIfNeeded) and iOS (applySelectionIfNeeded), with a CHANGELOG entry under ## 0.3.6.

Tests

  • Galaxy A22, Uno's dev OTP screen with the patched library, digits sent in one burst with adb shell input text:
    • before: 12345 → 14253, 123456 → 156234;
    • after: 12345 four times out of four, and 123456.
  • bun run test: 171/171.
  • bun run typecheck
  • bun run test:harness:ios: 120/120.
  • Android library compiles (:react-native-nitro-input:assembleDebug).
  • No automated test: the Harness can't type faster than JS renders.

🤖 Generated with Claude Code

A selection prop rendered before JS saw the latest native edits was still
applied, while the text prop in the same render was already held back by the
mostRecentEventCount handshake. Typed faster than JS renders, a caret computed
for '1' landed in a field showing '1234' and the next digits went in behind the
first: Uno's code field took '123456' as '156234' on a Galaxy A22. The selection
now uses the same guard, as React Native's TextInput does.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@ronickg
ronickg merged commit 46d6a86 into main Sep 29, 2026
6 checks passed
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.

1 participant