`onSelectionChange` event called twice with different payload on iOS for multiline
tomekzaw opened this issue · 1 comments
Reported by @perunt at https://expensify.slack.com/archives/C01GTK53T8Q/p1707846163324679
Reproducible on 5375a10 + iOS + multiline (Android works correctly, singleline works correctly)
Screen.Recording.2024-02-14.at.14.54.10.mov
App.tsx
import * as React from 'react';
import {StyleSheet, View} from 'react-native';
import {MarkdownTextInput} from '@expensify/react-native-live-markdown';
export default function App() {
const [value, setValue] = React.useState('');
return (
<View style={styles.container}>
<MarkdownTextInput
multiline
autoCapitalize="none"
value={value}
onChangeText={setValue}
style={styles.input}
onSelectionChange={(e) => console.log(e.nativeEvent)}
/>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
marginTop: 60,
},
input: {
fontSize: 20,
width: 300,
padding: 5,
borderColor: 'gray',
borderWidth: 1,
textAlignVertical: 'top',
},
});
Root cause analysis
onSelectionChange
events are emitted in [RCTBaseTextInputView textInputDidChangeSelection]
by calling _onSelectionChange
function.
When typing at the end of the text input, it works correctly (only single event is emitted).
When typing in the middle of the contents, two events are emitted.
The first event is emitted as a result of setAttributedText:
call inside [RCTBaseTextInputView(Markdown) markdown_updateLocalData]
:
However, the payload is incorrect since the selection is automatically set to the end of the current text:
The second event is emitted as a result of calling setSelectedTextRange:
to restore the original cursor position:
It has a correct payload:
The solution would be to somehow prevent emitting the first event.