-
Notifications
You must be signed in to change notification settings - Fork 60
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix backticks not removed when entering diacritics using option key commands on iOS #182
Conversation
@@ -47,13 +48,17 @@ - (NSAttributedString *)parseMarkdown:(nullable NSAttributedString *)input | |||
JSValue *result = [function callWithArguments:@[inputString]]; | |||
NSArray *ranges = [result toArray]; | |||
|
|||
NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc] initWithString:inputString attributes:_backedTextInputView.defaultTextAttributes]; | |||
NSMutableAttributedString *attributedString = [input mutableCopy]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I had to use mutableCopy
here because creating NSMutableAttributedString
from NSString
loses the information about diacritics context.
NSMutableDictionary<NSAttributedStringKey, id> *attributes = [_backedTextInputView.defaultTextAttributes mutableCopy]; | ||
[attributes removeObjectForKey:RCTTextAttributesTagAttributeName]; | ||
[attributedString addAttributes:attributes range:NSMakeRange(0, attributedString.length)]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Because of the above change, now the attributed string also contains previous styling so I need to apply default text attributes in order to reset it.
For some reason, restoring RCTTextAttributesTagAttributeName
attribute also breaks the diacritics context so I need to make sure it is not applied. This can be done either by removing it from the dictionary or calling [NSAttributedString removeAttribute]
later on.
This attribute is also removed by React Native itself: https://github.com/facebook/react-native/blob/f9a5b30e5a805061416123d037351e5c03860756/packages/react-native/Libraries/Text/TextInput/RCTBaseTextInputView.mm#L175-L179
// The workaround is to remove NSUnderlineStyleAttributeName attribute for whole string before iterating over ranges. | ||
[attributedString removeAttribute:NSUnderlineStyleAttributeName range:NSMakeRange(0, attributedString.length)]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This previous version of this workaround breaks the diacritics context:
Screen.Recording.2024-02-13.at.15.20.11.mov
If we remove the workaround, the diacritics context works correctly but the link underline persists:
Screen.Recording.2024-02-13.at.15.18.25.mov
If we modify the workaround so it uses removeAttribute
, it works correctly:
Screen.Recording.2024-02-13.at.15.22.56.mov
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you check on the single line input as well? I'm testing on it, and the current version of the underline workaroud doesn't work for me when multiline={false}
Reproduction steps
- set
multiline
prop ofMarkdownTextInput
tofalse
- Write any link inside text input
- press enter to submit - notice that it blurs the input
- focus the input and start typing - notice that underline is applied to whole input
Screen.Recording.2024-02-13.at.19.01.46.mov
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Okay, thanks, didn't notice this comment. I confirm this is reproducible on my end as well. Will investigate that!
Screen.Recording.2024-02-14.at.10.54.36.mov
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Updated version of workaround doesn't work for me in case of single line input. Could you look on this?
Btw. Great research 😮 - diacritics are working perfectly
@robertKozik What exactly seems to be wrong? How can I reproduce it? Looks like it's working correctly: App.tsximport * as React from 'react';
import {Button, Platform, StyleSheet, Text, View} from 'react-native';
import {MarkdownTextInput} from '@expensify/react-native-live-markdown';
const DEFAULT_TEXT = '';
function isWeb() {
return Platform.OS === 'web';
}
function getPlatform() {
if (isWeb()) {
return 'web';
}
// @ts-expect-error it works
return Platform.constants.systemName || Platform.constants.Brand;
}
function getPlatformVersion() {
return Platform.Version;
}
function getBundle() {
return __DEV__ ? 'dev' : 'production';
}
function getRuntime() {
if ('HermesInternal' in global) {
const version =
// @ts-expect-error this is fine
// eslint-disable-next-line es/no-optional-chaining
global.HermesInternal?.getRuntimeProperties?.()['OSS Release Version'];
return `Hermes (${version})`;
}
if ('_v8runtime' in global) {
// @ts-expect-error this is fine
// eslint-disable-next-line no-underscore-dangle
const version = global._v8runtime().version;
return `V8 (${version})`;
}
return 'JSC';
}
function getArchitecture() {
return 'nativeFabricUIManager' in global ? 'Fabric' : 'Paper';
}
function getReactNativeVersion() {
const {major, minor, patch} = Platform.constants.reactNativeVersion;
return `${major}.${minor}.${patch}`;
}
function getRandomColor() {
return `#${Math.floor(Math.random() * 16777215)
.toString(16)
.padStart(6, '0')}`;
}
export default function App() {
const [value, setValue] = React.useState(DEFAULT_TEXT);
const [markdownStyle, setMarkdownStyle] = React.useState({});
// TODO: use MarkdownTextInput ref instead of TextInput ref
const ref = React.useRef<TextInput>(null);
return (
<View style={styles.container}>
<View style={styles.platform}>
<Text>
Platform: {getPlatform()} {getPlatformVersion()}
</Text>
<Text>Bundle: {getBundle()}</Text>
{!isWeb() && (
<>
<Text>Architecture: {getArchitecture()}</Text>
<Text>RN version: {getReactNativeVersion()}</Text>
<Text>RN runtime: {getRuntime()}</Text>
</>
)}
</View>
<Text>MarkdownTextInput singleline</Text>
<MarkdownTextInput
autoCapitalize="none"
value={value}
onChangeText={setValue}
style={styles.input}
/>
<Text>MarkdownTextInput multiline</Text>
<MarkdownTextInput
multiline
autoCapitalize="none"
value={value}
onChangeText={setValue}
style={styles.input}
ref={ref}
markdownStyle={markdownStyle}
/>
<Text style={styles.text}>{JSON.stringify(value)}</Text>
<Button
title="Focus"
onPress={() => {
if (!ref.current) {
return;
}
ref.current.focus();
}}
/>
<Button
title="Blur"
onPress={() => {
if (!ref.current) {
return;
}
ref.current.blur();
}}
/>
<Button
title="Reset"
onPress={() => {
setValue(DEFAULT_TEXT);
setMarkdownStyle({});
}}
/>
<Button
title="Clear"
onPress={() => setValue('')}
/>
<Button
title="Change style"
onPress={() =>
setMarkdownStyle({
link: {
color: getRandomColor(),
},
})
}
/>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
marginTop: 60,
},
platform: {
alignItems: 'center',
marginBottom: 20,
},
input: {
fontSize: 20,
width: 300,
padding: 5,
borderColor: 'gray',
borderWidth: 1,
textAlignVertical: 'top',
},
text: {
fontFamily: 'Courier New',
marginTop: 10,
height: 100,
},
}); Screen.Recording.2024-02-13.at.23.49.23.mov |
After typing the link inside single line, press enter to trigger blur event. I've prepared repoduction steps here. But if it's not reproductible we can call it a day as It can be something specific only on my end |
On f755217 diacritics are still not working properly inside bold: Screen.Recording.2024-02-23.at.10.41.55.movScreen.Recording.2024-02-23.at.10.43.36.mov |
Closing in favor of #520. |
Details
This PR fixes incorrect behavior of
MarkdownTextInput
component when entering diacritics using option+` mode and aligns the behaviour with RN's built-inTextInput
component.before.mov
after.mov
Related Issues
Fixes #181.
Manual Tests
Linked PRs