From e46d81e2ab4558dca23f3e849e13d3e2280b49ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?F=C3=A1bio=20Henriques?= Date: Fri, 10 Feb 2023 18:06:00 +0000 Subject: [PATCH 1/2] fix: disable ios automatic extra space behavior when pasting --- patches/react-native+0.70.4-alpha.2.patch | 172 ++++++++++++++++++++++ src/components/Composer/index.ios.js | 1 + 2 files changed, 173 insertions(+) create mode 100644 patches/react-native+0.70.4-alpha.2.patch diff --git a/patches/react-native+0.70.4-alpha.2.patch b/patches/react-native+0.70.4-alpha.2.patch new file mode 100644 index 000000000000..0a602a7c0eae --- /dev/null +++ b/patches/react-native+0.70.4-alpha.2.patch @@ -0,0 +1,172 @@ +diff --git a/node_modules/react-native/Libraries/Components/TextInput/RCTTextInputViewConfig.js b/node_modules/react-native/Libraries/Components/TextInput/RCTTextInputViewConfig.js +index 52134db..6545ae0 100644 +--- a/node_modules/react-native/Libraries/Components/TextInput/RCTTextInputViewConfig.js ++++ b/node_modules/react-native/Libraries/Components/TextInput/RCTTextInputViewConfig.js +@@ -148,6 +148,7 @@ const RCTTextInputViewConfig = { + clearTextOnFocus: true, + showSoftInputOnFocus: true, + autoFocus: true, ++ smartInsertDelete: true, + ...ConditionallyIgnoredEventHandlers({ + onChange: true, + onSelectionChange: true, +diff --git a/node_modules/react-native/Libraries/Components/TextInput/TextInput.js b/node_modules/react-native/Libraries/Components/TextInput/TextInput.js +index 8fa1171..0a39140 100644 +--- a/node_modules/react-native/Libraries/Components/TextInput/TextInput.js ++++ b/node_modules/react-native/Libraries/Components/TextInput/TextInput.js +@@ -301,6 +301,14 @@ type IOSProps = $ReadOnly<{| + * @platform ios + */ + textContentType?: ?TextContentType, ++ ++ /** ++ * If `false`, the iOS system will not insert an extra space after a paste operation ++ * neither delete one or two spaces after a cut or delete operation. ++ * ++ * The default value is `true`. ++ */ ++ smartInsertDelete?: boolean | undefined; + |}>; + + type AndroidProps = $ReadOnly<{| +diff --git a/node_modules/react-native/Libraries/Text/RCTConvert+Text.h b/node_modules/react-native/Libraries/Text/RCTConvert+Text.h +index b7c411a..4425cc2 100644 +--- a/node_modules/react-native/Libraries/Text/RCTConvert+Text.h ++++ b/node_modules/react-native/Libraries/Text/RCTConvert+Text.h +@@ -16,6 +16,7 @@ NS_ASSUME_NONNULL_BEGIN + + (UITextAutocorrectionType)UITextAutocorrectionType:(nullable id)json; + + (UITextSpellCheckingType)UITextSpellCheckingType:(nullable id)json; + + (RCTTextTransform)RCTTextTransform:(nullable id)json; +++ (UITextSmartInsertDeleteType)UITextSmartInsertDeleteType:(nullable id)json; + + @end + +diff --git a/node_modules/react-native/Libraries/Text/RCTConvert+Text.m b/node_modules/react-native/Libraries/Text/RCTConvert+Text.m +index da9fb7c..5857677 100644 +--- a/node_modules/react-native/Libraries/Text/RCTConvert+Text.m ++++ b/node_modules/react-native/Libraries/Text/RCTConvert+Text.m +@@ -32,4 +32,11 @@ + (UITextSpellCheckingType)UITextSpellCheckingType:(id)json + @"lowercase": @(RCTTextTransformLowercase), + }), RCTTextTransformUndefined, integerValue) + +++ (UITextSmartInsertDeleteType)UITextSmartInsertDeleteType:(id)json ++{ ++ return json == nil ? UITextSmartInsertDeleteTypeDefault ++ : [RCTConvert BOOL:json] ? UITextSmartInsertDeleteTypeYes ++ : UITextSmartInsertDeleteTypeNo; ++} ++ + @end +diff --git a/node_modules/react-native/Libraries/Text/TextInput/RCTBaseTextInputViewManager.m b/node_modules/react-native/Libraries/Text/TextInput/RCTBaseTextInputViewManager.m +index b1ecf85..447286e 100644 +--- a/node_modules/react-native/Libraries/Text/TextInput/RCTBaseTextInputViewManager.m ++++ b/node_modules/react-native/Libraries/Text/TextInput/RCTBaseTextInputViewManager.m +@@ -48,6 +48,7 @@ @implementation RCTBaseTextInputViewManager + RCT_REMAP_VIEW_PROPERTY(clearButtonMode, backedTextInputView.clearButtonMode, UITextFieldViewMode) + RCT_REMAP_VIEW_PROPERTY(scrollEnabled, backedTextInputView.scrollEnabled, BOOL) + RCT_REMAP_VIEW_PROPERTY(secureTextEntry, backedTextInputView.secureTextEntry, BOOL) ++RCT_REMAP_VIEW_PROPERTY(smartInsertDelete, backedTextInputView.smartInsertDeleteType, UITextSmartInsertDeleteType) + RCT_EXPORT_VIEW_PROPERTY(autoFocus, BOOL) + RCT_EXPORT_VIEW_PROPERTY(blurOnSubmit, BOOL) + RCT_EXPORT_VIEW_PROPERTY(clearTextOnFocus, BOOL) +diff --git a/node_modules/react-native/React/Fabric/Mounting/ComponentViews/TextInput/RCTTextInputComponentView.mm b/node_modules/react-native/React/Fabric/Mounting/ComponentViews/TextInput/RCTTextInputComponentView.mm +index 3631fb4..9f793c5 100644 +--- a/node_modules/react-native/React/Fabric/Mounting/ComponentViews/TextInput/RCTTextInputComponentView.mm ++++ b/node_modules/react-native/React/Fabric/Mounting/ComponentViews/TextInput/RCTTextInputComponentView.mm +@@ -185,6 +185,21 @@ - (void)updateProps:(Props::Shared const &)props oldProps:(Props::Shared const & + } + } + ++ /* ++ * When updating component's props, we compare if the new value is different from the old one. ++ * If it is different, we update the native view with the new value. ++ * ++ * `RCTUITextSmartInsertDeleteTypeFromOptionalBool` is used to convert the boolean value coming ++ * from JS side to the appropriate `UITextSmartInsertDeleteType` value, that is required for ++ * this `smartInsertDeleteType` attribute. ++ */ ++ if (newTextInputProps.traits.smartInsertDelete != oldTextInputProps.traits.smartInsertDelete) { ++ if (@available(iOS 11.0, *)) { ++ _backedTextInputView.smartInsertDeleteType = ++ RCTUITextSmartInsertDeleteTypeFromOptionalBool(newTextInputProps.traits.smartInsertDelete); ++ } ++ } ++ + // Traits `blurOnSubmit`, `clearTextOnFocus`, and `selectTextOnFocus` were omitted intentially here + // because they are being checked on-demand. + +diff --git a/node_modules/react-native/React/Fabric/Mounting/ComponentViews/TextInput/RCTTextInputUtils.h b/node_modules/react-native/React/Fabric/Mounting/ComponentViews/TextInput/RCTTextInputUtils.h +index ffaac13..6f77538 100644 +--- a/node_modules/react-native/React/Fabric/Mounting/ComponentViews/TextInput/RCTTextInputUtils.h ++++ b/node_modules/react-native/React/Fabric/Mounting/ComponentViews/TextInput/RCTTextInputUtils.h +@@ -41,4 +41,7 @@ UITextContentType RCTUITextContentTypeFromString(std::string const &contentType) + API_AVAILABLE(ios(12.0)) + UITextInputPasswordRules *RCTUITextInputPasswordRulesFromString(std::string const &passwordRules); + ++API_AVAILABLE(ios(11.0)) ++UITextSmartInsertDeleteType RCTUITextSmartInsertDeleteTypeFromOptionalBool(std::optional smartInsertDelete); ++ + NS_ASSUME_NONNULL_END +diff --git a/node_modules/react-native/React/Fabric/Mounting/ComponentViews/TextInput/RCTTextInputUtils.mm b/node_modules/react-native/React/Fabric/Mounting/ComponentViews/TextInput/RCTTextInputUtils.mm +index 99f4681..41343e1 100644 +--- a/node_modules/react-native/React/Fabric/Mounting/ComponentViews/TextInput/RCTTextInputUtils.mm ++++ b/node_modules/react-native/React/Fabric/Mounting/ComponentViews/TextInput/RCTTextInputUtils.mm +@@ -44,6 +44,10 @@ void RCTCopyBackedTextInput( + toTextInput.keyboardType = fromTextInput.keyboardType; + toTextInput.textContentType = fromTextInput.textContentType; + ++ if (@available(iOS 11.0, *)) { ++ toTextInput.smartInsertDeleteType = fromTextInput.smartInsertDeleteType; ++ } ++ + if (@available(iOS 12.0, *)) { + toTextInput.passwordRules = fromTextInput.passwordRules; + } +@@ -232,3 +236,10 @@ UITextContentType RCTUITextContentTypeFromString(std::string const &contentType) + { + return [UITextInputPasswordRules passwordRulesWithDescriptor:RCTNSStringFromStringNilIfEmpty(passwordRules)]; + } ++ ++API_AVAILABLE(ios(11.0)) ++UITextSmartInsertDeleteType RCTUITextSmartInsertDeleteTypeFromOptionalBool(std::optional smartInsertDelete) ++{ ++ return smartInsertDelete.has_value() ? (*smartInsertDelete ? UITextSmartInsertDeleteTypeYes : UITextSmartInsertDeleteTypeNo) ++ : UITextSmartInsertDeleteTypeDefault; ++} +diff --git a/node_modules/react-native/ReactCommon/react/renderer/components/textinput/iostextinput/primitives.h b/node_modules/react-native/ReactCommon/react/renderer/components/textinput/iostextinput/primitives.h +index 1747a98..f9bb580 100644 +--- a/node_modules/react-native/ReactCommon/react/renderer/components/textinput/iostextinput/primitives.h ++++ b/node_modules/react-native/ReactCommon/react/renderer/components/textinput/iostextinput/primitives.h +@@ -215,6 +215,15 @@ class TextInputTraits final { + * Default value: `` (no rules). + */ + std::string passwordRules{}; ++ ++ /* ++ * If `false`, the iOS system will not insert an extra space after a paste operation ++ * neither delete one or two spaces after a cut or delete operation. ++ * iOS-only (inherently iOS-specific) ++ * Can be empty (`null` in JavaScript) which means `default`. ++ * Default value: `empty` (`null`). ++ */ ++ std::optional smartInsertDelete{}; + }; + + } // namespace react +diff --git a/node_modules/react-native/ReactCommon/react/renderer/components/textinput/iostextinput/propsConversions.h b/node_modules/react-native/ReactCommon/react/renderer/components/textinput/iostextinput/propsConversions.h +index 84c52ee..9e29840 100644 +--- a/node_modules/react-native/ReactCommon/react/renderer/components/textinput/iostextinput/propsConversions.h ++++ b/node_modules/react-native/ReactCommon/react/renderer/components/textinput/iostextinput/propsConversions.h +@@ -141,6 +141,12 @@ static TextInputTraits convertRawProp( + "passwordRules", + sourceTraits.passwordRules, + defaultTraits.passwordRules); ++ traits.smartInsertDelete = convertRawProp( ++ context, ++ rawProps, ++ "smartInsertDelete", ++ sourceTraits.smartInsertDelete, ++ defaultTraits.smartInsertDelete); + + return traits; + } diff --git a/src/components/Composer/index.ios.js b/src/components/Composer/index.ios.js index f75c331968c1..861504234451 100644 --- a/src/components/Composer/index.ios.js +++ b/src/components/Composer/index.ios.js @@ -105,6 +105,7 @@ class Composer extends React.Component { onContentSizeChange={(e) => ComposerUtils.updateNumberOfLines(this.props, e)} rejectResponderTermination={false} textAlignVertical="center" + smartInsertDelete={false} style={this.state.propStyles} /* eslint-disable-next-line react/jsx-props-no-spreading */ {...propsToPass} From 38903b020f8ecd0cbb361e2fa42c4824b26680a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?F=C3=A1bio=20Henriques?= Date: Tue, 16 May 2023 09:35:23 +0100 Subject: [PATCH 2/2] Remove RN patch --- patches/react-native+0.70.4-alpha.2.patch | 172 ---------------------- 1 file changed, 172 deletions(-) delete mode 100644 patches/react-native+0.70.4-alpha.2.patch diff --git a/patches/react-native+0.70.4-alpha.2.patch b/patches/react-native+0.70.4-alpha.2.patch deleted file mode 100644 index 0a602a7c0eae..000000000000 --- a/patches/react-native+0.70.4-alpha.2.patch +++ /dev/null @@ -1,172 +0,0 @@ -diff --git a/node_modules/react-native/Libraries/Components/TextInput/RCTTextInputViewConfig.js b/node_modules/react-native/Libraries/Components/TextInput/RCTTextInputViewConfig.js -index 52134db..6545ae0 100644 ---- a/node_modules/react-native/Libraries/Components/TextInput/RCTTextInputViewConfig.js -+++ b/node_modules/react-native/Libraries/Components/TextInput/RCTTextInputViewConfig.js -@@ -148,6 +148,7 @@ const RCTTextInputViewConfig = { - clearTextOnFocus: true, - showSoftInputOnFocus: true, - autoFocus: true, -+ smartInsertDelete: true, - ...ConditionallyIgnoredEventHandlers({ - onChange: true, - onSelectionChange: true, -diff --git a/node_modules/react-native/Libraries/Components/TextInput/TextInput.js b/node_modules/react-native/Libraries/Components/TextInput/TextInput.js -index 8fa1171..0a39140 100644 ---- a/node_modules/react-native/Libraries/Components/TextInput/TextInput.js -+++ b/node_modules/react-native/Libraries/Components/TextInput/TextInput.js -@@ -301,6 +301,14 @@ type IOSProps = $ReadOnly<{| - * @platform ios - */ - textContentType?: ?TextContentType, -+ -+ /** -+ * If `false`, the iOS system will not insert an extra space after a paste operation -+ * neither delete one or two spaces after a cut or delete operation. -+ * -+ * The default value is `true`. -+ */ -+ smartInsertDelete?: boolean | undefined; - |}>; - - type AndroidProps = $ReadOnly<{| -diff --git a/node_modules/react-native/Libraries/Text/RCTConvert+Text.h b/node_modules/react-native/Libraries/Text/RCTConvert+Text.h -index b7c411a..4425cc2 100644 ---- a/node_modules/react-native/Libraries/Text/RCTConvert+Text.h -+++ b/node_modules/react-native/Libraries/Text/RCTConvert+Text.h -@@ -16,6 +16,7 @@ NS_ASSUME_NONNULL_BEGIN - + (UITextAutocorrectionType)UITextAutocorrectionType:(nullable id)json; - + (UITextSpellCheckingType)UITextSpellCheckingType:(nullable id)json; - + (RCTTextTransform)RCTTextTransform:(nullable id)json; -++ (UITextSmartInsertDeleteType)UITextSmartInsertDeleteType:(nullable id)json; - - @end - -diff --git a/node_modules/react-native/Libraries/Text/RCTConvert+Text.m b/node_modules/react-native/Libraries/Text/RCTConvert+Text.m -index da9fb7c..5857677 100644 ---- a/node_modules/react-native/Libraries/Text/RCTConvert+Text.m -+++ b/node_modules/react-native/Libraries/Text/RCTConvert+Text.m -@@ -32,4 +32,11 @@ + (UITextSpellCheckingType)UITextSpellCheckingType:(id)json - @"lowercase": @(RCTTextTransformLowercase), - }), RCTTextTransformUndefined, integerValue) - -++ (UITextSmartInsertDeleteType)UITextSmartInsertDeleteType:(id)json -+{ -+ return json == nil ? UITextSmartInsertDeleteTypeDefault -+ : [RCTConvert BOOL:json] ? UITextSmartInsertDeleteTypeYes -+ : UITextSmartInsertDeleteTypeNo; -+} -+ - @end -diff --git a/node_modules/react-native/Libraries/Text/TextInput/RCTBaseTextInputViewManager.m b/node_modules/react-native/Libraries/Text/TextInput/RCTBaseTextInputViewManager.m -index b1ecf85..447286e 100644 ---- a/node_modules/react-native/Libraries/Text/TextInput/RCTBaseTextInputViewManager.m -+++ b/node_modules/react-native/Libraries/Text/TextInput/RCTBaseTextInputViewManager.m -@@ -48,6 +48,7 @@ @implementation RCTBaseTextInputViewManager - RCT_REMAP_VIEW_PROPERTY(clearButtonMode, backedTextInputView.clearButtonMode, UITextFieldViewMode) - RCT_REMAP_VIEW_PROPERTY(scrollEnabled, backedTextInputView.scrollEnabled, BOOL) - RCT_REMAP_VIEW_PROPERTY(secureTextEntry, backedTextInputView.secureTextEntry, BOOL) -+RCT_REMAP_VIEW_PROPERTY(smartInsertDelete, backedTextInputView.smartInsertDeleteType, UITextSmartInsertDeleteType) - RCT_EXPORT_VIEW_PROPERTY(autoFocus, BOOL) - RCT_EXPORT_VIEW_PROPERTY(blurOnSubmit, BOOL) - RCT_EXPORT_VIEW_PROPERTY(clearTextOnFocus, BOOL) -diff --git a/node_modules/react-native/React/Fabric/Mounting/ComponentViews/TextInput/RCTTextInputComponentView.mm b/node_modules/react-native/React/Fabric/Mounting/ComponentViews/TextInput/RCTTextInputComponentView.mm -index 3631fb4..9f793c5 100644 ---- a/node_modules/react-native/React/Fabric/Mounting/ComponentViews/TextInput/RCTTextInputComponentView.mm -+++ b/node_modules/react-native/React/Fabric/Mounting/ComponentViews/TextInput/RCTTextInputComponentView.mm -@@ -185,6 +185,21 @@ - (void)updateProps:(Props::Shared const &)props oldProps:(Props::Shared const & - } - } - -+ /* -+ * When updating component's props, we compare if the new value is different from the old one. -+ * If it is different, we update the native view with the new value. -+ * -+ * `RCTUITextSmartInsertDeleteTypeFromOptionalBool` is used to convert the boolean value coming -+ * from JS side to the appropriate `UITextSmartInsertDeleteType` value, that is required for -+ * this `smartInsertDeleteType` attribute. -+ */ -+ if (newTextInputProps.traits.smartInsertDelete != oldTextInputProps.traits.smartInsertDelete) { -+ if (@available(iOS 11.0, *)) { -+ _backedTextInputView.smartInsertDeleteType = -+ RCTUITextSmartInsertDeleteTypeFromOptionalBool(newTextInputProps.traits.smartInsertDelete); -+ } -+ } -+ - // Traits `blurOnSubmit`, `clearTextOnFocus`, and `selectTextOnFocus` were omitted intentially here - // because they are being checked on-demand. - -diff --git a/node_modules/react-native/React/Fabric/Mounting/ComponentViews/TextInput/RCTTextInputUtils.h b/node_modules/react-native/React/Fabric/Mounting/ComponentViews/TextInput/RCTTextInputUtils.h -index ffaac13..6f77538 100644 ---- a/node_modules/react-native/React/Fabric/Mounting/ComponentViews/TextInput/RCTTextInputUtils.h -+++ b/node_modules/react-native/React/Fabric/Mounting/ComponentViews/TextInput/RCTTextInputUtils.h -@@ -41,4 +41,7 @@ UITextContentType RCTUITextContentTypeFromString(std::string const &contentType) - API_AVAILABLE(ios(12.0)) - UITextInputPasswordRules *RCTUITextInputPasswordRulesFromString(std::string const &passwordRules); - -+API_AVAILABLE(ios(11.0)) -+UITextSmartInsertDeleteType RCTUITextSmartInsertDeleteTypeFromOptionalBool(std::optional smartInsertDelete); -+ - NS_ASSUME_NONNULL_END -diff --git a/node_modules/react-native/React/Fabric/Mounting/ComponentViews/TextInput/RCTTextInputUtils.mm b/node_modules/react-native/React/Fabric/Mounting/ComponentViews/TextInput/RCTTextInputUtils.mm -index 99f4681..41343e1 100644 ---- a/node_modules/react-native/React/Fabric/Mounting/ComponentViews/TextInput/RCTTextInputUtils.mm -+++ b/node_modules/react-native/React/Fabric/Mounting/ComponentViews/TextInput/RCTTextInputUtils.mm -@@ -44,6 +44,10 @@ void RCTCopyBackedTextInput( - toTextInput.keyboardType = fromTextInput.keyboardType; - toTextInput.textContentType = fromTextInput.textContentType; - -+ if (@available(iOS 11.0, *)) { -+ toTextInput.smartInsertDeleteType = fromTextInput.smartInsertDeleteType; -+ } -+ - if (@available(iOS 12.0, *)) { - toTextInput.passwordRules = fromTextInput.passwordRules; - } -@@ -232,3 +236,10 @@ UITextContentType RCTUITextContentTypeFromString(std::string const &contentType) - { - return [UITextInputPasswordRules passwordRulesWithDescriptor:RCTNSStringFromStringNilIfEmpty(passwordRules)]; - } -+ -+API_AVAILABLE(ios(11.0)) -+UITextSmartInsertDeleteType RCTUITextSmartInsertDeleteTypeFromOptionalBool(std::optional smartInsertDelete) -+{ -+ return smartInsertDelete.has_value() ? (*smartInsertDelete ? UITextSmartInsertDeleteTypeYes : UITextSmartInsertDeleteTypeNo) -+ : UITextSmartInsertDeleteTypeDefault; -+} -diff --git a/node_modules/react-native/ReactCommon/react/renderer/components/textinput/iostextinput/primitives.h b/node_modules/react-native/ReactCommon/react/renderer/components/textinput/iostextinput/primitives.h -index 1747a98..f9bb580 100644 ---- a/node_modules/react-native/ReactCommon/react/renderer/components/textinput/iostextinput/primitives.h -+++ b/node_modules/react-native/ReactCommon/react/renderer/components/textinput/iostextinput/primitives.h -@@ -215,6 +215,15 @@ class TextInputTraits final { - * Default value: `` (no rules). - */ - std::string passwordRules{}; -+ -+ /* -+ * If `false`, the iOS system will not insert an extra space after a paste operation -+ * neither delete one or two spaces after a cut or delete operation. -+ * iOS-only (inherently iOS-specific) -+ * Can be empty (`null` in JavaScript) which means `default`. -+ * Default value: `empty` (`null`). -+ */ -+ std::optional smartInsertDelete{}; - }; - - } // namespace react -diff --git a/node_modules/react-native/ReactCommon/react/renderer/components/textinput/iostextinput/propsConversions.h b/node_modules/react-native/ReactCommon/react/renderer/components/textinput/iostextinput/propsConversions.h -index 84c52ee..9e29840 100644 ---- a/node_modules/react-native/ReactCommon/react/renderer/components/textinput/iostextinput/propsConversions.h -+++ b/node_modules/react-native/ReactCommon/react/renderer/components/textinput/iostextinput/propsConversions.h -@@ -141,6 +141,12 @@ static TextInputTraits convertRawProp( - "passwordRules", - sourceTraits.passwordRules, - defaultTraits.passwordRules); -+ traits.smartInsertDelete = convertRawProp( -+ context, -+ rawProps, -+ "smartInsertDelete", -+ sourceTraits.smartInsertDelete, -+ defaultTraits.smartInsertDelete); - - return traits; - }