Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions packages/react-native-nitro-input/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,15 @@
# Changelog

## 0.3.6

- **A controlled `selection` rendered before the latest keystrokes is
dropped**, as `value` already was and as React Native's `TextInput` does.
Typed faster than JS renders (a slow Android phone, a busy JS thread), a
caret computed for an earlier text landed in a field that already had more
in it, and the next characters went in behind the first ones: a code field
driven by `selection` took "123456" as "156234". Uncontrolled fields are
unchanged.

## 0.3.5

- **`focusedValue`**: pass a shared value (Reanimated's `useSharedValue(false)`)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -532,12 +532,18 @@ class HybridNitroInputView(private val context: ThemedReactContext) : HybridNitr
}

/// A controlled `selection`; -1 on either end means "leave the caret alone".
/// Like `text`, dropped when it was rendered before JS saw the latest native
/// edits (React Native's `TextInput` does the same): typed faster than JS
/// renders, a caret computed for "1" landed in a field already showing
/// "1234", and the next digits went in behind the first one. An uncontrolled
/// field sends a count of 0 and is applied as before.
private fun flushSelectionIfNeeded() {
if (!selectionDirty) return
selectionDirty = false
val start = clampInt(selectionStart, -1, Int.MAX_VALUE, -1)
val end = clampInt(selectionEnd, -1, Int.MAX_VALUE, -1)
if (start < 0 || end < 0) return
if (mostRecentEventCount > 0 && mostRecentEventCount < eventCount) return
inputView.setSelection(start, end)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -434,13 +434,21 @@ final class HybridNitroInputView: HybridNitroInputViewSpec, RecyclableView {
}

/// A controlled `selection`: `-1` on either end means "leave the caret alone",
/// which is what an uncontrolled field sends on every render.
/// which is what an uncontrolled field sends on every render. Like `text`,
/// dropped when it was rendered before JS saw the latest native edits (React
/// Native's `TextInput` does the same): typed faster than JS renders, a caret
/// computed for "1" landed in a field already showing "1234". An
/// uncontrolled field sends a count of 0 and is applied as before.
private func applySelectionIfNeeded() {
guard selectionDirty else { return }
selectionDirty = false
let start = Self.clampInt(selectionStart, -1, Int(Int32.max), fallback: -1)
let end = Self.clampInt(selectionEnd, -1, Int(Int32.max), fallback: -1)
guard start >= 0, end >= 0 else { return }
snapshotLock.lock()
let nativeCount = snapshot.eventCount
snapshotLock.unlock()
if mostRecentEventCount.isFinite, mostRecentEventCount > 0, Int(mostRecentEventCount) < nativeCount { return }
inputView.setSelection(start: start, end: end)
}

Expand Down
Loading