fix(ios): clear a long text value wherever the caret lands

Merged
KR
2d ago
+193-30

Summary

On iOS, fill over a value longer than ~112 characters left part of it behind, so new text was appended (#3851). One delete burst is capped at 120, and the caret edge-tap lands mid-text in a field too narrow for its value.

After the tap, the clear now selects all and deletes through clearUntilEmpty, the synthesized route's loop renamed (up to 4 passes, since a fresh React Native process drops its first select-alls). Only readable values take this path, because a read proves the field emptied; masked values keep the old clear. Leftover text goes to delete bursts that re-read after each burst, for at most length/120 + 2 rounds. The clear posts and reads through the caller's TextEntryReader, so resolveTextEntryInput decides which input it may reach. tvOS and macOS get the re-reading bursts but not select-all.

Fixes #3851

Validation

At 9797ef6d0 vs main 6ea9f8173, iOS 26.5 simulator, test app Form, a fresh app process per run: fill 501, fill "", fill 500.

FieldMain: after clear / fill 500Head
field-name430 / 1336, clear exit 10 / 500
field-notes457 / 1376, clear exit 10 / 500

Every head clear logged outcome=cleared (2 passes on the first clear per process, then 1).

  • All 104 text-entry XCTests pass. The long-value tests fail with the select-all block disabled.
  • Short replacement clear: ~1.09 s → ~1.24 s; the first per process ~2.0 s.
  • check:affected --run --head 9797ef6d0 passed (exactCommit=true).

Risks:

  • Not run on a physical device, tvOS, or macOS.
  • A readable field that ignores ⌘A costs ~3 s.
  • Long masked values are still partly left, as on main.

Written with Claude Code (Opus 5.5).