Environment
- Package: react-native-enriched-html@1.0.0 (also reproduces on the previous
react-native-enriched@0.6.1 and 0.8.1; our app is currently pinned to react-native-enriched@0.6.1 because 1.0.0 introduced separate regressions we haven't finished isolating yet)
- Platform: iOS (physical iPhone, iOS 17+)
- React Native version: 0.85
- Language input: Japanese IME (expected to reproduce on Chinese / Korean IMEs)
Reproduction Steps
- Open an EnrichedTextInput (new / empty, or an existing document — both reproduce).
- Focus the editor. Cursor is at the beginning of the first paragraph (i.e. right after the
<p> opening tag in the canonical model).
- Start typing a Japanese IME character (a character with the composition underline still shown, i.e.
markedText state — for example, type「あ」).
- Press Backspace while the character is still unconfirmed (underlined).
Expected
The unconfirmed character is deleted, mirroring the standard iOS UITextView behavior in Notes.app / Safari / plain TextInput.
Actual
The character is not deleted. Repeatedly pressing Backspace has no effect. Committing the character first (e.g. tapping the confirm button), then pressing Backspace, works normally.
Additionally: If the same operation is performed not at the very beginning of a paragraph (e.g. after typing and confirming「a」then starting a new IME composition), Backspace deletes the unconfirmed character correctly. The bug is specific to the paragraph-start position.
Analysis
-textView:shouldChangeTextInRange:replacementText: is not called by UIKit while markedTextRange is non-nil (this is documented iOS behavior).
handleKeyPressInRange: and thus onKeyPress in this library are wired through shouldChangeTextInRange:, so they cannot observe the Backspace either.
- I suspect the ZWS-based paragraph tracking (
ZeroWidthSpaceUtils handleBackspaceInRange:) plus the composition state combine to leave the deletion in a no-op state when the caret is right after the paragraph's ZWS / <p> open.
Suggested Direction
Overriding -[UITextView deleteBackward] (or wrapping the internal UITextView with a subclass) in EnrichedTextInputView.mm could give a path to intercept the composition-time Backspace at the paragraph boundary and route it through the paragraph handling code even when markedTextRange != nil.
Happy to test any nightly build or patch. Thanks for the excellent library!
Environment
react-native-enriched@0.6.1and0.8.1; our app is currently pinned toreact-native-enriched@0.6.1because 1.0.0 introduced separate regressions we haven't finished isolating yet)Reproduction Steps
<p>opening tag in the canonical model).markedTextstate — for example, type「あ」).Expected
The unconfirmed character is deleted, mirroring the standard iOS
UITextViewbehavior inNotes.app/Safari/ plainTextInput.Actual
The character is not deleted. Repeatedly pressing Backspace has no effect. Committing the character first (e.g. tapping the confirm button), then pressing Backspace, works normally.
Additionally: If the same operation is performed not at the very beginning of a paragraph (e.g. after typing and confirming「a」then starting a new IME composition), Backspace deletes the unconfirmed character correctly. The bug is specific to the paragraph-start position.
Analysis
-textView:shouldChangeTextInRange:replacementText:is not called by UIKit whilemarkedTextRangeis non-nil (this is documented iOS behavior).handleKeyPressInRange:and thusonKeyPressin this library are wired throughshouldChangeTextInRange:, so they cannot observe the Backspace either.ZeroWidthSpaceUtils handleBackspaceInRange:) plus the composition state combine to leave the deletion in a no-op state when the caret is right after the paragraph's ZWS /<p>open.Suggested Direction
Overriding
-[UITextView deleteBackward](or wrapping the internalUITextViewwith a subclass) inEnrichedTextInputView.mmcould give a path to intercept the composition-time Backspace at the paragraph boundary and route it through the paragraph handling code even whenmarkedTextRange != nil.Happy to test any nightly build or patch. Thanks for the excellent library!