diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 4b81ca2408c33d..ac435cf2839611 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -1,5 +1,10 @@ + + +# Upstream PR Link + + ## Summary diff --git a/Libraries/Components/TextInput/RCTTextInputViewConfig.js b/Libraries/Components/TextInput/RCTTextInputViewConfig.js index 68ee77143d1b2f..f193fe74707fed 100644 --- a/Libraries/Components/TextInput/RCTTextInputViewConfig.js +++ b/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/Libraries/Components/TextInput/TextInput.js b/Libraries/Components/TextInput/TextInput.js index 59cb7f8e8bdc44..1bf1b7f3a8aca4 100644 --- a/Libraries/Components/TextInput/TextInput.js +++ b/Libraries/Components/TextInput/TextInput.js @@ -322,6 +322,16 @@ 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`. + * + * @platform ios + */ + smartInsertDelete?: ?boolean, |}>; type AndroidProps = $ReadOnly<{| diff --git a/Libraries/NativeComponent/BaseViewConfig.android.js b/Libraries/NativeComponent/BaseViewConfig.android.js index c843ca280395b0..49df96490c1e56 100644 --- a/Libraries/NativeComponent/BaseViewConfig.android.js +++ b/Libraries/NativeComponent/BaseViewConfig.android.js @@ -184,6 +184,7 @@ const validAttributesForNonEventProps = { translateX: true, translateY: true, accessibilityLiveRegion: true, + needsOffscreenAlphaCompositing: true, // @ReactProps from LayoutShadowNode width: true, diff --git a/Libraries/Text/RCTConvert+Text.h b/Libraries/Text/RCTConvert+Text.h index b7c411a2a69366..4425cc2ccfa8e3 100644 --- a/Libraries/Text/RCTConvert+Text.h +++ b/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/Libraries/Text/RCTConvert+Text.m b/Libraries/Text/RCTConvert+Text.m index da9fb7cb839f43..585767754226a2 100644 --- a/Libraries/Text/RCTConvert+Text.m +++ b/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/Libraries/Text/TextInput/RCTBaseTextInputViewManager.m b/Libraries/Text/TextInput/RCTBaseTextInputViewManager.m index fc59b088fe670c..8299af6b1a6fb3 100644 --- a/Libraries/Text/TextInput/RCTBaseTextInputViewManager.m +++ b/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(submitBehavior, NSString) RCT_EXPORT_VIEW_PROPERTY(clearTextOnFocus, BOOL) diff --git a/README.md b/README.md index 405f9203e1eed9..4c5db9cc1f5890 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,19 @@ +# Expensify Release + +To release this fork to npm there are a couple manual steps needed. + +If updating the base react-native version of the fork: + +1. Update the `version` variable on line 15 in `sdks/hermes-engine/hermes-engine.podspec` with the version of react-native the fork is based on. For example `version = '0.69.3'`. +2. Download hermesc from the version of react-native the fork is based on. This can be done by opening the url `https://registry.npmjs.com/react-native/-/react-native-.tgz`. For example `https://registry.npmjs.com/react-native/-/react-native-0.69.3.tgz`. Then copy `sdks/hermesc` to the same directory inside your react-native repository. +3. Commit the updated files. + +Build and publish the fork: + +1. Clean previous build if there is one in `android` folder with `rm -rf android`. +2. Run `node scripts/set-rn-version.js --to-version ` where version is the version of the **fork** that is being published, note that this might be different that the version the fork is based on we used previously. For example `node scripts/set-rn-version.js --to-version 0.69.4`. +3. Run `CIRCLE_TAG= node ./scripts/publish-npm.js` where version is the same as the one in the previous step. For example `CIRCLE_TAG=0.69.4 node ./scripts/publish-npm.js`. +

React Native diff --git a/React/Fabric/Mounting/ComponentViews/TextInput/RCTTextInputComponentView.mm b/React/Fabric/Mounting/ComponentViews/TextInput/RCTTextInputComponentView.mm index c7c0f1d1a7937b..cc5915309d3266 100644 --- a/React/Fabric/Mounting/ComponentViews/TextInput/RCTTextInputComponentView.mm +++ b/React/Fabric/Mounting/ComponentViews/TextInput/RCTTextInputComponentView.mm @@ -185,6 +185,13 @@ - (void)updateProps:(Props::Shared const &)props oldProps:(Props::Shared const & } } + 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/React/Fabric/Mounting/ComponentViews/TextInput/RCTTextInputUtils.h b/React/Fabric/Mounting/ComponentViews/TextInput/RCTTextInputUtils.h index ffaac133609248..6f775385a5a312 100644 --- a/React/Fabric/Mounting/ComponentViews/TextInput/RCTTextInputUtils.h +++ b/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/React/Fabric/Mounting/ComponentViews/TextInput/RCTTextInputUtils.mm b/React/Fabric/Mounting/ComponentViews/TextInput/RCTTextInputUtils.mm index 99f46819af9d09..41343e1c75db22 100644 --- a/React/Fabric/Mounting/ComponentViews/TextInput/RCTTextInputUtils.mm +++ b/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/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactScrollViewManager.java b/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactScrollViewManager.java index 933455e8056ac6..475f5dd6422c61 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactScrollViewManager.java +++ b/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactScrollViewManager.java @@ -375,4 +375,15 @@ public void setPointerEvents(ReactScrollView view, @Nullable String pointerEvent public void setScrollEventThrottle(ReactScrollView view, int scrollEventThrottle) { view.setScrollEventThrottle(scrollEventThrottle); } + + @ReactProp(name = "verticalScrollbarPosition") + public void setVerticalScrollbarPosition(ReactScrollView view, String position) { + if ("right".equals(position)) { + view.setVerticalScrollbarPosition(View.SCROLLBAR_POSITION_RIGHT); + } else if ("left".equals(position)) { + view.setVerticalScrollbarPosition(View.SCROLLBAR_POSITION_LEFT); + } else { + view.setVerticalScrollbarPosition(View.SCROLLBAR_POSITION_DEFAULT); + } + } } diff --git a/ReactCommon/react/renderer/components/textinput/iostextinput/primitives.h b/ReactCommon/react/renderer/components/textinput/iostextinput/primitives.h index bbb56d26d9a418..bfcf0f45127e54 100644 --- a/ReactCommon/react/renderer/components/textinput/iostextinput/primitives.h +++ b/ReactCommon/react/renderer/components/textinput/iostextinput/primitives.h @@ -223,6 +223,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/ReactCommon/react/renderer/components/textinput/iostextinput/propsConversions.h b/ReactCommon/react/renderer/components/textinput/iostextinput/propsConversions.h index 15dc0004596da0..fc03b469997f26 100644 --- a/ReactCommon/react/renderer/components/textinput/iostextinput/propsConversions.h +++ b/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/packages/rn-tester/js/examples/TextInput/TextInputExample.ios.js b/packages/rn-tester/js/examples/TextInput/TextInputExample.ios.js index b3940a1f8332d5..bfc2bb0a84d257 100644 --- a/packages/rn-tester/js/examples/TextInput/TextInputExample.ios.js +++ b/packages/rn-tester/js/examples/TextInput/TextInputExample.ios.js @@ -847,4 +847,23 @@ exports.examples = ([ ); }, }, + { + title: 'iOS autoformatting behaviors', + render: function (): React.Node { + return ( + + + + + + + + + ); + }, + }, ]: Array);