diff --git a/.circleci/config.yml b/.circleci/config.yml index 10deb3e54c19ed..bc995158bbbbf4 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -47,10 +47,10 @@ references: checkout_cache_key: &checkout_cache_key v1-checkout gems_cache_key: &gems_cache_key v1-gems-{{ checksum "Gemfile.lock" }} gradle_cache_key: &gradle_cache_key v1-gradle-{{ checksum "gradle/wrapper/gradle-wrapper.properties" }}-{{ checksum "ReactAndroid/gradle.properties" }} - hermes_cache_key: &hermes_cache_key v2-hermes-{{ .Environment.CIRCLE_JOB }}-{{ checksum "/tmp/hermes/hermesversion" }} - hermes_windows_cache_key: &hermes_windows_cache_key v2-hermes-{{ .Environment.CIRCLE_JOB }}-{{ checksum "tmp/hermes/hermesversion" }} - hermes_tarball_cache_key: &hermes_tarball_cache_key v2-hermes-tarball-{{ checksum "/tmp/hermes/hermesversion" }} - pods_cache_key: &pods_cache_key v7-pods-{{ .Environment.CIRCLE_JOB }}-{{ checksum "packages/rn-tester/Podfile.lock.bak" }}-{{ checksum "packages/rn-tester/Podfile" }} + hermes_cache_key: &hermes_cache_key v3-hermes-{{ .Environment.CIRCLE_JOB }}-{{ checksum "/tmp/hermes/hermesversion" }} + hermes_windows_cache_key: &hermes_windows_cache_key v3-hermes-{{ .Environment.CIRCLE_JOB }}-{{ checksum "tmp/hermes/hermesversion" }} + hermes_tarball_cache_key: &hermes_tarball_cache_key v3-hermes-tarball-{{ checksum "/tmp/hermes/hermesversion" }} + pods_cache_key: &pods_cache_key v8-pods-{{ .Environment.CIRCLE_JOB }}-{{ checksum "packages/rn-tester/Podfile.lock.bak" }}-{{ checksum "packages/rn-tester/Podfile" }} windows_yarn_cache_key: &windows_yarn_cache_key v1-win-yarn-cache-{{ arch }}-{{ checksum "yarn.lock" }} yarn_cache_key: &yarn_cache_key v5-yarn-cache-{{ .Environment.CIRCLE_JOB }} diff --git a/.flowconfig b/.flowconfig index f8da23113b8cb9..1c5251aa55048e 100644 --- a/.flowconfig +++ b/.flowconfig @@ -74,4 +74,4 @@ untyped-import untyped-type-import [version] -^0.185.0 +^0.185.1 diff --git a/.flowconfig.android b/.flowconfig.android index 04233ebab2727c..96e4b59c23a729 100644 --- a/.flowconfig.android +++ b/.flowconfig.android @@ -74,4 +74,4 @@ untyped-import untyped-type-import [version] -^0.185.0 +^0.185.1 diff --git a/Libraries/Components/TextInput/TextInput.js b/Libraries/Components/TextInput/TextInput.js index 8e3296f5d2cf20..3f9f196db5dec2 100644 --- a/Libraries/Components/TextInput/TextInput.js +++ b/Libraries/Components/TextInput/TextInput.js @@ -709,6 +709,13 @@ export type Props = $ReadOnly<{| */ placeholderTextColor?: ?ColorValue, + /** `readOnly` works like the `readonly` attribute in HTML. + * If `true`, text is not editable. The default value is `false`. + * See https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/readonly + * for more details. + */ + readOnly?: ?boolean, + /** * Determines how the return key should look. On Android you can also use * `returnKeyLabel`. @@ -1381,6 +1388,8 @@ const ExportedForwardRef: React.AbstractComponent< allowFontScaling = true, rejectResponderTermination = true, underlineColorAndroid = 'transparent', + readOnly, + editable, ...restProps }, forwardedRef: ReactRefSetter< @@ -1392,6 +1401,7 @@ const ExportedForwardRef: React.AbstractComponent< allowFontScaling={allowFontScaling} rejectResponderTermination={rejectResponderTermination} underlineColorAndroid={underlineColorAndroid} + editable={readOnly !== undefined ? !readOnly : editable} {...restProps} forwardedRef={forwardedRef} /> diff --git a/Libraries/Components/View/View.js b/Libraries/Components/View/View.js index 0379a7ce912f97..7822e8184f214b 100644 --- a/Libraries/Components/View/View.js +++ b/Libraries/Components/View/View.js @@ -26,13 +26,19 @@ export type Props = ViewProps; const View: React.AbstractComponent< ViewProps, React.ElementRef, -> = React.forwardRef((props: ViewProps, forwardedRef) => { - return ( - - - - ); -}); +> = React.forwardRef( + ({tabIndex, focusable, ...otherProps}: ViewProps, forwardedRef) => { + return ( + + + + ); + }, +); View.displayName = 'View'; diff --git a/Libraries/Components/View/ViewPropTypes.js b/Libraries/Components/View/ViewPropTypes.js index 24c0afcaee8af2..fa40f9ec40fd69 100644 --- a/Libraries/Components/View/ViewPropTypes.js +++ b/Libraries/Components/View/ViewPropTypes.js @@ -352,6 +352,19 @@ type AndroidViewProps = $ReadOnly<{| */ focusable?: boolean, + /** + * Indicates whether this `View` should be focusable with a non-touch input device, eg. receive focus with a hardware keyboard. + * See https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/tabindex + * for more details. + * + * Supports the following values: + * - -1 (View is focusable) + * - 0 (View is not focusable) + * + * @platform android + */ + tabIndex?: 0 | -1, + /** * The action to perform when this `View` is clicked on by a non-touch click, eg. enter key on a hardware keyboard. * diff --git a/React/Fabric/RCTSurfaceTouchHandler.mm b/React/Fabric/RCTSurfaceTouchHandler.mm index 89d9f8c77df2a7..dc9995dcaaa71e 100644 --- a/React/Fabric/RCTSurfaceTouchHandler.mm +++ b/React/Fabric/RCTSurfaceTouchHandler.mm @@ -349,7 +349,16 @@ static PointerEvent CreatePointerEventFromActiveTouch(ActiveTouch activeTouch, R event.button = activeTouch.button; } - event.buttons = ButtonMaskToButtons(activeTouch.buttonMask); + event.buttons = 1; + if (@available(iOS 13.4, *)) { + if (activeTouch.touchType == UITouchTypeIndirectPointer) { + // Indirect pointers are the only situations where buttonMask is "accurate" + // so we override the assumed "left click" button value when those type of + // events are recieved + event.buttons = ButtonMaskToButtons(activeTouch.buttonMask); + } + } + UpdatePointerEventModifierFlags(event, activeTouch.modifierFlags); // UIEvent's button mask for touch end events still marks the button as down diff --git a/ReactAndroid/src/test/java/com/facebook/react/uimanager/layoutanimation/BUCK b/ReactAndroid/src/test/java/com/facebook/react/uimanager/layoutanimation/BUCK index 1dcd20c25142c6..9e25be3b51d3f9 100644 --- a/ReactAndroid/src/test/java/com/facebook/react/uimanager/layoutanimation/BUCK +++ b/ReactAndroid/src/test/java/com/facebook/react/uimanager/layoutanimation/BUCK @@ -5,9 +5,7 @@ rn_robolectric_test( srcs = glob(["**/*.java"]), contacts = ["oncall+react_native@xmail.facebook.com"], language = "JAVA", - visibility = [ - "PUBLIC", - ], + visibility = ["PUBLIC"], deps = [ YOGA_TARGET, react_native_dep("third-party/java/assertj:assertj-core"), diff --git a/ReactCommon/react/renderer/animations/LayoutAnimationDriver.cpp b/ReactCommon/react/renderer/animations/LayoutAnimationDriver.cpp index a24d7c4a2cf0cc..7c91b6b329c1a1 100644 --- a/ReactCommon/react/renderer/animations/LayoutAnimationDriver.cpp +++ b/ReactCommon/react/renderer/animations/LayoutAnimationDriver.cpp @@ -59,7 +59,7 @@ void LayoutAnimationDriver::animationMutationsForFrame( mutationsList.emplace_back(ShadowViewMutation::UpdateMutation( keyframe.viewPrev, mutatedShadowView, keyframe.parentView)); - PrintMutationInstruction("Animation Progress:", updateMutation); + PrintMutationInstruction("Animation Progress:", mutationsList.back()); keyframe.viewPrev = std::move(mutatedShadowView); diff --git a/ReactCommon/react/renderer/animations/LayoutAnimationKeyFrameManager.cpp b/ReactCommon/react/renderer/animations/LayoutAnimationKeyFrameManager.cpp index 2160e541efcb00..00b8cfa69efc6b 100644 --- a/ReactCommon/react/renderer/animations/LayoutAnimationKeyFrameManager.cpp +++ b/ReactCommon/react/renderer/animations/LayoutAnimationKeyFrameManager.cpp @@ -14,7 +14,6 @@ #include #include -#include #include #include #include @@ -37,24 +36,12 @@ namespace react { #ifdef LAYOUT_ANIMATION_VERBOSE_LOGGING static std::string GetMutationInstructionString( ShadowViewMutation const &mutation) { - bool mutationIsRemove = mutation.type == ShadowViewMutation::Type::Remove; - bool mutationIsInsert = mutation.type == ShadowViewMutation::Type::Insert; - bool mutationIsDelete = mutation.type == ShadowViewMutation::Type::Delete; - bool mutationIsCreate = mutation.type == ShadowViewMutation::Type::Create; - std::string mutationType = - (mutationIsRemove - ? "REMOVE" - : (mutationIsInsert - ? "INSERT" - : (mutationIsDelete - ? "DELETE" - : (mutationIsCreate ? "CREATE" : "UPDATE")))); - return mutationType + " [" + - std::to_string( - mutationIsInsert || mutationIsCreate - ? mutation.newChildShadowView.tag - : mutation.oldChildShadowView.tag) + - "]->[" + std::to_string(mutation.parentShadowView.tag) + "] @" + + Tag tag = mutation.type == ShadowViewMutation::Type::Insert || + mutation.type == ShadowViewMutation::Type::Create + ? mutation.newChildShadowView.tag + : mutation.oldChildShadowView.tag; + return getDebugName(mutation) + " [" + std::to_string(tag) + "]->[" + + std::to_string(mutation.parentShadowView.tag) + "] @" + std::to_string(mutation.index); } @@ -1638,15 +1625,19 @@ void LayoutAnimationKeyFrameManager::deleteAnimationsForStoppedSurfaces() surfaceIdsToStop_.clear(); } +#ifdef LAYOUT_ANIMATION_VERBOSE_LOGGING + std::ostringstream surfaceIdsStr; + std::copy( + surfaceIdsToStop.begin(), + surfaceIdsToStop.end(), + std::ostream_iterator(surfaceIdsStr, ", ")); + LOG(ERROR) << "LayoutAnimations: stopping animations due to stopSurface on " + << surfaceIdsStr.str(); +#endif + for (auto it = inflightAnimations_.begin(); it != inflightAnimations_.end();) { const auto &animation = *it; - -#ifdef LAYOUT_ANIMATION_VERBOSE_LOGGING - LOG(ERROR) - << "LayoutAnimations: stopping animation due to stopSurface on " - << surfaceId; -#endif if (surfaceIdsToStop.find(animation.surfaceId) != surfaceIdsToStop.end()) { it = inflightAnimations_.erase(it); diff --git a/ReactCommon/react/renderer/mapbuffer/BUCK b/ReactCommon/react/renderer/mapbuffer/BUCK index 2189dbdb97e34c..ccbfc5f0c40882 100644 --- a/ReactCommon/react/renderer/mapbuffer/BUCK +++ b/ReactCommon/react/renderer/mapbuffer/BUCK @@ -1,6 +1,8 @@ load( "//tools/build_defs/oss:rn_defs.bzl", "ANDROID", + "APPLE", + "CXX", "fb_xplat_cxx_test", "get_apple_compiler_flags", "get_apple_inspector_flags", @@ -38,7 +40,7 @@ rn_xplat_cxx_library( "supermodule:xplat/default/public.react_native.infra", ], macosx_tests_override = [], - platforms = ANDROID, + platforms = (ANDROID, APPLE, CXX), preprocessor_flags = [ "-DLOG_TAG=\"ReactNative\"", "-DWITH_FBSYSTRACE=1", @@ -63,7 +65,7 @@ fb_xplat_cxx_test( "-Wall", ], contacts = ["oncall+react_native@xmail.facebook.com"], - platforms = ANDROID, + platforms = (ANDROID, APPLE, CXX), deps = [ "//xplat/third-party/gmock:gtest", react_native_xplat_target("react/debug:debug"), diff --git a/package.json b/package.json index 0922ddd9d8dac2..b04a15f4701b90 100644 --- a/package.json +++ b/package.json @@ -136,7 +136,7 @@ "ws": "^6.1.4" }, "devDependencies": { - "flow-bin": "^0.185.0", + "flow-bin": "^0.185.1", "hermes-eslint": "0.8.0", "react": "18.2.0", "react-test-renderer": "^18.2.0" diff --git a/packages/rn-tester/js/examples/TextInput/TextInputExample.android.js b/packages/rn-tester/js/examples/TextInput/TextInputExample.android.js index bf41299b8d3016..f372bbb77c58dc 100644 --- a/packages/rn-tester/js/examples/TextInput/TextInputExample.android.js +++ b/packages/rn-tester/js/examples/TextInput/TextInputExample.android.js @@ -148,6 +148,13 @@ const styles = StyleSheet.create({ singleLineWithHeightTextInput: { height: 30, }, + default: { + borderWidth: StyleSheet.hairlineWidth, + borderColor: '#0f0f0f', + flex: 1, + fontSize: 13, + padding: 4, + }, }); exports.title = 'TextInput'; @@ -347,6 +354,35 @@ exports.examples = ([ ); }, }, + { + title: 'Editable and Read only', + render: function (): React.Node { + return ( + + + + + + + ); + }, + }, { title: 'Fixed number of lines', platform: 'android', diff --git a/packages/rn-tester/js/examples/TextInput/TextInputExample.ios.js b/packages/rn-tester/js/examples/TextInput/TextInputExample.ios.js index ba2be2aaf8e29f..b3940a1f8332d5 100644 --- a/packages/rn-tester/js/examples/TextInput/TextInputExample.ios.js +++ b/packages/rn-tester/js/examples/TextInput/TextInputExample.ios.js @@ -621,6 +621,35 @@ exports.examples = ([ ); }, }, + { + title: 'Editable and Read only', + render: function (): React.Node { + return ( + + + + + + + ); + }, + }, { title: 'TextInput Intrinsic Size', render: function (): React.Node { diff --git a/repo-config/package.json b/repo-config/package.json index 13ea3e552d39e3..552a56e85c256b 100644 --- a/repo-config/package.json +++ b/repo-config/package.json @@ -32,7 +32,7 @@ "eslint-plugin-react-hooks": "^4.6.0", "eslint-plugin-react-native": "^4.0.0", "eslint-plugin-relay": "^1.8.3", - "flow-bin": "^0.185.0", + "flow-bin": "^0.185.1", "inquirer": "^7.1.0", "jest": "^26.6.3", "jest-junit": "^10.0.0", diff --git a/template/_flowconfig b/template/_flowconfig index 494d2a587ef22c..6450da501c2dbf 100644 --- a/template/_flowconfig +++ b/template/_flowconfig @@ -63,4 +63,4 @@ untyped-import untyped-type-import [version] -^0.185.0 +^0.185.1 diff --git a/yarn.lock b/yarn.lock index c4cc43f5db7dcf..4d8e79d49d4422 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3252,10 +3252,10 @@ flatted@^3.1.0: resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.2.2.tgz#64bfed5cb68fe3ca78b3eb214ad97b63bedce561" integrity sha512-JaTY/wtrcSyvXJl4IMFHPKyFur1sE9AUqc0QnhOaJ0CxHtAoIV8pYDzeEfAaNEtGkOfq4gr3LBFmdXW5mOQFnA== -flow-bin@^0.185.0: - version "0.185.0" - resolved "https://registry.yarnpkg.com/flow-bin/-/flow-bin-0.185.0.tgz#5110cd9ac6cb6716ec864acafe54007e0a13aeff" - integrity sha512-Kl6QdphjpAhD0ieohtmiOttB1Y4J8t7ucJepeovuFt7xFwTRhBA3j3XOST4jSpuEx7ijhP64A/T3bU6W810iYw== +flow-bin@^0.185.1: + version "0.185.1" + resolved "https://registry.yarnpkg.com/flow-bin/-/flow-bin-0.185.1.tgz#dbd3728405ff5aefd147e6c30a27381e9926ffb1" + integrity sha512-TUDZmyXpyKZin3oYtPke1wS5mT2ErCXEPuPsX1s6GgWhP7H7Z/qj6pg7CPcCYt5yNn2Im6k5VWx6J7/5a2stXA== flow-parser@0.*: version "0.163.0"