Skip to content

Enhance cursor-ime example with cursor movement and editing#876

Open
subinium wants to merge 3 commits intovadimdemedes:masterfrom
subinium:docs/improve-ime-example
Open

Enhance cursor-ime example with cursor movement and editing#876
subinium wants to merge 3 commits intovadimdemedes:masterfrom
subinium:docs/improve-ime-example

Conversation

@subinium
Copy link
Copy Markdown

@subinium subinium commented Feb 12, 2026

Upgrade the cursor-ime example from an append-only demo into a minimal TextInput with cursor movement, middle insertion, backspace, and submit.

Changes

  • Arrow-key cursor movement (left/right) with up/down guards
  • Position-aware backspace and middle insertion
  • Enter to submit (moves line to history above)
  • stringWidth for correct CJK column offset
  • charCount via [...str].length for correct codepoint counting
  • Cursor Y accounts for submitted history lines

The previous example was append-only with no cursor movement. Replace
it with a comprehensive TextInput demonstrating middle insertion,
arrow-key navigation, backspace at cursor position, and submit with
history. Add a readme explaining why CJK input needs useCursor +
stringWidth (Hangul composition, fullwidth columns, fake-cursor issue).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Remove readme.md (no other example has one)
- Trim JSDoc block to a minimal 2-line comment
- Guard upArrow/downArrow from inserting text

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@subinium subinium changed the title docs(cursor-ime): enhance IME example with full TextInput features Enhance cursor-ime example with cursor movement and editing Feb 12, 2026
@sindresorhus
Copy link
Copy Markdown
Collaborator

// @juniqlim

Replace `before.slice(0, -1)` (UTF-16) with `splitAt` + `charCount`
to correctly handle surrogate pairs (emoji) in backspace, consistent
with the rest of the codepoint-aware logic.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@sindresorhus
Copy link
Copy Markdown
Collaborator

Found a few things:

  1. The input handler reads text and cursorIndex from the render-time closure, then computes edits from those snapshots. Input events are emitted sequentially from one readable cycle and React batches state updates, so a second key event in the same cycle can compute from stale state (for example leftArrow + character insert, or backspace after cursor movement) and apply the edit at the wrong index. The edit path should be derived from previous state via functional updates so each key event composes with the latest result.
  2. Cursor Y is computd as 1 + submitted.length, which assumes one terminal row per submitted item. That is not true after soft-wrap (long lines, wide glyphs), so visual row count diverges from item count and cursor positioning drifts occassionally after submits. Cursor row should be based on rendered row height, not history length.

@juniqlim
Copy link
Copy Markdown
Contributor

juniqlim commented Feb 21, 2026

@subinium I built something similar and both issues are already solved there, for reference:

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.

3 participants