diff --git a/.ado/Brewfile b/.ado/Brewfile new file mode 100644 index 00000000000000..c94fbdf00279da --- /dev/null +++ b/.ado/Brewfile @@ -0,0 +1,2 @@ +brew "watchman" +brew "xcbeautify" diff --git a/.ado/Brewfile.lock.json b/.ado/Brewfile.lock.json new file mode 100644 index 00000000000000..53396e3d0f4697 --- /dev/null +++ b/.ado/Brewfile.lock.json @@ -0,0 +1,106 @@ +{ + "entries": { + "brew": { + "watchman": { + "version": "2023.03.13.00", + "bottle": { + "rebuild": 0, + "root_url": "https://ghcr.io/v2/homebrew/core", + "files": { + "arm64_ventura": { + "cellar": ":any", + "url": "https://ghcr.io/v2/homebrew/core/watchman/blobs/sha256:404c15d4d191fb04a2d756762e23f75281b6380dfa11e5ec6d03fc79f10df15b", + "sha256": "404c15d4d191fb04a2d756762e23f75281b6380dfa11e5ec6d03fc79f10df15b" + }, + "arm64_monterey": { + "cellar": ":any", + "url": "https://ghcr.io/v2/homebrew/core/watchman/blobs/sha256:4d9d73b0533628c3f4c36fb68f9de2e30c544bf97b4a31b128309f68a5368278", + "sha256": "4d9d73b0533628c3f4c36fb68f9de2e30c544bf97b4a31b128309f68a5368278" + }, + "arm64_big_sur": { + "cellar": ":any", + "url": "https://ghcr.io/v2/homebrew/core/watchman/blobs/sha256:d36a0916b1d93362c1f2de36cd9992fbd9af16b09ccb6d459fb9ddb10fceb9cd", + "sha256": "d36a0916b1d93362c1f2de36cd9992fbd9af16b09ccb6d459fb9ddb10fceb9cd" + }, + "ventura": { + "cellar": ":any", + "url": "https://ghcr.io/v2/homebrew/core/watchman/blobs/sha256:a6e4d1d0092e568d2b4d05942d934aec9feb73f4220156ed663a017831864556", + "sha256": "a6e4d1d0092e568d2b4d05942d934aec9feb73f4220156ed663a017831864556" + }, + "monterey": { + "cellar": ":any", + "url": "https://ghcr.io/v2/homebrew/core/watchman/blobs/sha256:6db809971a23f8de57ac377527afcb2acee533ff89946d564c52baccda1732b2", + "sha256": "6db809971a23f8de57ac377527afcb2acee533ff89946d564c52baccda1732b2" + }, + "big_sur": { + "cellar": ":any", + "url": "https://ghcr.io/v2/homebrew/core/watchman/blobs/sha256:127ab847fded291097dee223b29987f3fb925c3e9c859530f3f8d41488230de9", + "sha256": "127ab847fded291097dee223b29987f3fb925c3e9c859530f3f8d41488230de9" + }, + "x86_64_linux": { + "cellar": ":any_skip_relocation", + "url": "https://ghcr.io/v2/homebrew/core/watchman/blobs/sha256:b0a6fd449d6078c8ff9cbc81247a6253e5c21f955986ee7667c3da5f3ef713e8", + "sha256": "b0a6fd449d6078c8ff9cbc81247a6253e5c21f955986ee7667c3da5f3ef713e8" + } + } + } + }, + "xcbeautify": { + "version": "0.18.0", + "bottle": { + "rebuild": 0, + "root_url": "https://ghcr.io/v2/homebrew/core", + "files": { + "arm64_ventura": { + "cellar": ":any_skip_relocation", + "url": "https://ghcr.io/v2/homebrew/core/xcbeautify/blobs/sha256:099fcf0dee67ef581cea24fdd71373de2df7afc242777e6b708ecaa76bee3943", + "sha256": "099fcf0dee67ef581cea24fdd71373de2df7afc242777e6b708ecaa76bee3943" + }, + "arm64_monterey": { + "cellar": ":any_skip_relocation", + "url": "https://ghcr.io/v2/homebrew/core/xcbeautify/blobs/sha256:14111fef39cdb6e9fd0b78694ce0bbdba058b506f49b1f946a12693b0314a540", + "sha256": "14111fef39cdb6e9fd0b78694ce0bbdba058b506f49b1f946a12693b0314a540" + }, + "arm64_big_sur": { + "cellar": ":any_skip_relocation", + "url": "https://ghcr.io/v2/homebrew/core/xcbeautify/blobs/sha256:fae7f5b74af43fcfc199a0c35551b0a6f5a73f5cffeac3b1312cc05ab9ee2ec3", + "sha256": "fae7f5b74af43fcfc199a0c35551b0a6f5a73f5cffeac3b1312cc05ab9ee2ec3" + }, + "ventura": { + "cellar": ":any_skip_relocation", + "url": "https://ghcr.io/v2/homebrew/core/xcbeautify/blobs/sha256:e703db7316c728405ffcb575e06ab12207c6f0e8d3f89df8f5ea7d889bbea52e", + "sha256": "e703db7316c728405ffcb575e06ab12207c6f0e8d3f89df8f5ea7d889bbea52e" + }, + "monterey": { + "cellar": ":any_skip_relocation", + "url": "https://ghcr.io/v2/homebrew/core/xcbeautify/blobs/sha256:087766fc80f24f4f7be279797c6f6488616965cf69ea0969ef1d407d462fa053", + "sha256": "087766fc80f24f4f7be279797c6f6488616965cf69ea0969ef1d407d462fa053" + }, + "big_sur": { + "cellar": ":any_skip_relocation", + "url": "https://ghcr.io/v2/homebrew/core/xcbeautify/blobs/sha256:76c5506e47ef58a1706c8e5b5e9eb75e05cf57c4868c497faa3e86e3403dc004", + "sha256": "76c5506e47ef58a1706c8e5b5e9eb75e05cf57c4868c497faa3e86e3403dc004" + }, + "x86_64_linux": { + "cellar": "/home/linuxbrew/.linuxbrew/Cellar", + "url": "https://ghcr.io/v2/homebrew/core/xcbeautify/blobs/sha256:b89fe34cbad59b1dfb8d70a1baf31e153302cd4c3e730c871d368d4068082c7b", + "sha256": "b89fe34cbad59b1dfb8d70a1baf31e153302cd4c3e730c871d368d4068082c7b" + } + } + } + } + } + }, + "system": { + "macos": { + "ventura": { + "HOMEBREW_VERSION": "4.0.6", + "HOMEBREW_PREFIX": "/opt/homebrew", + "Homebrew/homebrew-core": "api", + "CLT": "", + "Xcode": "14.1", + "macOS": "13.2.1" + } + } + } +} diff --git a/.ado/ado-start-verdaccio.sh b/.ado/ado-start-verdaccio.sh deleted file mode 100755 index 072628fc8da9b1..00000000000000 --- a/.ado/ado-start-verdaccio.sh +++ /dev/null @@ -1,11 +0,0 @@ -#!/bin/bash -set -ex - -# Script used by the Azure DevOps build agent to start the verdaccio npm proxy server - -THIS_DIR=$PWD - -COMMAND="$TMPDIR/launchVerdaccio.command" -echo "cd ${THIS_DIR}; verdaccio --config ./.ado/verdaccio/config.yaml &> ./.ado/verdaccio/console.log" > "$COMMAND" -chmod +x "$COMMAND" -open "$COMMAND" diff --git a/.ado/ado-test-setup.sh b/.ado/ado-test-setup.sh index 0e64adbebb292c..8f7d11d1738ffe 100755 --- a/.ado/ado-test-setup.sh +++ b/.ado/ado-test-setup.sh @@ -3,6 +3,43 @@ set -ex # Script used by the Azure DevOps build agent to start the packager and web socket server +# Wait for the package to start +waitForPackager() { + local -i max_attempts=60 + local -i attempt_num=1 + + until curl -s http://localhost:8081/status | grep "packager-status:running" -q; do + if (( attempt_num == max_attempts )); then + echo "Packager did not respond in time. No more attempts left." + exit 1 + else + (( attempt_num++ )) + echo "Packager did not respond. Retrying for attempt number $attempt_num..." + sleep 1 + fi + done + + echo "Packager is ready!" +} + +waitForWebSocketServer() { + local -i max_attempts=60 + local -i attempt_num=1 + + until curl -s http://localhost:5555 | grep "Upgrade Required" -q; do + if (( attempt_num == max_attempts )); then + echo "WebSocket Server did not respond in time. No more attempts left." + exit 1 + else + (( attempt_num++ )) + echo "WebSocket Server did not respond. Retrying for attempt number $attempt_num..." + sleep 1 + fi + done + + echo "WebSocket Server is ready!" +} + THIS_DIR=$PWD # AppleScript can't be invoked from Azure DevOps Mojave agents until the following ticket is resolved: https://dev.azure.com/mseng/AzureDevOps/_workitems/edit/1513729 @@ -17,8 +54,10 @@ COMMAND="$TMPDIR/launchPackager.command" echo "cd ${THIS_DIR}; export SERVERS_NO_WAIT=1; ./scripts/launchPackager.command" > "$COMMAND" chmod +x "$COMMAND" open "$COMMAND" +waitForPackager COMMAND="$TMPDIR/launchWebSocketServer.command" echo "cd ${THIS_DIR}; export SERVERS_NO_WAIT=1; ./IntegrationTests/launchWebSocketServer.command" > "$COMMAND" chmod +x "$COMMAND" open "$COMMAND" +waitForWebSocketServer diff --git a/.ado/apple-integration.yml b/.ado/apple-integration.yml index 7f53c5f1c6189a..3492b8e5e46600 100644 --- a/.ado/apple-integration.yml +++ b/.ado/apple-integration.yml @@ -28,7 +28,7 @@ jobs: timeoutInMinutes: 60 cancelTimeoutInMinutes: 5 steps: - - template: templates/apple-node-setup.yml + - template: templates/apple-tools-setup.yml - template: templates/apple-xcode-select.yml parameters: slice_name: $(slice_name) @@ -50,7 +50,7 @@ jobs: set -eo pipefail cat package.json | jq '.devDependencies["react"] = $(react_version)' | - jq '.devDependencies["react-native"] = "^0.68"' | + jq '.devDependencies["react-native"] = "^0.71"' | jq '.devDependencies["react-native-macos"] = "../react-native-macos-$(package_version).tgz"' | jq 'del(.devDependencies["@react-native-community/cli"])' | jq 'del(.devDependencies["@react-native-community/cli-platform-android"])' | @@ -67,7 +67,7 @@ jobs: jq '.devDependencies["@react-native-community/cli-platform-android"] = $(rncli_android_version)' | jq '.devDependencies["@react-native-community/cli-platform-ios"] = $(rncli_ios_version)' | jq '.devDependencies["react"] = $(react_version)' | - jq '.devDependencies["react-native"] = "^0.64"' | + jq '.devDependencies["react-native"] = "^0.71"' | jq '.devDependencies["react-native-macos"] = "../../react-native-macos-$(package_version).tgz"' | jq 'del(.devDependencies["react-native-windows"])' > .package.json mv .package.json package.json @@ -89,7 +89,7 @@ jobs: workingDirectory: react-native-test-app/example - bash: | set -eo pipefail - ../scripts/xcodebuild.sh macos/Example.xcworkspace build + ../scripts/xcodebuild.sh macos/Example.xcworkspace build | xcbeautify displayName: Build Intel workingDirectory: react-native-test-app/example env: @@ -97,7 +97,7 @@ jobs: - bash: | set -eo pipefail ../scripts/xcodebuild.sh macos/Example.xcworkspace clean - ../scripts/xcodebuild.sh macos/Example.xcworkspace build ARCHS=arm64 + ../scripts/xcodebuild.sh macos/Example.xcworkspace build ARCHS=arm64 | xcbeautify displayName: Build ARM workingDirectory: react-native-test-app/example env: diff --git a/.ado/apple-pr.yml b/.ado/apple-pr.yml index 2cd923b1a674b4..85acbd8b710a6e 100644 --- a/.ado/apple-pr.yml +++ b/.ado/apple-pr.yml @@ -31,76 +31,171 @@ jobs: displayName: PR strategy: matrix: - 'iOS Paper Debug': + 'iOS Paper Debug JSC': packager_platform: 'ios' xcode_sdk: iphonesimulator xcode_scheme: 'RNTester' xcode_configuration: 'Debug' xcode_destination: 'platform=iOS Simulator,OS=latest,name=iPhone 14' xcode_actions: 'build test' + xcode_extraArgs: '-xcconfig $(Build.Repository.LocalPath)/.ado/xcconfig/debug_overrides.xcconfig' use_fabric: '0' - 'iOS Paper Release': + use_hermes: '0' + 'iOS Paper Release JSC': packager_platform: 'ios' xcode_sdk: iphonesimulator xcode_scheme: 'RNTester' xcode_configuration: 'Release' xcode_destination: 'platform=iOS Simulator,OS=latest,name=iPhone 14' xcode_actions: 'build' + xcode_extraArgs: '-xcconfig $(Build.Repository.LocalPath)/.ado/xcconfig/release_overrides.xcconfig' use_fabric: '0' - 'iOS Fabric Debug': - packager_platform: 'ios' - xcode_sdk: iphonesimulator - xcode_scheme: 'RNTester' - xcode_configuration: 'Debug' - xcode_destination: 'platform=iOS Simulator,OS=latest,name=iPhone 14' - xcode_actions: 'build test' - use_fabric: '1' - # Disable failing job - # 'iOS Fabric Release': - # packager_platform: 'ios' - # xcode_sdk: iphonesimulator - # xcode_scheme: 'RNTester' - # xcode_configuration: 'Release' - # xcode_destination: 'platform=iOS Simulator,OS=latest,name=iPhone 14' - # xcode_actions: 'build' - # use_fabric: '1' - 'macOS Paper Debug': + use_hermes: '0' + 'macOS Paper Debug JSC': packager_platform: 'macos' xcode_sdk: macosx xcode_scheme: 'RNTester-macOS' xcode_configuration: 'Debug' xcode_destination: 'platform=macOS,arch=x86_64' xcode_actions: 'build test' + xcode_extraArgs: '-xcconfig $(Build.Repository.LocalPath)/.ado/xcconfig/debug_overrides.xcconfig' use_fabric: '0' - 'macOS Paper Release': + use_hermes: '0' + 'macOS Paper Release JSC': packager_platform: 'macos' xcode_sdk: macosx xcode_scheme: 'RNTester-macOS' xcode_configuration: 'Release' xcode_destination: 'platform=macOS,arch=x86_64' xcode_actions: 'build' + xcode_extraArgs: '-xcconfig $(Build.Repository.LocalPath)/.ado/xcconfig/release_overrides.xcconfig' use_fabric: '0' - 'macOS Fabric Debug': + use_hermes: '0' + 'iOS Fabric Debug JSC': + packager_platform: 'ios' + xcode_sdk: iphonesimulator + xcode_scheme: 'RNTester' + xcode_configuration: 'Debug' + xcode_destination: 'platform=iOS Simulator,OS=latest,name=iPhone 14' + xcode_actions: 'build test' + xcode_extraArgs: '-xcconfig $(Build.Repository.LocalPath)/.ado/xcconfig/debug_overrides.xcconfig' + use_fabric: '1' + use_hermes: '0' + 'iOS Fabric Release JSC': + packager_platform: 'ios' + xcode_sdk: iphonesimulator + xcode_scheme: 'RNTester' + xcode_configuration: 'Release' + xcode_destination: 'platform=iOS Simulator,OS=latest,name=iPhone 14' + xcode_actions: 'build' + xcode_extraArgs: '-xcconfig $(Build.Repository.LocalPath)/.ado/xcconfig/release_overrides.xcconfig' + use_fabric: '1' + use_hermes: '0' + 'macOS Fabric Debug JSC': packager_platform: 'macos' xcode_sdk: macosx xcode_scheme: 'RNTester-macOS' xcode_configuration: 'Debug' xcode_destination: 'platform=macOS,arch=x86_64' xcode_actions: 'build test' + xcode_extraArgs: '-xcconfig $(Build.Repository.LocalPath)/.ado/xcconfig/debug_overrides.xcconfig' use_fabric: '1' - # Disable failing job - # 'macOS Fabric Release': + use_hermes: '0' + 'macOS Fabric Release JSC': + packager_platform: 'macos' + xcode_sdk: macosx + xcode_scheme: 'RNTester-macOS' + xcode_configuration: 'Release' + xcode_destination: 'platform=macOS,arch=x86_64' + xcode_actions: 'build' + xcode_extraArgs: '-xcconfig $(Build.Repository.LocalPath)/.ado/xcconfig/release_overrides.xcconfig' + use_fabric: '1' + use_hermes: '0' + # Disable Hermes Jobs for now + # 'iOS Paper Debug Hermes': + # packager_platform: 'ios' + # xcode_sdk: iphonesimulator + # xcode_scheme: 'RNTester' + # xcode_configuration: 'Debug' + # xcode_destination: 'platform=iOS Simulator,OS=latest,name=iPhone 14' + # xcode_actions: 'build test' + # xcode_extraArgs: '-xcconfig $(Build.Repository.LocalPath)/.ado/xcconfig/debug_overrides.xcconfig' + # use_fabric: '0' + # use_hermes: '1' + # 'iOS Paper Release Hermes': + # packager_platform: 'ios' + # xcode_sdk: iphonesimulator + # xcode_scheme: 'RNTester' + # xcode_configuration: 'Release' + # xcode_destination: 'platform=iOS Simulator,OS=latest,name=iPhone 14' + # xcode_extraArgs: '-xcconfig $(Build.Repository.LocalPath)/.ado/xcconfig/release_overrides.xcconfig' + # xcode_actions: 'build' + # use_fabric: '0' + # use_hermes: '1' + # 'macOS Paper Debug Hermes': + # packager_platform: 'macos' + # xcode_sdk: macosx + # xcode_scheme: 'RNTester-macOS' + # xcode_configuration: 'Debug' + # xcode_destination: 'platform=macOS,arch=x86_64' + # xcode_actions: 'build test' + # xcode_extraArgs: '-xcconfig $(Build.Repository.LocalPath)/.ado/xcconfig/debug_overrides.xcconfig' + # use_fabric: '0' + # use_hermes: '1' + # 'macOS Paper Release Hermes': + # packager_platform: 'macos' + # xcode_sdk: macosx + # xcode_scheme: 'RNTester-macOS' + # xcode_configuration: 'Release' + # xcode_destination: 'platform=macOS,arch=x86_64' + # xcode_actions: 'build' + # xcode_extraArgs: '-xcconfig $(Build.Repository.LocalPath)/.ado/xcconfig/release_overrides.xcconfig' + # use_fabric: '0' + # use_hermes: '1' + # 'iOS Fabric Debug Hermes': + # packager_platform: 'ios' + # xcode_sdk: iphonesimulator + # xcode_scheme: 'RNTester' + # xcode_configuration: 'Debug' + # xcode_destination: 'platform=iOS Simulator,OS=latest,name=iPhone 14' + # xcode_actions: 'build test' + # xcode_extraArgs: '-xcconfig $(Build.Repository.LocalPath)/.ado/xcconfig/debug_overrides.xcconfig' + # use_fabric: '1' + # use_hermes: '1' + # 'iOS Fabric Release Hermes': + # packager_platform: 'ios' + # xcode_sdk: iphonesimulator + # xcode_scheme: 'RNTester' + # xcode_configuration: 'Release' + # xcode_destination: 'platform=iOS Simulator,OS=latest,name=iPhone 14' + # xcode_actions: 'build' + # xcode_extraArgs: '-xcconfig $(Build.Repository.LocalPath)/.ado/xcconfig/release_overrides.xcconfig' + # use_fabric: '1' + # use_hermes: '0' + # 'macOS Fabric Debug Hermes': + # packager_platform: 'macos' + # xcode_sdk: macosx + # xcode_scheme: 'RNTester-macOS' + # xcode_configuration: 'Debug' + # xcode_destination: 'platform=macOS,arch=x86_64' + # xcode_actions: 'build test' + # xcode_extraArgs: '-xcconfig $(Build.Repository.LocalPath)/.ado/xcconfig/debug_overrides.xcconfig' + # use_fabric: '1' + # use_hermes: '1' + # 'macOS Fabric Release Hermes': # packager_platform: 'macos' # xcode_sdk: macosx # xcode_scheme: 'RNTester-macOS' # xcode_configuration: 'Release' # xcode_destination: 'platform=macOS,arch=x86_64' # xcode_actions: 'build' + # xcode_extraArgs: '-xcconfig $(Build.Repository.LocalPath)/.ado/xcconfig/release_overrides.xcconfig' # use_fabric: '1' + # use_hermes: '1' pool: vmImage: $(VmImageApple) demands: ['xcode', 'sh', 'npm'] - timeoutInMinutes: 60 # how long to run the job before automatically cancelling + timeoutInMinutes: 90 # how long to run the job before automatically cancelling cancelTimeoutInMinutes: 5 # how much time to give 'run always even if cancelled tasks' before killing them steps: - template: templates/apple-job-react-native.yml @@ -113,6 +208,7 @@ jobs: xcode_destination: $(xcode_destination) slice_name: $(slice_name) xcode_version: $(xcode_version) + xcode_extraArgs: $(xcode_extraArgs) - job: CliInit displayName: Verify react-native-macos-init diff --git a/.ado/publish.yml b/.ado/publish.yml index 78fa05fdd71d8a..f5c2e1d69fa5c8 100644 --- a/.ado/publish.yml +++ b/.ado/publish.yml @@ -59,7 +59,7 @@ jobs: displayName: Set dist-tag to v0.x-stable condition: and(ne(variables['Build.SourceBranchName'], 'main'), ne(variables['Build.SourceBranchName'], variables.latestStableBranch)) - - template: templates/apple-node-setup.yml + - template: templates/apple-tools-setup.yml - task: CmdLine@2 displayName: yarn install diff --git a/.ado/templates/apple-job-javascript.yml b/.ado/templates/apple-job-javascript.yml index 9a741d6349a59b..c6be655291245b 100644 --- a/.ado/templates/apple-job-javascript.yml +++ b/.ado/templates/apple-job-javascript.yml @@ -3,7 +3,7 @@ parameters: xcode_version: '' steps: - - template: apple-node-setup.yml + - template: apple-tools-setup.yml # Task Group: Xcode select proper version - template: apple-xcode-select.yml diff --git a/.ado/templates/apple-job-react-native.yml b/.ado/templates/apple-job-react-native.yml index cd6f11fd31b97a..7d098ed9cd6015 100644 --- a/.ado/templates/apple-job-react-native.yml +++ b/.ado/templates/apple-job-react-native.yml @@ -4,17 +4,15 @@ parameters: xcode_configuration: '' xcode_scheme: '' xcode_actions: '' - xcode_destination: '' + # xcode_destination: '' + xcode_extraArgs: '' slice_name: '' xcode_version: '' use_fabric: '' + use_hermes: '' steps: - - script: | - rm -rf $(Build.Repository.LocalPath)/DerivedData - displayName: 'Clean DerivedData' - - - template: apple-node-setup.yml + - template: apple-tools-setup.yml # Task Group: Xcode select proper version - template: apple-xcode-select.yml @@ -32,9 +30,11 @@ steps: inputs: script: | cd packages/rn-tester - pod install + bundle install + bundle exec pod install env: USE_FABRIC: $(use_fabric) + USE_HERMES: $(use_hermes) - task: ShellScript@2 displayName: 'Setup packager and WebSocket test server' @@ -45,21 +45,31 @@ steps: - bash: | echo Preparing the packager for platform $PLATFORM + curl --retry-connrefused --connect-timeout 5 --max-time 10 --retry 10 --retry-delay 5 --retry-max-time 120 "http://localhost:8081/packages/rn-tester/js/RNTesterApp.${PLATFORM}.bundle?platform=${PLATFORM}&dev=true" -o /dev/null + curl --retry-connrefused --connect-timeout 5 --max-time 10 --retry 10 --retry-delay 5 --retry-max-time 120 "http://localhost:8081/packages/rn-tester/js/RNTesterApp.${PLATFORM}.bundle?platform=${PLATFORM}&dev=true&minify=false" -o /dev/null curl --retry-connrefused --connect-timeout 5 --max-time 10 --retry 10 --retry-delay 5 --retry-max-time 120 "http://localhost:8081/IntegrationTests/IntegrationTestsApp.bundle?platform=${PLATFORM}&dev=true" -o /dev/null + curl --retry-connrefused --connect-timeout 5 --max-time 10 --retry 10 --retry-delay 5 --retry-max-time 120 "http://localhost:8081/IntegrationTests/RCTRootViewIntegrationTestApp.bundle?platform=${PLATFORM}&dev=true" -o /dev/null env: PLATFORM: ${{ parameters.packager_platform }} displayName: 'curl the packager' - - template: apple-xcode-build.yml - parameters: - xcode_sdk: ${{ parameters.xcode_sdk }} - xcode_configuration: ${{ parameters.xcode_configuration }} - xcode_workspacePath: packages/rn-tester/RNTesterPods.xcworkspace - xcode_scheme: ${{ parameters.xcode_scheme }} - xcode_actions: ${{ parameters.xcode_actions }} - xcode_useXcpretty: true - xcode_destination: ${{ parameters.xcode_destination }} - xcode_extraArgs: -retry-tests-on-failure -test-iterations 2 + - task: Xcode@5 + displayName: 'Xcode ${{ parameters.xcode_actions }} ${{ parameters.xcode_configuration }} ${{ parameters.xcode_sdk }} ${{ parameters.xcode_scheme }}' + inputs: + actions: '${{ parameters.xcode_actions }}' + configuration: ${{ parameters.xcode_configuration }} + sdk: ${{ parameters.xcode_sdk }} + xcWorkspacePath: packages/rn-tester/RNTesterPods.xcworkspace + scheme: ${{ parameters.xcode_scheme }} + xcodeVersion: default + signingOption: auto + packageApp: false + teamId: '$(XCodeSigningMicrosoftTeamID)' + args: '-destination "${{ parameters.xcode_destination }}" -verbose -derivedDataPath DerivedData ${{ parameters.xcode_extraArgs }}' + exportPath: '$(agent.builddirectory)/output/${{ parameters.xcode_sdk }}/${{ parameters.xcode_configuration }}' + useXcpretty: true + publishJUnitResults: true + xctoolReporter: 'junit:test-results.xml' - task: ShellScript@2 displayName: 'Cleanup packager and WebSocket test server' diff --git a/.ado/templates/apple-node-setup.yml b/.ado/templates/apple-node-setup.yml deleted file mode 100644 index 26586dae06ae9d..00000000000000 --- a/.ado/templates/apple-node-setup.yml +++ /dev/null @@ -1,13 +0,0 @@ -# -# Task Group: Brew install node version -# -steps: - - script: 'brew bundle' - displayName: 'brew bundle' - - # Brew can't access user data for node - - script: sudo chown -R $(whoami) /usr/local/* - displayName: 'fix node permissions' - - - script: brew link node@16 --overwrite --force - displayName: 'ensure node 16' diff --git a/.ado/templates/apple-tools-setup.yml b/.ado/templates/apple-tools-setup.yml new file mode 100644 index 00000000000000..73583641385f40 --- /dev/null +++ b/.ado/templates/apple-tools-setup.yml @@ -0,0 +1,12 @@ +steps: + - task: NodeTool@0 + inputs: + versionSource: 'fromFile' # 'spec' | 'fromFile'. Required. Source of version. Default: spec. + versionFilePath: '.node-version' + + - task: UseRubyVersion@0 + inputs: + versionSpec: '>= 2.7' + + - script: 'brew bundle --file .ado/Brewfile' + displayName: 'brew bundle' diff --git a/.ado/templates/apple-xcode-build.yml b/.ado/templates/apple-xcode-build.yml deleted file mode 100644 index c0ee51376ba7cf..00000000000000 --- a/.ado/templates/apple-xcode-build.yml +++ /dev/null @@ -1,28 +0,0 @@ -parameters: - xcode_sdk: '' - xcode_configuration: '' - xcode_workspacePath: '' - xcode_scheme: '' - xcode_actions: '' - xcode_useXcpretty: false - xcode_destination: '' - xcode_extraArgs: '' - -steps: - - task: Xcode@5 - displayName: 'Xcode ${{ parameters.xcode_actions }} ${{ parameters.xcode_configuration }} ${{ parameters.xcode_sdk }} ${{ parameters.xcode_scheme }}' - inputs: - actions: '${{ parameters.xcode_actions }}' - configuration: ${{ parameters.xcode_configuration }} - sdk: ${{ parameters.xcode_sdk }} - xcWorkspacePath: ${{ parameters.xcode_workspacePath }} - scheme: ${{ parameters.xcode_scheme }} - xcodeVersion: default - signingOption: auto - packageApp: false - teamId: '$(XCodeSigningMicrosoftTeamID)' - args: '-destination "${{ parameters.xcode_destination }}" ONLY_ACTIVE_ARCH=YES -verbose -derivedDataPath DerivedData ${{ parameters.xcode_extraArgs }}' - exportPath: '$(agent.builddirectory)/output/${{ parameters.xcode_sdk }}/${{ parameters.xcode_configuration }}' - useXcpretty: ${{ parameters.xcode_useXcpretty }} - publishJUnitResults: ${{ parameters.xcode_useXcpretty }} - xctoolReporter: 'junit:test-results.xml' diff --git a/.ado/templates/react-native-macos-init.yml b/.ado/templates/react-native-macos-init.yml index 34e414a8e4ce78..b1fecda78f196a 100644 --- a/.ado/templates/react-native-macos-init.yml +++ b/.ado/templates/react-native-macos-init.yml @@ -9,7 +9,7 @@ steps: submodules: false # set to 'true' for a single level of submodules or 'recursive' to get submodules of submodules persistCredentials: false # set to 'true' to leave the OAuth token in the Git config after the initial fetch - - template: apple-node-setup.yml + - template: apple-tools-setup.yml # First do a build of the local package, since we point the cli at the local files, it needs to be pre-built - task: CmdLine@2 @@ -32,17 +32,10 @@ steps: yarn build - task: CmdLine@2 - displayName: Install Verdaccio - inputs: - script: | - npm install --global verdaccio - - - task: ShellScript@2 displayName: Launch test npm server (verdaccio) inputs: - scriptPath: '.ado/ado-start-verdaccio.sh' - disableAutoCwd: true - cwd: '' + script: | + npx verdaccio --config ./.ado/verdaccio/config.yaml & - script: | npm set registry http://localhost:4873 @@ -84,9 +77,15 @@ steps: - task: CmdLine@2 displayName: Init new project inputs: - script: npx --yes react-native@0.68.2 init testcli --template react-native@0.68.2 + script: npx --yes react-native@0.71.4 init testcli --template react-native@0.71.4 --skip-install workingDirectory: $(Agent.BuildDirectory) + - task: CmdLine@2 + displayName: yarn install (local react-native-macos-init) + inputs: + script: yarn install --frozen-lockfile + workingDirectory: $(Agent.BuildDirectory)/testcli + - task: CmdLine@2 displayName: Apply macos template inputs: diff --git a/.ado/variables/vars.yml b/.ado/variables/vars.yml index 7f7be992155aae..77104d18c4cea6 100644 --- a/.ado/variables/vars.yml +++ b/.ado/variables/vars.yml @@ -1,4 +1,4 @@ variables: VmImageApple: internal-macos12 - slice_name: 'Xcode_14.0.1' - xcode_version: '/Applications/Xcode_14.0.1.app' + slice_name: 'Xcode_14.2' + xcode_version: '/Applications/Xcode_14.2.app' diff --git a/.ado/xcconfig/debug_overrides.xcconfig b/.ado/xcconfig/debug_overrides.xcconfig new file mode 100644 index 00000000000000..4d2cc29c3d83bf --- /dev/null +++ b/.ado/xcconfig/debug_overrides.xcconfig @@ -0,0 +1,3 @@ +// Turn on Sanitizers for Release Builds +CLANG_ADDRESS_SANITIZER = YES +CLANG_UNDEFINED_BEHAVIOR_SANITIZER = YES diff --git a/.ado/xcconfig/release_overrides.xcconfig b/.ado/xcconfig/release_overrides.xcconfig new file mode 100644 index 00000000000000..48d2466f2a49d5 --- /dev/null +++ b/.ado/xcconfig/release_overrides.xcconfig @@ -0,0 +1,21 @@ +#include "release_staticanalysis.xcconfig" +// For publish builds, only provide line tables for symbolizing crashes +CLANG_DEBUG_INFORMATION_LEVEL[config=Release]=line-tables-only +// The following build setting caused build errors, so it is commented out and placed in every podspec instead +// OTHER_SWIFT_FLAGS=-gline-tables-only + +// Optimize for size in publish builds +SWIFT_OPTIMIZATION_LEVEL[config=Release]=-Osize + +// Build for all architectures, not just the active one +ONLY_ACTIVE_ARCH=NO + +// react-native/react_native_pods.rb sometimes makes our lives difficult +EXCLUDED_ARCHS = + +// Specify the exact Swift version used for reproducibility +SWIFT_VERSION = 5.0 + +// Turn off Sanitizers for Release Builds +CLANG_ADDRESS_SANITIZER = NO +CLANG_UNDEFINED_BEHAVIOR_SANITIZER = NO diff --git a/.ado/xcconfig/release_staticanalysis.xcconfig b/.ado/xcconfig/release_staticanalysis.xcconfig new file mode 100644 index 00000000000000..c87887e0251ce9 --- /dev/null +++ b/.ado/xcconfig/release_staticanalysis.xcconfig @@ -0,0 +1,13 @@ +RUN_CLANG_STATIC_ANALYZER = YES +CLANG_STATIC_ANALYZER_MODE = deep + +// Required security settings for production code (do not override at target/project level, with the possible +// exception of legacy test code) +CLANG_ANALYZER_SECURITY_FLOATLOOPCOUNTER = YES +CLANG_ANALYZER_SECURITY_KEYCHAIN_API = YES +CLANG_ANALYZER_SECURITY_INSECUREAPI_UNCHECKEDRETURN = YES +CLANG_ANALYZER_SECURITY_INSECUREAPI_GETPW_GETS = YES +CLANG_ANALYZER_SECURITY_INSECUREAPI_MKSTEMP = YES +CLANG_ANALYZER_SECURITY_INSECUREAPI_RAND = YES +CLANG_ANALYZER_SECURITY_INSECUREAPI_STRCPY = YES +CLANG_ANALYZER_SECURITY_INSECUREAPI_VFORK = YES diff --git a/.buckconfig b/.buckconfig index 76d22bf86f5e18..272ffbbe1221a5 100644 --- a/.buckconfig +++ b/.buckconfig @@ -2,6 +2,10 @@ [android] target = android-31 +[kotlin] + compile_against_abis = True + kotlin_version = 1.6.10 + [download] max_number_of_retries = 3 diff --git a/.circleci/Dockerfiles/Dockerfile.android b/.circleci/Dockerfiles/Dockerfile.android index 81ec524f8af794..366a8d8fba06e3 100644 --- a/.circleci/Dockerfiles/Dockerfile.android +++ b/.circleci/Dockerfiles/Dockerfile.android @@ -24,7 +24,7 @@ # Disabling this is okay because per (Github#774) this test, which is redundant to Azure Devops test, # fails in the fork because of Microsoft's V8 upgrade to Android # -#FROM reactnativecommunity/react-native-android:5.2 +#FROM reactnativecommunity/react-native-android:6.0 LABEL Description="React Native Android Test Image" LABEL maintainer="Héctor Ramos " @@ -32,7 +32,7 @@ LABEL maintainer="Héctor Ramos " ARG BUCK_BUILD # set default environment variables ENV GRADLE_OPTS="-Dorg.gradle.daemon=false -Dorg.gradle.jvmargs=\"-Xmx512m -XX:+HeapDumpOnOutOfMemoryError\"" -ENV JAVA_TOOL_OPTIONS="-Dfile.encoding=UTF8" +ENV KOTLIN_HOME="third-party/kotlin" ADD .buckconfig /app/.buckconfig ADD .buckjavaargs /app/.buckjavaargs @@ -44,6 +44,7 @@ ADD React /app/React ADD keystores /app/keystores ADD packages/react-native-codegen /app/packages/react-native-codegen ADD tools /app/tools +add scripts /app/scripts # add third party dependencies ADD Folly /app/Folly @@ -54,6 +55,8 @@ ADD jsc /app/jsc # set workdir WORKDIR /app +RUN scripts/download-kotlin-compiler-with-buck.sh + RUN buck fetch ReactAndroid/src/test/java/com/facebook/react/modules RUN buck fetch ReactAndroid/src/main/java/com/facebook/react RUN buck fetch ReactAndroid/src/main/java/com/facebook/react/shell @@ -80,6 +83,4 @@ ADD . /app RUN yarn -RUN ./gradlew :ReactAndroid:downloadBoost :ReactAndroid:downloadDoubleConversion :ReactAndroid:downloadFolly :ReactAndroid:downloadGlog - -RUN ./gradlew :ReactAndroid:packageReactNdkLibsForBuck -Pjobs=1 +RUN ./gradlew :ReactAndroid:assembleDebug diff --git a/.circleci/Dockerfiles/scripts/run-android-docker-instrumentation-tests.sh b/.circleci/Dockerfiles/scripts/run-android-docker-instrumentation-tests.sh index 64f0ee465642ab..130ebbb01f0b0b 100755 --- a/.circleci/Dockerfiles/scripts/run-android-docker-instrumentation-tests.sh +++ b/.circleci/Dockerfiles/scripts/run-android-docker-instrumentation-tests.sh @@ -33,7 +33,7 @@ node cli.js bundle --platform android --dev true --entry-file ReactAndroid/src/a # build test APK # shellcheck disable=SC1091 -source ./scripts/android-setup.sh && NO_BUCKD=1 retry3 buck install ReactAndroid/src/androidTest/buck-runner:instrumentation-tests --config build.threads=1 +source ./scripts/android-setup.sh && NO_BUCKD=1 scripts/retry3 buck install ReactAndroid/src/androidTest/buck-runner:instrumentation-tests --config build.threads=1 # run installed apk with tests node ./.circleci/Dockerfiles/scripts/run-android-ci-instrumentation-tests.js "$*" diff --git a/.circleci/config.yml b/.circleci/config.yml index 303e35e217db81..8a5a4af5f231b7 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -8,17 +8,81 @@ orbs: win: circleci/windows@2.4.0 # ------------------------- -# DEFAULTS +# REFERENCES # ------------------------- -defaults: &defaults - working_directory: ~/react-native - environment: - - GIT_COMMIT_DESC: git log --format=oneline -n 1 $CIRCLE_SHA1 - # The public github tokens are publicly visible by design - - PUBLIC_PULLBOT_GITHUB_TOKEN_A: &github_pullbot_token_a "a6edf8e8d40ce4e8b11a" - - PUBLIC_PULLBOT_GITHUB_TOKEN_B: &github_pullbot_token_b "150e1341f4dd9c944d2a" - - PUBLIC_ANALYSISBOT_GITHUB_TOKEN_A: &github_analysisbot_token_a "312d354b5c36f082cfe9" - - PUBLIC_ANALYSISBOT_GITHUB_TOKEN_B: &github_analysisbot_token_b "07973d757026bdd9f196" +references: + defaults: &defaults + working_directory: ~/react-native + environment: + - GIT_COMMIT_DESC: git log --format=oneline -n 1 $CIRCLE_SHA1 + # The public github tokens are publicly visible by design + - PUBLIC_PULLBOT_GITHUB_TOKEN_A: &github_pullbot_token_a "a6edf8e8d40ce4e8b11a" + - PUBLIC_PULLBOT_GITHUB_TOKEN_B: &github_pullbot_token_b "150e1341f4dd9c944d2a" + - PUBLIC_ANALYSISBOT_GITHUB_TOKEN_A: &github_analysisbot_token_a "312d354b5c36f082cfe9" + - PUBLIC_ANALYSISBOT_GITHUB_TOKEN_B: &github_analysisbot_token_b "07973d757026bdd9f196" + # Homebrew currently breaks while updating: + # https://discuss.circleci.com/t/brew-install-fails-while-updating/32992 + - HOMEBREW_NO_AUTO_UPDATE: 1 + + hermes_workspace_root: &hermes_workspace_root + /tmp/hermes + hermes_tarball_artifacts_dir: &hermes_tarball_artifacts_dir + /tmp/hermes/hermes-runtime-darwin + hermes_osxbin_artifacts_dir: &hermes_osxbin_artifacts_dir + /tmp/hermes/osx-bin + attach_hermes_workspace: &attach_hermes_workspace + attach_workspace: + at: *hermes_workspace_root + + # ------------------------- + # Dependency Anchors + # ------------------------- + dependency_versions: + xcode_version: &xcode_version "14.0.1" + nodelts_image: &nodelts_image "cimg/node:16.14" + nodeprevlts_image: &nodeprevlts_image "cimg/node:14.19" + + # ------------------------- + # Cache Key Anchors + # ------------------------- + # Anchors for the cache keys + + cache_keys: + 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_workspace_cache_key: &hermes_workspace_cache_key v4-hermes-{{ .Environment.CIRCLE_JOB }}-{{ checksum "/tmp/hermes/hermesversion" }} + hermes_workspace_debug_cache_key: &hermes_workspace_debug_cache_key v2-hermes-{{ .Environment.CIRCLE_JOB }}-debug-{{ checksum "/tmp/hermes/hermesversion" }} + hermes_workspace_release_cache_key: &hermes_workspace_release_cache_key v2-hermes-{{ .Environment.CIRCLE_JOB }}-release-{{ checksum "/tmp/hermes/hermesversion" }} + hermes_windows_cache_key: &hermes_windows_cache_key v3-hermes-{{ .Environment.CIRCLE_JOB }}-{{ checksum "tmp/hermes/hermesversion" }} + hermes_tarball_debug_cache_key: &hermes_tarball_debug_cache_key v2-hermes-tarball-debug-{{ checksum "/tmp/hermes/hermesversion" }} + hermes_tarball_release_cache_key: &hermes_tarball_release_cache_key v1-hermes-tarball-release-{{ 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 }} + + cache_paths: + hermes_workspace_macos_cache_paths: &hermes_workspace_macos_cache_paths + - ~/react-native/sdks/hermes/build_macosx + - ~/react-native/sdks/hermes/destroot + hermes_tarball_cache_paths: &hermes_tarball_cache_paths + - *hermes_tarball_artifacts_dir + + # ------------------------- + # Filters + # ------------------------- + # CircleCI filters are OR-ed, with all branches triggering by default and tags excluded by default + # CircleCI env-vars are only set with the branch OR tag that triggered the job, not both. + + # In this case, CIRCLE_BRANCH is unset, but CIRCLE_TAG is set. + only_release_tags: &only_release_tags + # Both of the following conditions must be included! + # Ignore any commit on any branch by default. + branches: + ignore: /.*/ + # Only act on version tags. + tags: + only: /v[0-9]+(\.[0-9]+)*(\-rc(\.[0-9]+)?)?/ # ------------------------- # EXECUTORS @@ -28,15 +92,20 @@ executors: <<: *defaults docker: # Note: Version set separately for Windows builds, see below. - - image: circleci/node:16 + - image: *nodelts_image + # [macOS] Change resource_class to large as we're on the free CircleCI plan + resource_class: "large" nodeprevlts: <<: *defaults docker: - - image: circleci/node:14 + - image: *nodeprevlts_image + # [macOS] Change resource_class to large as we're on the free CircleCI plan + resource_class: "large" reactnativeandroid: <<: *defaults docker: - - image: reactnativecommunity/react-native-android:5.2 + - image: reactnativecommunity/react-native-android:6.0 + # [macOS] Change resource_class to large as we're on the free CircleCI plan resource_class: "large" environment: - TERM: "dumb" @@ -51,12 +120,30 @@ executors: reactnativeios: <<: *defaults macos: - xcode: &_XCODE_VERSION "13.3.1" + xcode: *xcode_version + resource_class: macos.x86.medium.gen2 # ------------------------- # COMMANDS # ------------------------- commands: + # Checkout with cache, on machines that are using Docker the cache is ignored + checkout_code_with_cache: + parameters: + checkout_base_cache_key: + default: *checkout_cache_key + type: string + steps: + - restore_cache: + keys: + - << parameters.checkout_base_cache_key >>-{{ arch }}-{{ .Branch }}-{{ .Revision }} + - << parameters.checkout_base_cache_key >>-{{ arch }}-{{ .Branch }}- + - << parameters.checkout_base_cache_key >>-{{ arch }}- + - checkout + - save_cache: + key: << parameters.checkout_base_cache_key >>-{{ arch }}-{{ .Branch }}-{{ .Revision }} + paths: + - ".git" setup_artifacts: steps: @@ -67,24 +154,29 @@ commands: setup_ruby: steps: - restore_cache: - key: 1-gems-{{ checksum "Gemfile.lock" }} + key: *gems_cache_key - run: name: Bundle Install command: | source /usr/local/share/chruby/auto.sh bundle check || bundle install --path vendor/bundle --clean - save_cache: - key: 1-gems-{{ checksum "Gemfile.lock" }} + key: *gems_cache_key paths: - vendor/bundle run_yarn: + parameters: + yarn_base_cache_key: + default: *yarn_cache_key + type: string + steps: - restore_cache: keys: - - v5-yarn-cache-{{ .Environment.CIRCLE_JOB }}-{{ arch }}-{{ checksum "yarn.lock" }} - - v5-yarn-cache-{{ .Environment.CIRCLE_JOB }}-{{ arch }} - - v5-yarn-cache-{{ .Environment.CIRCLE_JOB }} + - << parameters.yarn_base_cache_key >>-{{ arch }}-{{ checksum "yarn.lock" }} + - << parameters.yarn_base_cache_key >>-{{ arch }} + - << parameters.yarn_base_cache_key >> - run: name: "Yarn: Install Dependencies" command: | @@ -96,32 +188,7 @@ commands: - save_cache: paths: - ~/.cache/yarn - key: v5-yarn-cache-{{ .Environment.CIRCLE_JOB }}-{{ arch }}-{{ checksum "yarn.lock" }} - - install_buck_tooling: - steps: - - restore_cache: - keys: - - v3-buck-v2019.01.10.01-{{ checksum "scripts/circleci/buck_fetch.sh" }}} - - run: - name: Install BUCK - command: | - buck --version - # Install related tooling - if [[ ! -e ~/okbuck ]]; then - git clone https://github.com/uber/okbuck.git ~/okbuck --depth=1 - fi - - save_cache: - paths: - - ~/buck - - ~/okbuck - key: v3-buck-v2019.01.10.01-{{ checksum "scripts/circleci/buck_fetch.sh" }} - - install_github_bot_deps: - steps: - - run: - name: "Yarn: Install dependencies (GitHub bots)" - command: cd bots && yarn install --non-interactive --cache-folder ~/.cache/yarn + key: << parameters.yarn_base_cache_key >>-{{ arch }}-{{ checksum "yarn.lock" }} brew_install: parameters: @@ -131,22 +198,7 @@ commands: steps: - run: name: "Brew: Install << parameters.package >>" - command: HOMEBREW_NO_AUTO_UPDATE=1 brew install << parameters.package >> >/dev/null - - with_brew_cache_span: - parameters: - steps: - type: steps - steps: - - restore_cache: - keys: - - v4-brew - - steps: << parameters.steps >> - - save_cache: - paths: - - /usr/local/Homebrew - - ~/Library/Caches/Homebrew - key: v4-brew + command: brew install << parameters.package >> >/dev/null with_rntester_pods_cache_span: parameters: @@ -159,35 +211,29 @@ commands: command: cp packages/rn-tester/Podfile.lock packages/rn-tester/Podfile.lock.bak - restore_cache: keys: - # The committed lockfile is generated using USE_FRAMEWORKS=0 and USE_HERMES=0 so it could load an outdated cache if a change + # The committed lockfile is generated using USE_FRAMEWORKS=0 and USE_HERMES=1 so it could load an outdated cache if a change # only affects the frameworks or hermes config. To help prevent this also cache based on the content of Podfile. - - v3-pods-{{ .Environment.CIRCLE_JOB }}-{{ checksum "packages/rn-tester/Podfile.lock.bak" }}-{{ checksum "packages/rn-tester/Podfile" }} + - *pods_cache_key - steps: << parameters.steps >> - save_cache: paths: - packages/rn-tester/Pods - key: v3-pods-{{ .Environment.CIRCLE_JOB }}-{{ checksum "packages/rn-tester/Podfile.lock.bak" }}-{{ checksum "packages/rn-tester/Podfile" }} + key: *pods_cache_key download_gradle_dependencies: steps: - restore_cache: keys: - - v1-gradle-{{ checksum "gradle/wrapper/gradle-wrapper.properties" }}-{{ checksum "ReactAndroid/gradle.properties" }} + - *gradle_cache_key - run: name: Download Dependencies Using Gradle - command: ./scripts/circleci/gradle_download_deps.sh + command: ./gradlew downloadAll - save_cache: paths: - ~/.gradle - ReactAndroid/build/downloads - ReactAndroid/build/third-party-ndk - key: v1-gradle-{{ checksum "gradle/wrapper/gradle-wrapper.properties" }}-{{ checksum "ReactAndroid/gradle.properties" }} - - download_buck_dependencies: - steps: - - run: - name: Download Dependencies Using Buck - command: ./scripts/circleci/buck_fetch.sh + key: *gradle_cache_key run_e2e: parameters: @@ -212,11 +258,149 @@ commands: type: enum enum: ["android", "ios"] steps: - - install_github_bot_deps - run: name: Report size of RNTester.app (analysis-bot) command: GITHUB_TOKEN="$PUBLIC_ANALYSISBOT_GITHUB_TOKEN_A""$PUBLIC_ANALYSISBOT_GITHUB_TOKEN_B" scripts/circleci/report-bundle-size.sh << parameters.platform >> || true + with_hermes_tarball_cache_span: + parameters: + steps: + type: steps + set_tarball_path: + type: boolean + default: False + flavor: + default: "Debug" + description: The Hermes build type. Must be one of "Debug", "Release". + type: enum + enum: ["Debug", "Release"] + hermes_tarball_artifacts_dir: + type: string + default: *hermes_tarball_artifacts_dir + steps: + - when: + condition: + equal: [ << parameters.flavor >>, "Debug"] + steps: + - restore_cache: + keys: + - *hermes_tarball_debug_cache_key + - when: + condition: + equal: [ << parameters.flavor >>, "Release"] + steps: + - restore_cache: + keys: + - *hermes_tarball_release_cache_key + - when: + condition: << parameters.set_tarball_path >> + steps: + - run: + name: Set HERMES_ENGINE_TARBALL_PATH envvar if Hermes tarball is present + command: | + HERMES_TARBALL_ARTIFACTS_DIR=<< parameters.hermes_tarball_artifacts_dir >> + if [ ! -d $HERMES_TARBALL_ARTIFACTS_DIR ]; then + echo "Hermes tarball artifacts dir not present ($HERMES_TARBALL_ARTIFACTS_DIR). Build Hermes from source." + exit 0 + fi + + if [ ! -d ~/react-native ]; then + echo "No React Native checkout found. Run `checkout` first." + exit 0 + fi + + TARBALL_FILENAME=$(node ~/react-native/scripts/hermes/get-tarball-name.js --buildType "<< parameters.flavor >>" --releaseVersion "*") + TARBALL_PATH=$(ls $HERMES_TARBALL_ARTIFACTS_DIR/$TARBALL_FILENAME) + + echo "Looking for $TARBALL_FILENAME in $HERMES_TARBALL_ARTIFACTS_DIR" + echo "$TARBALL_PATH" + + if [ ! -f $TARBALL_PATH ]; then + echo "Hermes tarball not present ($TARBALL_PATH). Build Hermes from source." + exit 0 + fi + + echo "Found Hermes tarball at $TARBALL_PATH" + echo "export HERMES_ENGINE_TARBALL_PATH=$TARBALL_PATH" >> $BASH_ENV + - steps: << parameters.steps >> + - when: + condition: + equal: [ << parameters.flavor >>, "Debug"] + steps: + - save_cache: + key: *hermes_tarball_debug_cache_key + paths: *hermes_tarball_cache_paths + - when: + condition: + equal: [ << parameters.flavor >>, "Release"] + steps: + - save_cache: + key: *hermes_tarball_release_cache_key + paths: *hermes_tarball_cache_paths + + with_hermesc_span: + description: "Makes hermesc available to the provided steps, if hermesc is present." + parameters: + flavor: + default: "Debug" + description: The Hermes build type. Must be one of "Debug", "Release". + type: enum + enum: ["Debug", "Release"] + steps: + type: steps + steps: + - export_hermesc: + flavor: << parameters.flavor >> + - steps: << parameters.steps >> + - export_hermesc: + flavor: << parameters.flavor >> + + export_hermesc: + description: "Configures hermesc for use in Hermes builds when possible. The binary is built by either of the macOS or iOS builds, and may be cached by previous builds." + parameters: + flavor: + default: "Debug" + description: The Hermes build type. Must be one of "Debug", "Release". + type: enum + enum: ["Debug", "Release"] + artifacts_dir: + type: string + default: *hermes_osxbin_artifacts_dir + steps: + - run: + name: "Export path to HermesC if available" + command: | + # Although the hermesc binary built by debug and release jobs is + # identical, we need to store it in distinct paths as Circle CI + # cannot have two different jobs write to the same path in + # artifacts. + mkdir -p << parameters.artifacts_dir >>/Debug << parameters.artifacts_dir >>/Release + hermesc_artifacts_path=<< parameters.artifacts_dir >>/<< parameters.flavor >>/hermesc + + hermesc_bin_path=bin/hermesc + hermes_build_dir_macos=$(pwd)/sdks/hermes/build_macosx + hermes_build_dir_ios=$(pwd)/sdks/hermes/build_iphoneos + + function export_hermesc_cmake_path { + build_dir=$1 + hermesc_bin=$build_dir/$hermesc_bin_path + cmake_path=$build_dir/ImportHermesc.cmake + + if [[ -f $cmake_path ]]; then + echo "export HERMES_OVERRIDE_HERMESC_PATH=$cmake_path" >> $BASH_ENV + fi + + if [[ ! -f $hermesc_artifacts_path ]]; then + cp $hermesc_bin $hermesc_artifacts_path + fi + } + + if [[ -f $hermes_build_dir_macos/$hermesc_bin_path ]]; then + export_hermesc_cmake_path $hermes_build_dir_macos + elif [[ -f $hermes_build_dir_ios/$hermesc_bin_path ]]; then + export_hermesc_cmake_path $hermes_build_dir_ios + fi + # ------------------------- # JOBS # ------------------------- @@ -233,7 +417,6 @@ jobs: - checkout - run_yarn - - install_github_bot_deps # Note: The yarn gpg key needs to be refreshed to work around https://github.com/yarnpkg/yarn/issues/7866 - run: @@ -252,13 +435,6 @@ jobs: command: GITHUB_TOKEN="$PUBLIC_ANALYSISBOT_GITHUB_TOKEN_A""$PUBLIC_ANALYSISBOT_GITHUB_TOKEN_B" yarn lint-ci when: always - - run: - name: Analyze Pull Request (pull-bot) - command: | - cd bots - DANGER_GITHUB_API_TOKEN="$PUBLIC_PULLBOT_GITHUB_TOKEN_A""$PUBLIC_PULLBOT_GITHUB_TOKEN_B" yarn danger ci --use-github-checks - when: always - # ------------------------- # JOBS: Analyze Code # ------------------------- @@ -289,6 +465,11 @@ jobs: command: yarn flow-check-android when: always + - run: + name: Run TypeScript tests + command: yarn test-typescript + when: always + - run: name: Sanity checks command: | @@ -322,7 +503,7 @@ jobs: - run_yarn - run: name: Install rsync - command: sudo apt-get install rsync + command: sudo apt update && sudo apt install rsync # ------------------------- # Run JavaScript tests @@ -344,7 +525,7 @@ jobs: path: ./reports/junit # ------------------------- - # JOBS: Test iOS + # JOBS: iOS Unit Tests # ------------------------- test_ios: executor: reactnativeios @@ -352,9 +533,6 @@ jobs: use_frameworks: type: boolean default: false - use_hermes: - type: boolean - default: false run_unit_tests: description: Specifies whether unit tests should run. type: boolean @@ -363,14 +541,24 @@ jobs: description: Specifies whether disabled tests should run. Set this to true to debug failing tests. type: boolean default: false + jsengine: + default: "Hermes" + description: Which JavaScript engine to use. Must be one of "Hermes", "JSC". + type: enum + enum: ["Hermes", "JSC"] environment: - REPORTS_DIR: "./reports/junit" steps: - - checkout + - checkout_code_with_cache - setup_artifacts - setup_ruby + - run: + name: Run Ruby Tests + command: | + cd scripts + sh run_ruby_tests.sh - run_yarn - + - *attach_hermes_workspace - run: | cd packages/rn-tester bundle check || bundle install @@ -384,21 +572,11 @@ jobs: echo 'export PATH=/usr/local/opt/node@16/bin:$PATH' >> $BASH_ENV source $BASH_ENV - - with_brew_cache_span: - steps: - - brew_install: - package: watchman - - run: - name: "Brew: Tap wix/brew" - command: HOMEBREW_NO_AUTO_UPDATE=1 brew tap wix/brew >/dev/null - - brew_install: - package: applesimutils - - run: - name: Configure Node - # Sourcing find-node.sh will ensure nvm is set up. - # It also helps future invocation of find-node.sh prevent permission issue with nvm.sh. - command: source scripts/find-node.sh && nvm install 16 && nvm alias default 16 + name: "Brew: Tap wix/brew" + command: brew tap wix/brew >/dev/null + - brew_install: + package: applesimutils watchman - run: name: Configure Watchman @@ -411,22 +589,23 @@ jobs: name: Set USE_FRAMEWORKS=1 command: echo "export USE_FRAMEWORKS=1" >> $BASH_ENV - - when: - condition: << parameters.use_hermes >> - steps: - - run: - name: Set USE_HERMES=1 - command: echo "export USE_HERMES=1" >> $BASH_ENV - - run: name: Setup the CocoaPods environment command: bundle exec pod setup - - with_rntester_pods_cache_span: + - with_hermes_tarball_cache_span: + set_tarball_path: True steps: - - run: - name: Generate RNTesterPods Workspace - command: cd packages/rn-tester && bundle exec pod install --verbose + - with_rntester_pods_cache_span: + steps: + - run: + name: Generate RNTesterPods Workspace + command: | + if [[ << parameters.jsengine >> == "JSC" ]]; then + export USE_HERMES=0 + fi + + cd packages/rn-tester && bundle exec pod install --verbose # ------------------------- # Runs iOS unit tests @@ -436,6 +615,16 @@ jobs: - run: name: "Run Tests: iOS Unit and Integration Tests" command: yarn test-ios + - run: + name: Zip Derived data folder + when: always + command: | + echo "zipping tests results" + cd /Users/distiller/Library/Developer/Xcode + XCRESULT_PATH=$(find . -name '*.xcresult') + tar -zcvf xcresults.tar.gz $XCRESULT_PATH + - store_artifacts: + path: /Users/distiller/Library/Developer/Xcode/xcresults.tar.gz # Optionally, run disabled tests - when: @@ -462,6 +651,59 @@ jobs: - store_test_results: path: ./reports/junit + # ------------------------- + # JOBS: Test Buck + # ------------------------- + test_buck: + executor: reactnativeandroid + environment: + KOTLIN_HOME=third-party/kotlin + steps: + - checkout + - setup_artifacts + - run_yarn + + - run: + name: Download Dependencies Using Buck + command: ./scripts/circleci/buck_fetch.sh + + - run: + name: Build & Test React Native using Buck + command: | + buck build ReactAndroid/src/main/java/com/facebook/react + buck build ReactAndroid/src/main/java/com/facebook/react/shell + + - run: + name: Run Tests - Android Unit Tests with Buck + command: buck test ReactAndroid/src/test/... --config build.threads=$BUILD_THREADS --xml ./reports/buck/all-results-raw.xml + + - run: + name: Build JavaScript Bundle for instrumentation tests + command: node cli.js bundle --max-workers 2 --platform android --dev true --entry-file ReactAndroid/src/androidTest/js/TestBundle.js --bundle-output ReactAndroid/src/androidTest/assets/AndroidTestBundle.js + + - run: + name: Build Tests - Android Instrumentation Tests with Buck + # Here, just build the instrumentation tests. There is a known issue with installing the APK to android-21+ emulator. + command: | + if [[ ! -e ReactAndroid/src/androidTest/assets/AndroidTestBundle.js ]]; then + echo "JavaScript bundle missing, cannot run instrumentation tests. Verify Build JavaScript Bundle step completed successfully."; exit 1; + fi + source scripts/android-setup.sh && NO_BUCKD=1 scripts/retry3 timeout 300 buck build ReactAndroid/src/androidTest/buck-runner:instrumentation-tests --config build.threads=$BUILD_THREADS + + - run: + name: Collect Test Results + command: | + find . -type f -regex ".*/build/test-results/debug/.*xml" -exec cp {} ./reports/build/ \; + find . -type f -regex ".*/outputs/androidTest-results/connected/.*xml" -exec cp {} ./reports/outputs/ \; + find . -type f -regex ".*/buck-out/gen/ReactAndroid/src/test/.*/.*xml" -exec cp {} ./reports/buck/ \; + if [ -f ~/react-native/reports/buck/all-results-raw.xml ]; then + ~/react-native/scripts/circleci/buckToJunit/buckToJunit.sh ~/react-native/reports/buck/all-results-raw.xml ~/react-native/reports/junit/results.xml + fi + when: always + + - store_test_results: + path: ./reports/junit + # ------------------------- # JOBS: Test Android # ------------------------- @@ -476,11 +718,6 @@ jobs: - setup_artifacts - run_yarn - # Validate Android SDK installation and packages - - run: - name: Validate Android SDK Install - command: ./scripts/validate-android-sdk.sh - # Starting emulator in advance as it takes some time to boot. - run: name: Create Android Virtual Device @@ -490,55 +727,23 @@ jobs: command: source scripts/android-setup.sh && launchAVD background: true - # Install Buck - - install_buck_tooling - - # Validate Android test environment (including Buck) - - run: - name: Validate Android Test Environment - command: ./scripts/validate-android-test-env.sh - - - download_buck_dependencies - download_gradle_dependencies - # Build and compile - run: - name: Build Android App - command: | - buck build ReactAndroid/src/main/java/com/facebook/react - buck build ReactAndroid/src/main/java/com/facebook/react/shell - - run: - name: Compile Native Libs for Unit and Integration Tests - command: ./gradlew :ReactAndroid:packageReactNdkLibsForBuck -Pjobs=$BUILD_THREADS - no_output_timeout: 30m + name: Build & Test React Native using Gradle + command: ./gradlew buildAll - # Build JavaScript Bundle for instrumentation tests - run: - name: Build JavaScript Bundle - command: node cli.js bundle --max-workers 2 --platform android --dev true --entry-file ReactAndroid/src/androidTest/js/TestBundle.js --bundle-output ReactAndroid/src/androidTest/assets/AndroidTestBundle.js + name: Build RN Tester for Release using Gradle + command: ./gradlew packages:rn-tester:android:app:assembleRelease # Wait for AVD to finish booting before running tests - run: name: Wait for Android Virtual Device command: source scripts/android-setup.sh && waitForAVD - - run: - name: Assemble RNTester App - command: ./gradlew packages:rn-tester:android:app:assembleRelease - - # ------------------------- - # Run Android tests - - run: - name: "Run Tests: Android Unit Tests" - command: buck test ReactAndroid/src/test/... --config build.threads=$BUILD_THREADS --xml ./reports/buck/all-results-raw.xml - - run: - name: "Build Tests: Android Instrumentation Tests" - # Here, just build the instrumentation tests. There is a known issue with installing the APK to android-21+ emulator. - command: | - if [[ ! -e ReactAndroid/src/androidTest/assets/AndroidTestBundle.js ]]; then - echo "JavaScript bundle missing, cannot run instrumentation tests. Verify Build JavaScript Bundle step completed successfully."; exit 1; - fi - source scripts/android-setup.sh && NO_BUCKD=1 retry3 timeout 300 buck build ReactAndroid/src/androidTest/buck-runner:instrumentation-tests --config build.threads=$BUILD_THREADS + - report_bundle_size: + platform: android # Optionally, run disabled tests - when: @@ -547,81 +752,114 @@ jobs: - run: echo "Failing tests may be moved here temporarily." - run_e2e: platform: android - # ------------------------- - - # Collect Results - - report_bundle_size: - platform: android - - run: - name: Collect Test Results - command: | - find . -type f -regex ".*/build/test-results/debug/.*xml" -exec cp {} ./reports/build/ \; - find . -type f -regex ".*/outputs/androidTest-results/connected/.*xml" -exec cp {} ./reports/outputs/ \; - find . -type f -regex ".*/buck-out/gen/ReactAndroid/src/test/.*/.*xml" -exec cp {} ./reports/buck/ \; - if [ -f ~/react-native/reports/buck/all-results-raw.xml ]; then - cd ~/okbuck - ./tooling/junit/buck_to_junit.sh ~/react-native/reports/buck/all-results-raw.xml ~/react-native/reports/junit/results.xml - fi - when: always - - store_test_results: - path: ./reports/junit # ------------------------- # JOBS: Test Android Template # ------------------------- test_android_template: executor: reactnativeandroid + parameters: + flavor: + default: "Debug" + description: The Android build type. Must be one of "Debug", "Release". + type: enum + enum: ["Debug", "Release"] + architecture: + default: "OldArch" + description: Which React Native architecture to use. Must be one of "NewArch", "OldArch". + type: enum + enum: [ "NewArch", "OldArch" ] + jsengine: + default: "Hermes" + description: Which JavaScript engine to use. Must be one of "Hermes", "JSC". + type: enum + enum: ["Hermes", "JSC"] + environment: + - PROJECT_NAME: "AndroidTemplateProject" steps: - - checkout + - checkout_code_with_cache - run_yarn - attach_workspace: at: . - - run: name: Create Android template project command: | REPO_ROOT=$(pwd) - PACKAGE=$(cat build/react-native-package-version) - PATH_TO_PACKAGE="$REPO_ROOT/build/$PACKAGE" - cd template - npm add $PATH_TO_PACKAGE - npm install + node ./scripts/set-rn-template-version.js "file:$REPO_ROOT/build/$(cat build/react-native-package-version)" + node cli.js init $PROJECT_NAME --directory "/tmp/$PROJECT_NAME" --template $REPO_ROOT --verbose --skip-install + cd /tmp/$PROJECT_NAME + yarn - run: - name: Build the template application - command: cd template/android/ && ./gradlew assembleDebug - - # ------------------------- - # JOBS: Test Android RNTester - # ------------------------- - test_android_rntester: - executor: reactnativeandroid - steps: - - checkout - - run_yarn - - - run: - name: Generate artifacts for Maven - command: ./gradlew :ReactAndroid:installArchives - - - run: - name: Assemble RNTester - command: ./gradlew :packages:rn-tester:android:app:assembleDebug + name: Build the template application for << parameters.flavor >> with Architecture set to << parameters.architecture >>, and using the << parameters.jsengine>> JS engine. + command: | + cd /tmp/$PROJECT_NAME/android/ + if [[ << parameters.architecture >> == "NewArch" ]]; then + export ORG_GRADLE_PROJECT_newArchEnabled=true + else + export ORG_GRADLE_PROJECT_newArchEnabled=false + fi + if [[ << parameters.jsengine >> == "Hermes" ]]; then + export ORG_GRADLE_PROJECT_hermesEnabled=true + else + export ORG_GRADLE_PROJECT_hermesEnabled=false + fi + ./gradlew assemble<< parameters.flavor >> -PREACT_NATIVE_MAVEN_LOCAL_REPO=/root/react-native/maven-local # ------------------------- # JOBS: Test iOS Template # ------------------------- test_ios_template: executor: reactnativeios + parameters: + flavor: + default: "Debug" + description: The Xcode build type. Must be one of "Debug", "Release". + type: enum + enum: ["Debug", "Release"] + architecture: + default: "OldArch" + description: Which React Native architecture to use. Must be one of "NewArch", "OldArch". + type: enum + enum: ["NewArch", "OldArch"] + jsengine: + default: "Hermes" + description: Which JavaScript engine to use. Must be one of "Hermes", "JSC". + type: enum + enum: ["Hermes", "JSC"] + flipper: + default: "WithFlipper" + description: Whether Flipper is enabled. Must be one of "WithFlipper", "WithoutFlipper". + type: enum + enum: ["WithFlipper", "WithoutFlipper"] environment: - PROJECT_NAME: "iOSTemplateProject" - + - HERMES_WS_DIR: *hermes_workspace_root steps: - - checkout + # Early exit in case of Release and WithFlipper. The two does not make sense together. + # Unfortunately, the `exclude` parameter of `matrix` does not work, so we have to do it manually. + - when: + condition: + and: + - equal: [ << parameters.flavor >>, "Release"] + - equal: [ << parameters.flipper >>, "WithFlipper" ] + steps: + - run: + command: circleci-agent step halt # this interrupts the job successfully. + # Valid configuration, we can continue + - checkout_code_with_cache - run_yarn - attach_workspace: at: . - + - *attach_hermes_workspace + - when: + condition: + equal: ["Hermes", << parameters.jsengine >>] + steps: + - run: + name: Set HERMES_ENGINE_TARBALL_PATH + command: | + echo "export HERMES_ENGINE_TARBALL_PATH=$(ls -AU $HERMES_WS_DIR/hermes-runtime-darwin/hermes-runtime-darwin-*.tar.gz | head -1)" >> $BASH_ENV - run: name: Create iOS template project command: | @@ -629,15 +867,39 @@ jobs: PACKAGE=$(cat build/react-native-package-version) PATH_TO_PACKAGE="$REPO_ROOT/build/$PACKAGE" node ./scripts/set-rn-template-version.js "file:$PATH_TO_PACKAGE" - mkdir -p ~/tmp - cd ~/tmp - node "$REPO_ROOT/cli.js" init "$PROJECT_NAME" --template "$REPO_ROOT" + node cli.js init $PROJECT_NAME --directory "/tmp/$PROJECT_NAME" --template $REPO_ROOT --verbose --skip-install + - run: + name: Install iOS dependencies - Configuration << parameters.flavor >>; New Architecture << parameters.architecture >>; JS Engine << parameters.jsengine>>; Flipper << parameters.flipper >> + command: | + cd /tmp/$PROJECT_NAME + yarn install + cd ios + + bundle install + + if [[ << parameters.flavor >> == "Release" ]]; then + export PRODUCTION=1 + fi + + if [[ << parameters.architecture >> == "NewArch" ]]; then + export RCT_NEW_ARCH_ENABLED=1 + fi + + if [[ << parameters.jsengine >> == "JSC" ]]; then + export USE_HERMES=0 + fi + + if [[ << parameters.flipper >> == "WithoutFlipper" ]]; then + export NO_FLIPPER=1 + fi + bundle exec pod install - run: name: Build template project command: | xcodebuild build \ - -workspace ~/tmp/$PROJECT_NAME/ios/$PROJECT_NAME.xcworkspace \ + -configuration << parameters.flavor >> \ + -workspace /tmp/$PROJECT_NAME/ios/$PROJECT_NAME.xcworkspace \ -scheme $PROJECT_NAME \ -sdk iphonesimulator @@ -647,25 +909,46 @@ jobs: test_ios_rntester: executor: reactnativeios parameters: - use_hermes: - type: boolean - default: false + jsengine: + default: "Hermes" + description: Which JavaScript engine to use. Must be one of "Hermes", "JSC". + type: enum + enum: ["Hermes", "JSC"] + architecture: + default: "OldArch" + description: Which React Native architecture to use. Must be one of "OldArch", "NewArch". + type: enum + enum: ["NewArch", "OldArch"] steps: - - checkout + - checkout_code_with_cache - run_yarn + - *attach_hermes_workspace - - when: - condition: << parameters.use_hermes >> + # The macOS machine can run out of storage if Hermes is enabled and built from source. + # Since this job does not use the iOS Simulator, deleting it provides a quick way to + # free up space. + - run: + name: Delete iOS Simulators + background: true + command: sudo rm -rf /Library/Developer/CoreSimulator/Profiles/Runtimes/ + + - with_hermes_tarball_cache_span: + set_tarball_path: True steps: - run: - name: Set USE_HERMES=1 - command: echo "export USE_HERMES=1" >> $BASH_ENV + name: Install CocoaPods dependencies - Architecture << parameters.architecture >> + command: | + rm -rf packages/rn-tester/Pods - - run: - name: Install CocoaPods dependencies - command: | - rm -rf packages/rn-tester/Pods - cd packages/rn-tester && bundle exec pod install + if [[ << parameters.architecture >> == "NewArch" ]]; then + export RCT_NEW_ARCH_ENABLED=1 + fi + + if [[ << parameters.jsengine >> == "JSC" ]]; then + export USE_HERMES=0 + fi + + cd packages/rn-tester && bundle exec pod install - run: name: Build RNTester @@ -692,19 +975,22 @@ jobs: - ANDROID_TOOLS_VERSION: 31.0.0 - GRADLE_OPTS: -Dorg.gradle.daemon=false steps: - - checkout + - checkout_code_with_cache + + - run: + name: Disable NVM + # Use choco to manage node versions due to https://github.com/npm/cli/issues/4234 + command: nvm off - run: - name: Install Node + name: Install Node JS # Note: Version set separately for non-Windows builds, see above. - command: | - nvm install 16 - nvm use 16 + command: choco install nodejs-lts # Setup Dependencies - run: - name: Install Yarn - command: choco install yarn + name: Enable Yarn with corepack + command: corepack enable - run: name: Display Environment info @@ -712,12 +998,12 @@ jobs: - restore_cache: keys: - - v1-win-yarn-cache-{{ arch }}-{{ checksum "yarn.lock" }} + - *windows_yarn_cache_key - run: name: "Yarn: Install Dependencies" command: yarn install --frozen-lockfile --non-interactive - save_cache: - key: v1-win-yarn-cache-{{ arch }}-{{ checksum "yarn.lock" }} + key: *windows_yarn_cache_key paths: - C:\Users\circleci\AppData\Local\Yarn @@ -777,12 +1063,291 @@ jobs: name: Collect test coverage information command: | scripts/circleci/exec_swallow_error.sh yarn test --coverage --maxWorkers=2 - if [[ -e ./coverage/lcov.info ]]; then - cat ./coverage/lcov.info | scripts/circleci/exec_swallow_error.sh ./node_modules/.bin/coveralls - fi - store_artifacts: path: ~/react-native/coverage/ + # ------------------------- + # JOBS: Build Hermes + # ------------------------- + prepare_hermes_workspace: + docker: + - image: debian:11 + environment: + - HERMES_WS_DIR: *hermes_workspace_root + - HERMES_VERSION_FILE: "sdks/.hermesversion" + steps: + - run: + name: Install dependencies + command: | + apt update + apt install -y wget git curl + curl -sL https://deb.nodesource.com/setup_16.x | bash - + apt install -y nodejs + npm install --global yarn + - checkout + - run_yarn + - run: + name: Set up Hermes workspace and caching + command: | + mkdir -p "/tmp/hermes" "/tmp/hermes/download" "/tmp/hermes/hermes" + + if [ -f "$HERMES_VERSION_FILE" ]; then + cat $HERMES_VERSION_FILE > /tmp/hermes/hermesversion + else + HERMES_TAG_SHA=$(git ls-remote https://github.com/facebook/hermes main | cut -f 1 | tr -d '[:space:]') + echo $HERMES_TAG_SHA > /tmp/hermes/hermesversion + fi + cat /tmp/hermes/hermesversion + - restore_cache: + key: *hermes_workspace_cache_key + - run: + name: Download Hermes tarball + command: | + node scripts/hermes/prepare-hermes-for-build $CIRCLE_PULL_REQUEST + cp sdks/download/* $HERMES_WS_DIR/download/. + cp -r sdks/hermes/* $HERMES_WS_DIR/hermes/. + + cat /tmp/hermes/hermesversion + - save_cache: + key: *hermes_workspace_cache_key + paths: + - /tmp/hermes/download/ + - /tmp/hermes/hermes/ + - persist_to_workspace: + root: *hermes_workspace_root + paths: + - download + - hermes + - hermesversion + + build_hermesc_linux: + docker: + - image: debian:bullseye + # [macOS] Change resource_class to large as we're on the free CircleCI plan + resource_class: "large" + working_directory: /root + steps: + - run: + name: Install dependencies + command: | + apt update + apt install -y git openssh-client cmake build-essential \ + libreadline-dev libicu-dev zip python3 + - *attach_hermes_workspace + - restore_cache: + key: *hermes_workspace_cache_key + - run: + name: Set up workspace + command: | + mkdir -p /tmp/hermes/linux64-bin + - run: + name: Build HermesC for Linux + command: | + if [ -f /tmp/hermes/linux64-bin/hermesc ]; then + echo 'Skipping; Clean "/tmp/hermes/linux64-bin" to rebuild.' + else + cd /tmp/hermes + cmake -S hermes -B build -DHERMES_STATIC_LINK=ON -DCMAKE_BUILD_TYPE=Release \ + -DCMAKE_INTERPROCEDURAL_OPTIMIZATION=True -DCMAKE_CXX_FLAGS=-s -DCMAKE_C_FLAGS=-s \ + -DCMAKE_EXE_LINKER_FLAGS="-Wl,--whole-archive -lpthread -Wl,--no-whole-archive" + cmake --build build --target check-hermes -j 4 + cp /tmp/hermes/build/bin/hermesc /tmp/hermes/linux64-bin/. + fi + - save_cache: + key: *hermes_workspace_cache_key + paths: + - /tmp/hermes/linux64-bin/ + - /tmp/hermes/hermes/destroot/ + - store_artifacts: + path: /tmp/hermes/linux64-bin/ + - persist_to_workspace: + root: /tmp/hermes/ + paths: + - linux64-bin + + build_hermes_macos: + parameters: + flavor: + default: "Debug" + description: The Hermes build type. Must be one of "Debug", "Release". + type: enum + enum: ["Debug", "Release"] + executor: reactnativeios + environment: + - HERMES_WS_DIR: *hermes_workspace_root + - HERMES_TARBALL_ARTIFACTS_DIR: *hermes_tarball_artifacts_dir + - HERMES_OSXBIN_ARTIFACTS_DIR: *hermes_osxbin_artifacts_dir + steps: + - checkout_code_with_cache + - run_yarn + - *attach_hermes_workspace + - when: + condition: + equal: [ << parameters.flavor >>, "Debug"] + steps: + - restore_cache: + keys: + - *hermes_workspace_debug_cache_key + - when: + condition: + equal: [ << parameters.flavor >>, "Release"] + steps: + - restore_cache: + keys: + - *hermes_workspace_release_cache_key + - run: + name: Set up workspace + command: | + mkdir -p $HERMES_OSXBIN_ARTIFACTS_DIR ./sdks/hermes + cp -r $HERMES_WS_DIR/hermes/* ./sdks/hermes/. + - brew_install: + package: cmake + - with_hermes_tarball_cache_span: + flavor: << parameters.flavor >> + steps: + - with_hermesc_span: + flavor: << parameters.flavor >> + steps: + - run: + name: Build the Hermes Mac frameworks + command: | + cd ./sdks/hermes || exit 1 + BUILD_TYPE="<< parameters.flavor >>" ./utils/build-mac-framework.sh + - with_hermesc_span: + flavor: << parameters.flavor >> + steps: + - run: + name: Build the Hermes iOS frameworks + command: | + cd ./sdks/hermes || exit 1 + BUILD_TYPE="<< parameters.flavor >>" ./utils/build-ios-framework.sh + - run: + name: Package the Hermes Apple frameworks + command: | + BUILD_TYPE="<< parameters.flavor >>" + echo "Packaging Hermes Apple frameworks for $BUILD_TYPE build type" + + TARBALL_OUTPUT_DIR=$(mktemp -d /tmp/hermes-tarball-output-XXXXXXXX) + + # get_release_version() is defined in build-apple-framework.sh + pushd ./sdks/hermes || exit 1 + BUILD_TYPE=$BUILD_TYPE source ./utils/build-apple-framework.sh + RELEASE_VERSION=$(get_release_version) + popd + + TARBALL_FILENAME=$(node ./scripts/hermes/get-tarball-name.js --buildType "$BUILD_TYPE" --releaseVersion "$RELEASE_VERSION") + + echo "Packaging Hermes Apple frameworks for $BUILD_TYPE build type" + + TARBALL_OUTPUT_PATH=$(node ./scripts/hermes/create-tarball.js \ + --inputDir ./sdks/hermes \ + --buildType "$BUILD_TYPE" \ + --releaseVersion "$RELEASE_VERSION" \ + --outputDir $TARBALL_OUTPUT_DIR) + + echo "Hermes tarball saved to $TARBALL_OUTPUT_PATH" + + mkdir -p $HERMES_TARBALL_ARTIFACTS_DIR + cp $TARBALL_OUTPUT_PATH $HERMES_TARBALL_ARTIFACTS_DIR/. + - when: + condition: + equal: [ << parameters.flavor >>, "Debug"] + steps: + - save_cache: + key: *hermes_workspace_debug_cache_key + paths: *hermes_workspace_macos_cache_paths + - when: + condition: + equal: [ << parameters.flavor >>, "Release"] + steps: + - save_cache: + key: *hermes_workspace_release_cache_key + paths: *hermes_workspace_macos_cache_paths + - store_artifacts: + path: *hermes_tarball_artifacts_dir + - store_artifacts: + path: *hermes_osxbin_artifacts_dir + - persist_to_workspace: + root: /tmp/hermes/ + paths: + - hermes-runtime-darwin + - osx-bin + + build_hermesc_windows: + executor: + name: win/default + shell: powershell.exe + environment: + - HERMES_WS_DIR: 'C:\tmp\hermes' + - ICU_URL: "https://github.com/unicode-org/icu/releases/download/release-64-2/icu4c-64_2-Win64-MSVC2017.zip" + - MSBUILD_DIR: 'C:\Program Files (x86)\Microsoft Visual Studio\2019\BuildTools\MSBuild\Current\Bin' + - CMAKE_DIR: 'C:\Program Files\CMake\bin' + steps: + - *attach_hermes_workspace + - restore_cache: + key: *hermes_windows_cache_key + - run: + name: Set up workspace + command: | + New-Item -ItemType Directory $Env:HERMES_WS_DIR + New-Item -ItemType Directory $Env:HERMES_WS_DIR\icu + New-Item -ItemType Directory $Env:HERMES_WS_DIR\deps + New-Item -ItemType Directory $Env:HERMES_WS_DIR\win64-bin + New-Item -ItemType SymbolicLink -Target tmp\hermes\hermes -Path $Env:HERMES_WS_DIR -Name hermes + - run: + name: Build HermesC for Windows + command: | + if (-not(Test-Path -Path $Env:HERMES_WS_DIR\win64-bin\hermesc.exe)) { + choco install --no-progress cmake --version 3.14.7 + if (-not $?) { throw "Failed to install CMake" } + choco install --no-progress python3 + if (-not $?) { throw "Failed to install Python" } + + cd $Env:HERMES_WS_DIR\icu + # If Invoke-WebRequest shows a progress bar, it will fail with + # Win32 internal error "Access is denied" 0x5 occurred [...] + $progressPreference = 'silentlyContinue' + Invoke-WebRequest -Uri "$Env:ICU_URL" -OutFile "icu.zip" + Expand-Archive -Path "icu.zip" -DestinationPath "." + + cd $Env:HERMES_WS_DIR + Copy-Item -Path "icu\bin64\icu*.dll" -Destination "deps" + # Include MSVC++ 2015 redistributables + Copy-Item -Path "c:\windows\system32\msvcp140.dll" -Destination "deps" + Copy-Item -Path "c:\windows\system32\vcruntime140.dll" -Destination "deps" + Copy-Item -Path "c:\windows\system32\vcruntime140_1.dll" -Destination "deps" + + $Env:PATH += ";$Env:CMAKE_DIR;$Env:MSBUILD_DIR" + $Env:ICU_ROOT = "$Env:HERMES_WS_DIR\icu" + + cmake -S hermes -B build_release -G 'Visual Studio 16 2019' -Ax64 -DCMAKE_BUILD_TYPE=Release -DCMAKE_INTERPROCEDURAL_OPTIMIZATION=True -DHERMES_ENABLE_WIN10_ICU_FALLBACK=OFF + if (-not $?) { throw "Failed to configure Hermes" } + cd build_release + cmake --build . --target hermesc --config Release + if (-not $?) { throw "Failed to build Hermes" } + + cd $Env:HERMES_WS_DIR + Copy-Item -Path "build_release\bin\Release\hermesc.exe" -Destination "win64-bin" + # Include Windows runtime dependencies + Copy-Item -Path "deps\*" -Destination "win64-bin" + } + else { + Write-Host "Skipping; Clean c:\tmp\hermes\win64-bin to rebuild." + } + - save_cache: + key: *hermes_windows_cache_key + paths: + - C:\tmp\hermes\win64-bin\ + - C:\tmp\hermes\hermes\icu\ + - C:\tmp\hermes\hermes\deps\ + - C:\tmp\hermes\hermes\build_release\ + - store_artifacts: + path: C:\tmp\hermes\win64-bin\ + - persist_to_workspace: + root: C:\tmp\hermes\ + paths: + - win64-bin + # ------------------------- # JOBS: Releases # ------------------------- @@ -793,24 +1358,33 @@ jobs: latest: type: boolean default: false + dryrun: + type: boolean + default: false executor: reactnativeios steps: - - checkout + - checkout_code_with_cache - run_yarn - add_ssh_keys: fingerprints: - "1c:98:e0:3a:52:79:95:29:12:cd:b4:87:5b:41:e2:bb" + - brew_install: + package: cmake - run: name: "Set new react-native version and commit changes" command: | - node ./scripts/prepare-package-for-release.js -v << parameters.version >> -l << parameters.latest >> + node ./scripts/prepare-package-for-release.js -v << parameters.version >> -l << parameters.latest >> --dry-run << parameters.dryrun >> build_npm_package: parameters: - publish_npm_args: - type: string - default: --dry-run + release_type: + description: The type of release to build. Must be one of "nightly", "release", "dry-run". + type: enum + enum: ["nightly", "release", "dry-run"] + default: "dry-run" executor: reactnativeandroid + environment: + - HERMES_WS_DIR: *hermes_workspace_root steps: - run: name: Add github.com to SSH known hosts @@ -818,26 +1392,69 @@ jobs: mkdir -p ~/.ssh echo '|1|If6MU203eXTaaWL678YEfWkVMrw=|kqLeIAyTy8pzpj8x8Ae4Fr8Mtlc= ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAq2A7hRGmdnm9tUDbO9IDSwBK6TbQa+PXYPCPy6rbTrTtw7PHkccKrpp0yVhp5HdEIcKr6pLlVDBfOLX9QUsyCOV0wzfjIJNlGEYsdlLJizHhbn2mUjvSAHQqZETYP81eFzLQNnPHt4EVVUh7VfDESU84KezmD5QlWpXLmvU31/yMf+Se8xhHTvKSCZIFImWwoG6mbUoWf9nzpIoaSjB+weqqUUmpaaasXVal72J+UX2B+2RPW3RcT0eOzQgqlJL3RKrTJvdsjE3JEAvGq3lGHSZXy28G3skua2SmVi/w4yCE6gbODqnTWlg7+wC604ydGXA8VJiS5ap43JXiUFFAaQ==' >> ~/.ssh/known_hosts - checkout + - *attach_hermes_workspace + - run: + name: Copy Hermes binaries + command: | + mkdir -p ./sdks/hermesc ./sdks/hermesc/osx-bin ./sdks/hermesc/win64-bin ./sdks/hermesc/linux64-bin + + # When build_hermes_macos runs as a matrix, it outputs + if [[ -d $HERMES_WS_DIR/osx-bin/Release ]]; then + cp -r $HERMES_WS_DIR/osx-bin/Release/* ./sdks/hermesc/osx-bin/. + elif [[ -d $HERMES_WS_DIR/osx-bin/Debug ]]; then + cp -r $HERMES_WS_DIR/osx-bin/Debug/* ./sdks/hermesc/osx-bin/. + else + ls $HERMES_WS_DIR/osx-bin || echo "hermesc macOS artifacts directory missing." + echo "Could not locate macOS hermesc binary."; exit 1; + fi + + cp -r $HERMES_WS_DIR/win64-bin/* ./sdks/hermesc/win64-bin/. + cp -r $HERMES_WS_DIR/linux64-bin/* ./sdks/hermesc/linux64-bin/. + mkdir -p ./ReactAndroid/external-artifacts/artifacts/ + cp $HERMES_WS_DIR/hermes-runtime-darwin/hermes-runtime-darwin-debug-*.tar.gz ./ReactAndroid/external-artifacts/artifacts/hermes-ios-debug.tar.gz + cp $HERMES_WS_DIR/hermes-runtime-darwin/hermes-runtime-darwin-release-*.tar.gz ./ReactAndroid/external-artifacts/artifacts/hermes-ios-release.tar.gz + - run_yarn - - install_buck_tooling - - download_buck_dependencies - download_gradle_dependencies - # Only tagged releases and nightlies should be able to publish to npm + + # START: Stables and nightlies + # This conditional step sets up the necessary credentials for publishing react-native to npm, + # and for interacting with GitHub as the react-native-bot account. Important: these steps + # should not be allowed to run on commits from pull requests. - when: condition: or: - - equal: [ --release, << parameters.publish_npm_args >> ] - - equal: [ --nightly, << parameters.publish_npm_args >> ] + - equal: [ "release", << parameters.release_type >> ] + - equal: [ "nightly", << parameters.release_type >> ] steps: - run: echo "//registry.npmjs.org/:_authToken=${CIRCLE_NPM_TOKEN}" > ~/.npmrc - run: | git config --global user.email "react-native-bot@users.noreply.github.com" git config --global user.name "npm Deployment Script" echo "machine github.com login react-native-bot password $GITHUB_TOKEN" > ~/.netrc - - run: node ./scripts/publish-npm.js << parameters.publish_npm_args >> + # END: Stables and nightlies + + - run: node ./scripts/publish-npm.js --<< parameters.release_type >> + - run: + name: Zip Hermes Native Symbols + command: zip -r /tmp/hermes-native-symbols.zip ~/react-native/ReactAndroid/hermes-engine/build/intermediates/cmake/ + - store_artifacts: + path: /tmp/hermes-native-symbols.zip + - run: + name: Zip Maven Artifacts from /tmp/maven-local + command: zip -r /tmp/maven-local.zip /tmp/maven-local + - store_artifacts: + path: /tmp/maven-local.zip + - persist_to_workspace: + root: /tmp + paths: + - maven-local + + # START: Commitlies + # Provide a react-native package for this commit as a Circle CI release artifact. - when: condition: - equal: [ --dry-run, << parameters.publish_npm_args >> ] + equal: [ "dry-run", << parameters.release_type >> ] steps: - run: name: Build release package as a job artifact @@ -853,19 +1470,23 @@ jobs: root: . paths: - build/* + # END: Commitlies + # START: Commits from pull requests + # When building commits from pull requests, leave a comment on the PR with a link to build artifacts - when: condition: matches: { pattern: '^pull\/.*$', value: << pipeline.git.branch >> } steps: - - install_github_bot_deps - run: name: Post link to PR build artifacts (pull-bot) command: GITHUB_TOKEN="$PUBLIC_PULLBOT_GITHUB_TOKEN_A""$PUBLIC_PULLBOT_GITHUB_TOKEN_B" scripts/circleci/post-artifacts-link.sh || true + # END: Commits from pull requests + # START: Stable releases - when: condition: - equal: [ --release, << parameters.publish_npm_args >> ] + equal: [ "release", << parameters.release_type >> ] steps: - run: name: Update rn-diff-purge to generate upgrade-support diff @@ -874,6 +1495,44 @@ jobs: -H "Accept: application/vnd.github.v3+json" \ -u "$PAT_USERNAME:$PAT_TOKEN" \ -d "{\"event_type\": \"publish\", \"client_payload\": { \"version\": \"${CIRCLE_TAG:1}\" }}" + # END: Stable releases + + # START: Stables and commitlies + - when: + condition: + or: + - equal: [ "release", << parameters.release_type >> ] + - equal: [ "dry-run", << parameters.release_type >> ] + steps: + - run: + name: Install dependencies + command: apt update && apt install -y jq jo + - run: + name: Create draft GitHub Release and upload Hermes binaries + command: | + RELEASE_VERSION=$(cat build/.version) + if [[ << parameters.release_type >> == "release" ]]; then + GIT_TAG=$CIRCLE_TAG + elif [[ << parameters.release_type >> == "dry-run" ]]; then + GIT_TAG=v1000.0.0 + fi + + ARTIFACTS=("") + for build_type in "Debug" "Release"; do + TARBALL_FILENAME=$(node ./scripts/hermes/get-tarball-name.js \ + --buildType $build_type \ + --releaseVersion $RELEASE_VERSION) + + ARTIFACTS+=("$HERMES_WS_DIR/hermes-runtime-darwin/$TARBALL_FILENAME") + done + + ./scripts/circleci/create_github_release.sh \ + << parameters.release_type >> \ + $GIT_TAG \ + $RELEASE_VERSION \ + $GITHUB_TOKEN \ + "${ARTIFACTS[@]}" + # END: Stable and commitlies # ------------------------- # JOBS: Nightly @@ -917,99 +1576,81 @@ workflows: tests: unless: << pipeline.parameters.run_package_release_workflow_only >> jobs: - - build_npm_package: - # Build a release package on every untagged commit, but do not publish to npm. - publish_npm_args: --dry-run - # [macOS Disable this failing test - filters: - branches: - ignore: /.*/ - # macOS] - - test_js: - run_disabled_tests: false - filters: - branches: - ignore: gh-pages - - test_android: - run_disabled_tests: false - # [macOS Disable this failing test - filters: - branches: - ignore: /.*/ - # macOS] - - test_android_template: + - prepare_hermes_workspace + - build_hermesc_linux: requires: - - build_npm_package - # [macOS Disable this failing test - filters: - branches: - ignore: /.*/ - # macOS] - - test_android_rntester: - filters: - branches: - ignore: /.*/ # [macOS] Disable this failing test - - test_ios_template: + - prepare_hermes_workspace + # [macOS Disable failing test + # - build_hermes_macos: + # requires: + # - prepare_hermes_workspace + # matrix: + # parameters: + # flavor: ["Debug", "Release"] + # [macOS Disable failing test + - build_hermesc_windows: requires: - - build_npm_package - # [macOS Disable this failing test - filters: - branches: - ignore: /.*/ - # macOS] - - test_ios_rntester: - name: test_ios_rntester_hermes - use_hermes: true - # [macOS Disable this failing test - filters: - branches: - ignore: /.*/ - # macOS] - - test_ios_rntester: - name: test_ios_rntester_jsc - # [macOS Disable this failing test - filters: - branches: - ignore: /.*/ - # macOS] - - test_ios: - name: test_ios_unit_jsc - run_unit_tests: true - # [macOS Disable this failing test - filters: - branches: - ignore: /.*/ - # macOS] - # DISABLED: USE_FRAMEWORKS=1 not supported by Flipper + - prepare_hermes_workspace + # [macOS Disable failing test + # - build_npm_package: + # # Build a release package on every untagged commit, but do not publish to npm. + # release_type: "dry-run" + # requires: + # - build_hermesc_linux + # # - build_hermes_macos # [macOS] Comment out failing test requirement + # - build_hermesc_windows + # macOS] + - test_js: + run_disabled_tests: false + # [macOS Comment out failing test + # - test_android: + # run_disabled_tests: false + # - test_android_template: + # requires: + # - build_npm_package + # matrix: + # parameters: + # architecture: ["NewArch", "OldArch"] + # jsengine: ["Hermes", "JSC"] + # flavor: ["Debug", "Release"] + # macOS] + - test_buck + # [macOS Comment out failing test + # - test_ios_template: + # requires: + # - build_npm_package + # matrix: + # parameters: + # architecture: ["NewArch", "OldArch"] + # flavor: ["Debug", "Release"] + # jsengine: ["Hermes", "JSC"] + # flipper: ["WithFlipper", "WithoutFlipper"] + # - test_ios_rntester: + # requires: + # - build_hermes_macos + # matrix: + # parameters: + # architecture: ["NewArch", "OldArch"] + # jsengine: ["Hermes", "JSC"] # - test_ios: - # name: test_ios_unit_frameworks_jsc - # use_frameworks: true # run_unit_tests: true - - test_ios: - name: test_ios_unit_hermes - use_hermes: true - run_unit_tests: true - # [macOS Disable this failing test - filters: - branches: - ignore: /.*/ - # macOS] + # requires: + # - build_hermes_macos + # matrix: + # parameters: + # jsengine: ["Hermes", "JSC"] + # macOS] # DISABLED: USE_FRAMEWORKS=1 not supported by Flipper # - test_ios: - # name: test_ios_unit_frameworks_hermes - # use_hermes: true + # name: test_ios_frameworks # use_frameworks: true # run_unit_tests: true + # requires: + # - build_ios_frameworks - test_js: name: test_js_prev_lts executor: nodeprevlts - filters: - branches: - ignore: gh-pages - test_windows: - filters: - branches: - ignore: /.*/ # [macOS] Disable this failing test run_disabled_tests: false # This workflow should only be triggered by release script @@ -1025,45 +1666,78 @@ workflows: publish_release: unless: << pipeline.parameters.run_package_release_workflow_only >> jobs: + - prepare_hermes_workspace: + filters: *only_release_tags + - build_hermesc_linux: + filters: *only_release_tags + requires: + - prepare_hermes_workspace + - build_hermes_macos: + filters: *only_release_tags + requires: + - prepare_hermes_workspace + matrix: + parameters: + flavor: ["Debug", "Release"] + - build_hermesc_windows: + filters: *only_release_tags + requires: + - prepare_hermes_workspace # This job will trigger when a version tag is pushed (by package_release) - build_npm_package: name: build_and_publish_npm_package context: react-native-bot - publish_npm_args: --release - # CircleCI filters are OR-ed, with all branches triggering by default and tags excluded by default - # CircleCI env-vars are only set with the branch OR tag that triggered the job, not both. - # In this case, CIRCLE_BRANCH is unset, but CIRCLE_TAG is set - filters: - # Both of the following conditions must be included! - # Ignore any commit on any branch by default. - branches: - ignore: /.*/ - # Only act on version tags. - tags: - only: /v[0-9]+(\.[0-9]+)*(\-rc(\.[0-9]+)?)?/ + release_type: "release" + filters: *only_release_tags + requires: + - build_hermesc_linux + - build_hermes_macos + - build_hermesc_windows + + # [macOS Disable failing workflow + # package_and_publish_release_dryrun: + # jobs: + # - prepare_package_for_release: + # name: prepare_package_for_release + # version: 'v1000.0.1' + # latest : false + # dryrun: true + # - prepare_hermes_workspace: + # requires: + # - prepare_package_for_release + # - build_hermesc_linux: + # requires: + # - prepare_hermes_workspace + # - build_hermes_macos: + # requires: + # - prepare_hermes_workspace + # matrix: + # parameters: + # flavor: ["Debug", "Release"] + # - build_hermesc_windows: + # requires: + # - prepare_hermes_workspace + # - build_npm_package: + # name: build_and_publish_npm_package + # context: react-native-bot + # release_type: "dry-run" + # requires: + # - build_hermesc_linux + # - build_hermes_macos + # - build_hermesc_windows + # macOS] analysis: unless: << pipeline.parameters.run_package_release_workflow_only >> jobs: - # Run lints on every commit other than those to the gh-pages branch - - analyze_code: - filters: - branches: - ignore: /.*/ # [macOS] Disable failing test + # Run lints on every commit + - analyze_code - # Run code checks on PRs from forks - - analyze_pr: - filters: - branches: - ignore: /.*/ # [macOS] Disable failing test + # Run code checks on PRs + - analyze_pr # Gather coverage - # [macOS Disable test as it depends on npm package `coveralls`, which depends on deprecated `request` package - # - js_coverage: - # filters: - # branches: - # ignore: gh-pages - # macOS] + - js_coverage nightly: unless: << pipeline.parameters.run_package_release_workflow_only >> @@ -1080,5 +1754,22 @@ workflows: jobs: - nightly_job + - prepare_hermes_workspace + - build_hermesc_linux: + requires: + - prepare_hermes_workspace + - build_hermes_macos: + requires: + - prepare_hermes_workspace + matrix: + parameters: + flavor: ["Debug", "Release"] + - build_hermesc_windows: + requires: + - prepare_hermes_workspace - build_npm_package: - publish_npm_args: --nightly \ No newline at end of file + release_type: "nightly" + requires: + - build_hermesc_linux + - build_hermes_macos + - build_hermesc_windows diff --git a/.circleci/verdaccio.yml b/.circleci/verdaccio.yml new file mode 100644 index 00000000000000..37e5d23b380227 --- /dev/null +++ b/.circleci/verdaccio.yml @@ -0,0 +1,44 @@ +storage: ./storage +auth: + htpasswd: + file: ./htpasswd +uplinks: + npmjs: + url: https://registry.npmjs.org/ + max_fails: 40 + maxage: 30m + timeout: 60s + fail_timeout: 10m + cache: false + agent_options: + keepAlive: true + maxSockets: 40 + maxFreeSockets: 10 +packages: + # Group and isolate all local packages, avoid being proxy from outside + '@react-native/*': + access: $all + publish: $all + # The below specific entries can be removed once they are renamed and have the @react-native prefix + '@react-native-community/eslint-config': + access: $all + publish: $all + '@react-native-community/eslint-plugin': + access: $all + publish: $all + 'react-native-codegen': + access: $all + publish: $all + 'react-native-gradle-plugin': + access: $all + publish: $all + '@*/*': + access: $all + publish: $authenticated + proxy: npmjs + '**': + access: $all + publish: $all + proxy: npmjs +logs: + - {type: file, path: verdaccio.log, format: json, level: warn} diff --git a/.eslintignore b/.eslintignore index 16662f7bfb3b71..49c1ac6eac737a 100644 --- a/.eslintignore +++ b/.eslintignore @@ -1,15 +1,10 @@ **/main.js **/staticBundle.js -bots/node_modules docs/generatedComponentApiDocs.js flow/ Libraries/Renderer/* Libraries/vendor/**/* node_modules/ packages/*/node_modules -packages/*/lib -packages/*/lib-commonjs -bots/node_modules -android-patches/ packages/react-native-codegen/lib -repo-config/node_modules +tools/eslint/rules/sort-imports.js diff --git a/.eslintrc b/.eslintrc deleted file mode 100644 index c05c62620cbf81..00000000000000 --- a/.eslintrc +++ /dev/null @@ -1,60 +0,0 @@ -{ - "root": true, - - "extends": [ - "./packages/eslint-config-react-native-community/index.js" - ], - - "plugins": [ - "@react-native/eslint-plugin-specs" - ], - - "overrides": [ - { - "files": [ - "Libraries/**/*.js", - ], - "rules": { - "@react-native-community/no-haste-imports": 2, - "@react-native-community/error-subclass-name": 2, - "@react-native-community/platform-colors": 2, - "@react-native/specs/react-native-modules": 2 - } - }, - { - "files": [ - "flow-typed/**/*.js", - ], - "rules": { - quotes: 0 - } - }, - { - "files": [ - "**/__fixtures__/**/*.js", - "**/__mocks__/**/*.js", - "**/__tests__/**/*.js", - "jest/**/*.js", - "packages/rn-tester/**/*.js", - ], - "globals": { - // Expose some Jest globals for test helpers - "afterAll": true, - "afterEach": true, - "beforeAll": true, - "beforeEach": true, - "expect": true, - "jest": true, - }, - }, - { - "files": [ - "**/__tests__/**/*-test.js", - ], - "env": { - "jasmine": true, - "jest": true - } - } - ] -} diff --git a/.eslintrc.js b/.eslintrc.js new file mode 100644 index 00000000000000..1a970847534674 --- /dev/null +++ b/.eslintrc.js @@ -0,0 +1,95 @@ +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @format + */ + +'use strict'; + +const path = require('node:path'); + +require('eslint-plugin-lint').load(path.join(__dirname, 'tools/eslint/rules')); + +module.exports = { + root: true, + + extends: ['@react-native-community'], + + plugins: ['@react-native/eslint-plugin-specs', 'lint'], + + overrides: [ + // overriding the JS config from eslint-config-react-native-community config to ensure + // that we use hermes-eslint for all js files + { + files: ['*.js'], + parser: 'hermes-eslint', + rules: { + // These rules are not required with hermes-eslint + 'ft-flow/define-flow-type': 0, + 'ft-flow/use-flow-type': 0, + // flow handles this check for us, so it's not required + 'no-undef': 0, + }, + }, + + { + files: ['Libraries/**/*.js'], + rules: { + '@react-native-community/platform-colors': 2, + '@react-native/specs/react-native-modules': 2, + 'lint/no-haste-imports': 2, + 'lint/no-react-native-imports': 2, + 'lint/require-extends-error': 2, + 'lint/sort-imports': 1, + }, + }, + { + files: ['flow-typed/**/*.js'], + rules: { + 'lint/valid-flow-typed-signature': 2, + 'no-unused-vars': 0, + quotes: 0, + }, + }, + { + files: [ + '**/__fixtures__/**/*.js', + '**/__mocks__/**/*.js', + '**/__tests__/**/*.js', + 'jest/**/*.js', + 'packages/rn-tester/**/*.js', + ], + globals: { + // Expose some Jest globals for test helpers + afterAll: true, + afterEach: true, + beforeAll: true, + beforeEach: true, + expect: true, + jest: true, + }, + }, + { + files: ['**/__tests__/**/*-test.js'], + env: { + jasmine: true, + jest: true, + }, + }, + { + files: ['**/*.{ts,tsx}'], + parser: '@typescript-eslint/parser', + plugins: ['@typescript-eslint/eslint-plugin'], + rules: { + '@typescript-eslint/no-unused-vars': 'off', + 'react-native/no-inline-styles': 'off', + '@typescript-eslint/no-shadow': 'off', + 'no-self-compare': 'off', + 'react/self-closing-comp': 'off', + }, + }, + ], +}; diff --git a/.flowconfig b/.flowconfig index 4f096efa2ef825..8c33504894b30f 100644 --- a/.flowconfig +++ b/.flowconfig @@ -8,7 +8,7 @@ /template/.* ; Ignore the Dangerfile -/bots/dangerfile.js +/packages/react-native-bots/dangerfile.js ; Ignore "BUCK" generated dirs /\.buckd/ @@ -19,8 +19,7 @@ ; Flow doesn't support platforms .*/Libraries/Utilities/LoadingView.js -; Ignore everything in android-patches -/android-patches/.* +.*/node_modules/resolve/test/resolver/malformed_package_json/package\.json$ [untyped] .*/node_modules/@react-native-community/cli/.*/.* @@ -57,6 +56,8 @@ suppress_type=$FlowFixMeProps suppress_type=$FlowFixMeState suppress_type=$FlowFixMeEmpty +inference_mode=constrain_writes + [lints] sketchy-null-number=warn sketchy-null-mixed=warn @@ -66,7 +67,6 @@ nonstrict-import=warn deprecated-type=error unsafe-getters-setters=warn unnecessary-invariant=warn -signature-verification-failure=warn [strict] deprecated-type @@ -78,4 +78,4 @@ untyped-import untyped-type-import [version] -^0.171.0 +^0.191.0 diff --git a/.flowconfig.android b/.flowconfig.android index 6e27866c9650e5..1287ed32e9e75c 100644 --- a/.flowconfig.android +++ b/.flowconfig.android @@ -8,7 +8,7 @@ /template/.* ; Ignore the Dangerfile -/bots/dangerfile.js +/packages/react-native-bots/dangerfile.js ; Ignore "BUCK" generated dirs /\.buckd/ @@ -19,8 +19,7 @@ ; Flow doesn't support platforms .*/Libraries/Utilities/LoadingView.js -; Ignore everything in android-patches -/android-patches/.* +.*/node_modules/resolve/test/resolver/malformed_package_json/package\.json$ [untyped] .*/node_modules/@react-native-community/cli/.*/.* @@ -60,6 +59,8 @@ suppress_type=$FlowFixMeProps suppress_type=$FlowFixMeState suppress_type=$FlowFixMeEmpty +inference_mode=constrain_writes + [lints] sketchy-null-number=warn sketchy-null-mixed=warn @@ -69,7 +70,6 @@ nonstrict-import=warn deprecated-type=error unsafe-getters-setters=warn unnecessary-invariant=warn -signature-verification-failure=warn [strict] deprecated-type @@ -81,4 +81,4 @@ untyped-import untyped-type-import [version] -^0.171.0 +^0.191.0 diff --git a/.flowconfig.macos b/.flowconfig.macos index c0ed79dd08f1cb..2336138507ddbc 100644 --- a/.flowconfig.macos +++ b/.flowconfig.macos @@ -7,7 +7,7 @@ /template/.* ; Ignore the Dangerfile -/bots/dangerfile.js +/packages/react-native-bots/dangerfile.js ; Ignore "BUCK" generated dirs /\.buckd/ @@ -18,8 +18,7 @@ ; Flow doesn't support platforms .*/Libraries/Utilities/LoadingView.js -; Ignore everything in android-patches -/android-patches/.* +.*/node_modules/resolve/test/resolver/malformed_package_json/package\.json$ [untyped] .*/node_modules/@react-native-community/cli/.*/.* @@ -57,6 +56,8 @@ suppress_type=$FlowFixMeProps suppress_type=$FlowFixMeState suppress_type=$FlowFixMeEmpty +inference_mode=constrain_writes + [lints] sketchy-null-number=warn sketchy-null-mixed=warn @@ -66,7 +67,6 @@ nonstrict-import=warn deprecated-type=error unsafe-getters-setters=warn unnecessary-invariant=warn -signature-verification-failure=warn [strict] deprecated-type @@ -78,4 +78,4 @@ untyped-import untyped-type-import [version] -^0.171.0 +^0.191.0 diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml index 8b6f8c0f12ae61..5188c39c86ea89 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -40,8 +40,9 @@ body: attributes: label: Snack, code example, screenshot, or link to a repository description: | - Please provide a Snack (https://snack.expo.io/), a link to a repository on GitHub, or provide a minimal code example that reproduces the problem. + Please provide a Snack (https://snack.expo.dev/), a link to a repository on GitHub, or provide a minimal code example that reproduces the problem. You may provide a screenshot of the application if you think it is relevant to your bug report. Here are some tips for providing a minimal example: https://stackoverflow.com/help/mcve + Please note that a reproducer is mandatory. Issues without reproducer are more likely to stall and will be closed. validations: - required: false + required: true diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml index 8cebc673188671..00539a1ae8df03 100644 --- a/.github/ISSUE_TEMPLATE/config.yml +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -6,6 +6,9 @@ contact_links: - name: 🤔 Questions and Help url: https://reactnative.dev/help about: Looking for help with your app? Please refer to the React Native community's support resources. + - name: 💫 New Architecture - Questions & Technical Deep dive insights + url: https://github.com/reactwg/react-native-new-architecture + about: Questions and doubts related to technical questions for the New Architecture should be directed to the Working Group. Instructions on how to join are available in the README. - name: 🚀 Discussions and Proposals url: https://github.com/react-native-community/discussions-and-proposals about: Discuss the future of React Native in the React Native community's discussions and proposals repository. diff --git a/.github/ISSUE_TEMPLATE/new_architecture_bug_report.yml b/.github/ISSUE_TEMPLATE/new_architecture_bug_report.yml new file mode 100644 index 00000000000000..7b88c23b94e226 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/new_architecture_bug_report.yml @@ -0,0 +1,53 @@ +name: 💫 New Architecture - Bug Report +description: Report a reproducible bug or a build issue when using the New Architecture (Fabric & TurboModules) in React Native. +labels: ["Needs: Triage :mag:", "Type: New Architecture"] +body: + - type: markdown + attributes: + value: | + Please provide all the information requested. Issues that do not follow this format are going to be closed. + This issue report is reserved to bug & build issues for users on the New Architecture. If you're not using + the New Architecture, please don't open issues on this category. + - type: textarea + id: description + attributes: + label: Description + description: | + Please provide a clear and concise description of what the bug or issue is. Include screenshots if needed. + Please make sure you check the New Architecture documentation first, as your issue might + already be answered there - https://reactnative.dev/docs/next/new-architecture-intro + validations: + required: true + - type: input + id: version + attributes: + label: Version + description: What react-native version does this appear on? Please test against the latest stable version. Bug reports against older versions are more likely to stall. + placeholder: ex. 0.68.0 + validations: + required: true + - type: textarea + id: react-native-info + attributes: + label: Output of `npx react-native info` + description: Run `npx react-native info` in your terminal, copy and paste the results here. + validations: + required: true + - type: textarea + id: reproduction + attributes: + label: Steps to reproduce + description: Provide a detailed list of steps that reproduce the issue. + validations: + required: true + - type: textarea + id: extra + attributes: + label: Snack, code example, screenshot, or link to a repository + description: | + Please provide a Snack (https://snack.expo.dev/), a link to a repository on GitHub, or provide a minimal code example that reproduces the problem. + You may provide a screenshot of the application if you think it is relevant to your bug report. + Here are some tips for providing a minimal example: https://stackoverflow.com/help/mcve + Please note that a reproducer is mandatory. Issues without reproducer are more likely to stall and will be closed. + validations: + required: true diff --git a/.github/ISSUE_TEMPLATE/upgrade-regression-form.yml b/.github/ISSUE_TEMPLATE/upgrade-regression-form.yml index 4dede5ee379ec6..51495e4916a373 100644 --- a/.github/ISSUE_TEMPLATE/upgrade-regression-form.yml +++ b/.github/ISSUE_TEMPLATE/upgrade-regression-form.yml @@ -1,4 +1,4 @@ -name: Upgrade - Build Regression +name: ⬆️ Upgrade - Build Regression description: If you are upgrading to a new React Native version (stable or pre-release) and encounter a build regression. labels: ["Needs: Triage :mag:", "Type: Upgrade Issue"] body: diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index f34e5777e55052..dc433b1c6b6c01 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -24,7 +24,7 @@ If you are making a new change then one of the following should be done: ## Changelog [CATEGORY] [TYPE] - Message diff --git a/.github/RELEASE_TEMPLATE.md b/.github/RELEASE_TEMPLATE.md new file mode 100644 index 00000000000000..302daf94622667 --- /dev/null +++ b/.github/RELEASE_TEMPLATE.md @@ -0,0 +1,23 @@ + + + + +- + +--- + +To test it, run: + +npx react-native init RN__SHORT_VERSION__ --version __VERSION__ + +--- + +You can participate in the conversation on the status of this release in the [working group](https://github.com/reactwg/react-native-releases/discussions). + +--- + +To help you upgrade to this version, you can use the [upgrade helper](https://react-native-community.github.io/upgrade-helper/) ⚛️ + +--- + +See changes from this release in the [changelog PR](https://github.com/facebook/react-native/labels/%F0%9F%93%9D%20Changelog) diff --git a/.github/respond-to-issue-based-on-label.yml b/.github/respond-to-issue-based-on-label.yml index 57cc3eeb02a60f..acb89311bc4fb9 100644 --- a/.github/respond-to-issue-based-on-label.yml +++ b/.github/respond-to-issue-based-on-label.yml @@ -46,7 +46,7 @@
:warning: Missing Reproducible Example
:information_source: - It looks like your issue is missing a reproducible example. Please provide a Snack or a repository that demonstrates the issue you are reporting in a minimal, complete, and reproducible manner. + It looks like your issue is missing a reproducible example. Please provide a Snack or a repository that demonstrates the issue you are reporting in a minimal, complete, and reproducible manner.
labels: - "Needs: Author Feedback" diff --git a/.github/workflows/apply-version-label-issue.yml b/.github/workflows/apply-version-label-issue.yml index 816d29876a200a..121e280cfcafe6 100644 --- a/.github/workflows/apply-version-label-issue.yml +++ b/.github/workflows/apply-version-label-issue.yml @@ -4,8 +4,13 @@ on: issues: types: [opened, edited] +permissions: + contents: read + jobs: add-version-label-issue: + permissions: + issues: write # for react-native-community/actions-apply-version-label to label issues runs-on: ubuntu-latest continue-on-error: true diff --git a/.github/workflows/autorebase.yml b/.github/workflows/autorebase.yml new file mode 100644 index 00000000000000..78820f8fea4b3d --- /dev/null +++ b/.github/workflows/autorebase.yml @@ -0,0 +1,24 @@ +name: Automatic Rebase +on: + issue_comment: + types: [created] +permissions: + contents: read +jobs: + rebase: + permissions: + contents: write # for cirrus-actions/rebase to push code to rebase + pull-requests: read # for cirrus-actions/rebase to get info about PR + name: Rebase + if: github.event.issue.pull_request != '' && contains(github.event.comment.body, '/rebase') + runs-on: ubuntu-latest + steps: + - name: Checkout the latest code + uses: actions/checkout@v2 + with: + token: ${{ secrets.GITHUB_TOKEN }} + fetch-depth: 0 # otherwise, you will fail to push refs to dest repo + - name: Automatic Rebase + uses: cirrus-actions/rebase@1.7 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/danger_pr.yml b/.github/workflows/danger_pr.yml new file mode 100644 index 00000000000000..06f8a2e830201c --- /dev/null +++ b/.github/workflows/danger_pr.yml @@ -0,0 +1,27 @@ +name: Run Danger on PR + +on: + pull_request_target: + types: [opened, edited, reopened, synchronize] + +permissions: + actions: write + checks: write + contents: write + issues: write + pull-requests: write + statuses: write + +jobs: + danger: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - name: Run Yarn Install on Root + run: yarn install + working-directory: . + - name: Danger + run: yarn danger ci --use-github-checks --failOnErrors + working-directory: packages/react-native-bots + env: + DANGER_GITHUB_API_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/needs-attention.yml b/.github/workflows/needs-attention.yml index e5c1a979653171..f1ec7e8813475c 100644 --- a/.github/workflows/needs-attention.yml +++ b/.github/workflows/needs-attention.yml @@ -4,12 +4,18 @@ on: issue_comment: types: created +permissions: + contents: read + jobs: applyNeedsAttentionLabel: + permissions: + contents: read # for actions/checkout to fetch code + issues: write # for hramos/needs-attention to label issues name: Apply Needs Attention Label runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Apply Needs Attention Label uses: hramos/needs-attention@v1 with: diff --git a/.github/workflows/on-issue-labeled.yml b/.github/workflows/on-issue-labeled.yml index e68682b2ecb71b..f99404e94fae8a 100644 --- a/.github/workflows/on-issue-labeled.yml +++ b/.github/workflows/on-issue-labeled.yml @@ -4,12 +4,18 @@ on: issues: types: labeled +permissions: + contents: read + jobs: respondToIssueBasedOnLabel: + permissions: + contents: read # for hramos/respond-to-issue-based-on-label to fetch config file + issues: write # for hramos/respond-to-issue-based-on-label to update issues name: Respond to Issue Based on Label runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Respond to Issue Based on Label uses: hramos/respond-to-issue-based-on-label@v2 with: diff --git a/.github/workflows/stale-bot.yml b/.github/workflows/stale-bot.yml index 2ef7890236e881..326a54eb71e9aa 100644 --- a/.github/workflows/stale-bot.yml +++ b/.github/workflows/stale-bot.yml @@ -9,11 +9,11 @@ jobs: issues: write pull-requests: write steps: - - uses: actions/stale@v4 + - uses: actions/stale@v5 with: repo-token: ${{ secrets.GITHUB_TOKEN }} - days-before-stale: 365 - stale-issue-message: 'This issue is stale because it has been open 365 days with no activity. Remove stale label or comment or this will be closed in 7 days.' - stale-pr-message: 'This PR is stale because it has been open 365 days with no activity. Remove stale label or comment or this will be closed in 7 days.' + days-before-stale: 180 + stale-issue-message: 'This issue is stale because it has been open 180 days with no activity. Remove stale label or comment or this will be closed in 7 days.' + stale-pr-message: 'This PR is stale because it has been open 180 days with no activity. Remove stale label or comment or this will be closed in 7 days.' close-issue-message: 'This issue was closed because it has been stalled for 7 days with no activity.' close-pr-message: 'This PR was closed because it has been stalled for 7 days with no activity.' diff --git a/.github/workflows/test-docker-android.yml b/.github/workflows/test-docker-android.yml index 8f973823054bf4..6951e180eb81ce 100644 --- a/.github/workflows/test-docker-android.yml +++ b/.github/workflows/test-docker-android.yml @@ -1,21 +1,26 @@ -# [macOS] disable this test +name: Test Docker Android Image +# This workflow is triggered on commits to main and pull requests. +on: + push: + branches: + - main + pull_request: + branches: + - main -# name: Test Docker Android Image -# # This workflow is triggered on commits to main and pull requests. -# on: -# push: -# branches: -# - main -# pull_request: -# types: [ synchronize ] -# branches: -# - main +permissions: + contents: read -# jobs: -# test-docker-android: -# name: Test Docker -# runs-on: ubuntu-latest -# steps: -# - uses: actions/checkout@v2 -# - name: Build Docker image with Android test app -# run: npm run docker-build-android +jobs: + test-docker-android: + name: Test Docker + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - name: Free up space by removing unnecessary folders + run: | + sudo rm -rf /usr/share/dotnet + sudo rm -rf /opt/ghc + sudo rm -rf "$AGENT_TOOLSDIRECTORY" + - name: Build Docker image with Android test app + run: npm run docker-build-android diff --git a/.gitignore b/.gitignore index 53e8e938dd8b5c..720d8a86b650c8 100644 --- a/.gitignore +++ b/.gitignore @@ -19,14 +19,13 @@ DerivedData *.hmap *.ipa *.xcuserstate -# exclude project.xcworkspace except for xcshareddata/WorkspaceSettings.xcsettings -project.xcworkspace/* -**/project.xcworkspace/contents.xcworkspacedata -**/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +project.xcworkspace +**/.xcode.env.local # Gradle /build/ /packages/react-native-gradle-plugin/build/ +/packages/rn-tester/build /packages/rn-tester/android/app/.cxx/ /packages/rn-tester/android/app/build/ /packages/rn-tester/android/app/gradle/ @@ -37,8 +36,12 @@ project.xcworkspace/* /ReactAndroid/gradle/ /ReactAndroid/gradlew /ReactAndroid/gradlew.bat -/build_deps/ -/ReactAndroid/packages/ +/ReactAndroid/external-artifacts/build/ +/ReactAndroid/external-artifacts/artifacts/ +/ReactAndroid/hermes-engine/build/ +/ReactAndroid/hermes-engine/.cxx/ +/template/android/app/build/ +/template/android/build/ # Buck .buckd @@ -68,7 +71,6 @@ local.properties node_modules *.log .nvm -/bots/node_modules/ package-lock.json # OS X @@ -89,8 +91,6 @@ package-lock.json # ReactCommon subdir shouldn't have Xcode project /ReactCommon/**/*.xcodeproj -/packages/rn-tester/build -/packages/rn-tester/android/app/build/* # Libs that shouldn't have Xcode project /Libraries/FBLazyVector/**/*.xcodeproj @@ -111,18 +111,30 @@ package-lock.json # Ignore RNTester specific Pods, but keep the __offline_mirrors__ here. /packages/rn-tester/Pods/* -!/packages/rn-tester/Pods/__offline_mirrors__ +!/packages/rn-tester/Pods/__offline_mirrors_hermes__ +!/packages/rn-tester/Pods/__offline_mirrors_jsc__ # react-native-codegen /React/FBReactNativeSpec/FBReactNativeSpec /packages/react-native-codegen/lib +/packages/react-native-codegen/tmp/ /ReactCommon/react/renderer/components/rncore/ /packages/rn-tester/NativeModuleExample/ScreenshotManagerSpec* /packages/rn-tester/NativeModuleExample/react/renderer/components/ScreenshotManagerSpec/ + +# Additional SDKs +/sdks/download +/sdks/hermes +/sdks/hermesc +/sdks/hermes-engine/build_host_hermesc + # Visual studio .vscode .vs # Android memory profiler files *.hprof + +# Temporary files created by Metro to check the health of the file watcher +.metro-health-check* diff --git a/.node-version b/.node-version new file mode 100644 index 00000000000000..b6a7d89c68e0ca --- /dev/null +++ b/.node-version @@ -0,0 +1 @@ +16 diff --git a/.prettierignore b/.prettierignore deleted file mode 100644 index 2554d5caf8684f..00000000000000 --- a/.prettierignore +++ /dev/null @@ -1 +0,0 @@ -android-patches/ diff --git a/.ruby-version b/.ruby-version index a603bb50a29e35..49cdd668e1c82b 100644 --- a/.ruby-version +++ b/.ruby-version @@ -1 +1 @@ -2.7.5 +2.7.6 diff --git a/BUCK b/BUCK index a26e8b2852641d..699ce820e9e438 100644 --- a/BUCK +++ b/BUCK @@ -10,7 +10,6 @@ load( ) load( "//tools/build_defs/oss:rn_defs.bzl", - "APPLETVOS", "HERMES_BYTECODE_VERSION", "IOS", "RCT_IMAGE_DATA_DECODER_SOCKET", @@ -36,6 +35,7 @@ RCTCXXBRIDGE_PUBLIC_HEADERS = { "JSCExecutorFactory.h", "NSDataBigString.h", "RCTCxxBridgeDelegate.h", + "RCTJSIExecutorRuntimeInstaller.h", "RCTMessageThread.h", ] } @@ -57,8 +57,9 @@ fb_native.genrule( ) + [ react_native_root_target("packages/rn-tester:nativecomponent-srcs"), ], - cmd = "$(exe {}) $OUT $SRCS".format(react_native_root_target("packages/react-native-codegen:write_to_json")), out = "schema-rncore.json", + cmd = "$(exe {}) $OUT $SRCS".format(react_native_root_target("packages/react-native-codegen:write_to_json")), + labels = ["uses_hg"], ) rn_codegen_components( @@ -96,7 +97,7 @@ rn_xplat_cxx_library2( # it's linked in your app, transparently use it". labels = [ "depslint_never_remove", - "supermodule:xplat/default/public.react_native.infra", + "pfh:ReactNative_CommonInfrastructurePlaceholder", ], preprocessor_flags = get_objc_arc_preprocessor_flags() + get_preprocessor_flags_for_build_mode() + [ "-DWITH_FBSYSTRACE=1", @@ -108,7 +109,6 @@ rn_xplat_cxx_library2( ":RCTCxxUtils", ":ReactInternal", "//fbobjc/Libraries/FBReactKit:RCTFBSystrace", - "//xplat/folly:molly", react_native_root_target("React/CoreModules:CoreModules"), react_native_xplat_target("cxxreact:bridge"), react_native_xplat_target("cxxreact:jsbigstring"), @@ -152,14 +152,15 @@ rn_xplat_cxx_library2( frameworks = [ "$SDKROOT/System/Library/Frameworks/Foundation.framework", ], - labels = ["supermodule:xplat/default/public.react_native.infra"], + labels = [ + "pfh:ReactNative_CommonInfrastructurePlaceholder", + ], preprocessor_flags = get_objc_arc_preprocessor_flags() + get_preprocessor_flags_for_build_mode() + ["-DWITH_FBSYSTRACE=1"], visibility = ["PUBLIC"], deps = [ ":RCTCxxUtils", ":ReactInternal", "//xplat/fbsystrace:fbsystrace", - "//xplat/folly:headers_only", react_native_xplat_target("cxxreact:module"), react_native_xplat_target("cxxreact:bridge"), react_native_xplat_target("reactperflogger:reactperflogger"), @@ -183,17 +184,19 @@ rn_xplat_cxx_library2( exclude = RCTCXXMODULE_PUBLIC_HEADERS.values(), prefix = "React", ), - apple_sdks = (IOS, APPLETVOS), + apple_sdks = (IOS,), contacts = ["oncall+react_native@xmail.facebook.com"], fbobjc_enable_exceptions = True, frameworks = [ "$SDKROOT/System/Library/Frameworks/Foundation.framework", ], - labels = ["supermodule:xplat/default/public.react_native.infra"], + labels = [ + "pfh:ReactNative_CommonInfrastructurePlaceholder", + ], preprocessor_flags = get_objc_arc_preprocessor_flags() + get_preprocessor_flags_for_build_mode(), visibility = ["PUBLIC"], deps = [ - "//xplat/folly:molly", + "//xplat/folly:dynamic", ], ) @@ -214,7 +217,9 @@ rn_xplat_cxx_library2( ), contacts = ["oncall+react_native@xmail.facebook.com"], fbobjc_enable_exceptions = True, - labels = ["supermodule:xplat/default/public.react_native.infra"], + labels = [ + "pfh:ReactNative_CommonInfrastructurePlaceholder", + ], preprocessor_flags = get_objc_arc_preprocessor_flags() + get_preprocessor_flags_for_build_mode(), visibility = ["PUBLIC"], deps = [ @@ -237,13 +242,17 @@ REACT_PUBLIC_HEADERS = { "React/RCTAnimationType.h": RCTVIEWS_PATH + "RCTAnimationType.h", "React/RCTAssert.h": RCTBASE_PATH + "RCTAssert.h", "React/RCTAutoInsetsProtocol.h": RCTVIEWS_PATH + "RCTAutoInsetsProtocol.h", + "React/RCTBorderCurve.h": RCTVIEWS_PATH + "RCTBorderCurve.h", "React/RCTBorderDrawing.h": RCTVIEWS_PATH + "RCTBorderDrawing.h", "React/RCTBorderStyle.h": RCTVIEWS_PATH + "RCTBorderStyle.h", "React/RCTBridge+Private.h": RCTBASE_PATH + "RCTBridge+Private.h", "React/RCTBridge.h": RCTBASE_PATH + "RCTBridge.h", + "React/RCTBridgeConstants.h": RCTBASE_PATH + "RCTBridgeConstants.h", "React/RCTBridgeDelegate.h": RCTBASE_PATH + "RCTBridgeDelegate.h", "React/RCTBridgeMethod.h": RCTBASE_PATH + "RCTBridgeMethod.h", "React/RCTBridgeModule.h": RCTBASE_PATH + "RCTBridgeModule.h", + "React/RCTBridgeModuleDecorator.h": RCTBASE_PATH + "RCTBridgeModuleDecorator.h", + "React/RCTBundleManager.h": RCTBASE_PATH + "RCTBundleManager.h", "React/RCTBundleURLProvider.h": RCTBASE_PATH + "RCTBundleURLProvider.h", "React/RCTComponent.h": RCTVIEWS_PATH + "RCTComponent.h", "React/RCTComponentData.h": RCTVIEWS_PATH + "RCTComponentData.h", @@ -325,6 +334,7 @@ REACT_PUBLIC_HEADERS = { "React/RCTSurfaceView.h": RCTBASE_PATH + "Surface/RCTSurfaceView.h", "React/RCTTextDecorationLineType.h": RCTVIEWS_PATH + "RCTTextDecorationLineType.h", "React/RCTTouchHandler.h": RCTBASE_PATH + "RCTTouchHandler.h", + "React/RCTTurboModuleRegistry.h": RCTBASE_PATH + "RCTTurboModuleRegistry.h", "React/RCTUIManager.h": RCTMODULES_PATH + "RCTUIManager.h", "React/RCTUIManagerObserverCoordinator.h": RCTMODULES_PATH + "RCTUIManagerObserverCoordinator.h", "React/RCTUIManagerUtils.h": RCTMODULES_PATH + "RCTUIManagerUtils.h", @@ -338,7 +348,6 @@ REACT_PUBLIC_HEADERS = { "React/RCTViewManager.h": RCTVIEWS_PATH + "RCTViewManager.h", "React/RCTViewUtils.h": RCTVIEWS_PATH + "RCTViewUtils.h", "React/RCTWeakProxy.h": RCTBASE_PATH + "RCTWeakProxy.h", - "React/RCTWeakViewHolder.h": RCTVIEWS_PATH + "RCTWeakViewHolder.h", "React/RCTWrapperViewController.h": RCTVIEWS_PATH + "RCTWrapperViewController.h", "React/UIView+React.h": RCTVIEWS_PATH + "UIView+React.h", } @@ -416,7 +425,7 @@ rn_xplat_cxx_library2( labels = [ "depslint_never_add", "depslint_never_remove", # Some old NativeModule still relies on +load unfortunately. - "supermodule:xplat/default/public.react_native.infra", + "pfh:ReactNative_CommonInfrastructurePlaceholder", ], platform_preprocessor_flags = [( "linux", @@ -507,7 +516,7 @@ rn_xplat_cxx_library2( header_path_prefix = "React", labels = [ "disable_plugins_only_validation", - "supermodule:xplat/default/public.react_native.infra", + "pfh:ReactNative_CommonInfrastructurePlaceholder", ], plugins = [ react_fabric_component_plugin_provider("SafeAreaView", "RCTSafeAreaViewCls"), @@ -586,10 +595,14 @@ rn_apple_library( contacts = ["oncall+react_native@xmail.facebook.com"], extension_api_only = True, frameworks = [ - "$PLATFORM_DIR/Developer/Library/Frameworks/Foundation.framework", + "Foundation", ], inherited_buck_flags = get_static_library_ios_flags(), - labels = ["supermodule:xplat/default/public.react_native.infra"], + labels = [ + "fbios_link_group:xplat/default/public.react_native.infra", + "pfh:ReactNative_CommonInfrastructurePlaceholder", + "talkios_link_group:xplat/default/public.react_native.infra", + ], preprocessor_flags = get_objc_arc_preprocessor_flags() + get_preprocessor_flags_for_build_mode(), reexport_all_header_dependencies = True, deps = [ @@ -659,7 +672,7 @@ rn_apple_library( contacts = ["oncall+react_native@xmail.facebook.com"], labels = [ "disable_plugins_only_validation", - "supermodule:xplat/default/public.react_native.infra", + "pfh:ReactNative_CommonInfrastructurePlaceholder", ], plugins = [react_fabric_component_plugin_provider("Image", "RCTImageCls")], visibility = ["PUBLIC"], @@ -689,7 +702,9 @@ rn_xplat_cxx_library2( }, compiler_flags = ["-Wall"], contacts = ["oncall+react_native@xmail.facebook.com"], - labels = ["supermodule:xplat/default/public.react_native.infra"], + labels = [ + "pfh:ReactNative_CommonInfrastructurePlaceholder", + ], visibility = ["PUBLIC"], deps = [ "//xplat/js/react-native-github:RCTImage", @@ -716,16 +731,21 @@ rn_library( "**/__*__/**", "**/gulpfile.js", "Libraries/Components/Switch/SwitchSchema.js", + "**/*._reactvr.js", ], ), - labels = ["supermodule:xplat/default/public.react_native.core"], + labels = [ + "pfh:ReactNative_CommonInfrastructurePlaceholder", + ], visibility = ["PUBLIC"], deps = [ "//xplat/js:node_modules__abort_19controller", "//xplat/js:node_modules__anser", "//xplat/js:node_modules__base64_19js", + "//xplat/js:node_modules__deprecated_19react_19native_19prop_19types", "//xplat/js:node_modules__event_19target_19shim", "//xplat/js:node_modules__invariant", + "//xplat/js:node_modules__memoize_19one", "//xplat/js:node_modules__nullthrows", "//xplat/js:node_modules__pretty_19format", "//xplat/js:node_modules__promise", @@ -734,7 +754,7 @@ rn_library( "//xplat/js:node_modules__react_19shallow_19renderer", "//xplat/js:node_modules__regenerator_19runtime", "//xplat/js:node_modules__stacktrace_19parser", - "//xplat/js:node_modules__use_19subscription", + "//xplat/js:node_modules__use_19sync_19external_19store", "//xplat/js:node_modules__whatwg_19fetch", "//xplat/js/RKJSModules/Libraries/Polyfills:Polyfills", "//xplat/js/RKJSModules/Libraries/React:React", @@ -754,7 +774,9 @@ rn_codegen( android_package_name = "com.facebook.fbreact.specs", codegen_modules = True, ios_assume_nonnull = False, - library_labels = ["supermodule:xplat/default/public.react_native.infra"], + library_labels = [ + "pfh:ReactNative_CommonInfrastructurePlaceholder", + ], native_module_spec_name = "FBReactNativeSpec", src_prefix = "Libraries/", ) @@ -764,7 +786,9 @@ rn_codegen( name = "FBReactNativeComponentSpec", codegen_components = True, ios_assume_nonnull = False, - library_labels = ["supermodule:xplat/default/public.react_native.infra"], + library_labels = [ + "pfh:ReactNative_CommonInfrastructurePlaceholder", + ], src_prefix = "Libraries/", ) @@ -798,7 +822,9 @@ rn_apple_library( "depslint_never_remove", # Some old NativeModule still relies on +load unfortunately. "disable_plugins_only_validation", "extension_api_allow_unsafe_unavailable_usages", - "supermodule:xplat/default/public.react_native.infra", + "fbios_link_group:xplat/default/public.react_native.infra", + "pfh:ReactNative_CommonInfrastructurePlaceholder", + "talkios_link_group:xplat/default/public.react_native.infra", ], plugins = react_module_plugin_providers( @@ -847,7 +873,8 @@ rn_apple_library( labels = [ "depslint_never_remove", # Some old NativeModule still relies on +load unfortunately. "disable_plugins_only_validation", - "supermodule:xplat/default/public.react_native.infra", + "fbios_link_group:xplat/default/public.react_native.infra", + "pfh:ReactNative_CommonInfrastructurePlaceholder", ], plugins = react_module_plugin_providers( @@ -905,7 +932,9 @@ rn_apple_library( "depslint_never_remove", # Some old NativeModule still relies on +load unfortunately. "disable_plugins_only_validation", "extension_api_allow_unsafe_unavailable_usages", - "supermodule:xplat/default/public.react_native.infra", + "fbios_link_group:xplat/default/public.react_native.infra", + "pfh:ReactNative_CommonInfrastructurePlaceholder", + "talkios_link_group:xplat/default/public.react_native.infra", ], plugins = react_module_plugin_providers( @@ -952,7 +981,9 @@ rn_apple_library( "depslint_never_remove", # Some old NativeModule still relies on +load unfortunately. "disable_plugins_only_validation", "extension_api_allow_unsafe_unavailable_usages", - "supermodule:xplat/default/public.react_native.infra", + "fbios_link_group:xplat/default/public.react_native.infra", + "pfh:ReactNative_CommonInfrastructurePlaceholder", + "talkios_link_group:xplat/default/public.react_native.infra", ], plugins = react_module_plugin_providers( @@ -1003,7 +1034,9 @@ rn_apple_library( "depslint_never_remove", # Some old NativeModule still relies on +load unfortunately. "disable_plugins_only_validation", "extension_api_allow_unsafe_unavailable_usages", - "supermodule:xplat/default/public.react_native.infra", + "fbios_link_group:xplat/default/public.react_native.infra", + "pfh:ReactNative_CommonInfrastructurePlaceholder", + "talkios_link_group:xplat/default/public.react_native.infra", ], plugins = react_module_plugin_providers( @@ -1083,7 +1116,9 @@ rn_apple_library( "depslint_never_remove", # Some old NativeModule still relies on +load unfortunately. "disable_plugins_only_validation", "extension_api_allow_unsafe_unavailable_usages", - "supermodule:xplat/default/public.react_native.infra", + "fbios_link_group:xplat/default/public.react_native.infra", + "pfh:ReactNative_CommonInfrastructurePlaceholder", + "talkios_link_group:xplat/default/public.react_native.infra", ], plugins = react_module_plugin_providers( @@ -1216,7 +1251,7 @@ rn_xplat_cxx_library2( ], labels = [ "depslint_never_remove", # Some old NativeModule still relies on +load unfortunately. - "supermodule:xplat/default/public.react_native.infra", + "pfh:ReactNative_CommonInfrastructurePlaceholder", ], preprocessor_flags = get_objc_arc_preprocessor_flags() + get_preprocessor_flags_for_build_mode(), visibility = ["PUBLIC"], @@ -1248,7 +1283,8 @@ rn_apple_library( labels = [ "depslint_never_remove", "disable_plugins_only_validation", - "supermodule:xplat/default/public.react_native.infra", + "fbios_link_group:xplat/default/public.react_native.infra", + "pfh:ReactNative_CommonInfrastructurePlaceholder", ], plugins = react_module_plugin_providers( name = "Vibration", @@ -1288,7 +1324,7 @@ rn_xplat_cxx_library2( ], labels = [ "depslint_never_remove", # Some old NativeModule still relies on +load unfortunately. - "supermodule:xplat/default/public.react_native.infra", + "pfh:ReactNative_CommonInfrastructurePlaceholder", ], preprocessor_flags = get_objc_arc_preprocessor_flags() + get_preprocessor_flags_for_build_mode(), visibility = ["PUBLIC"], @@ -1320,7 +1356,7 @@ rn_xplat_cxx_library2( ], labels = [ "depslint_never_remove", - "supermodule:xplat/default/public.react_native.infra", + "pfh:ReactNative_CommonInfrastructurePlaceholder", ], preprocessor_flags = get_objc_arc_preprocessor_flags() + get_preprocessor_flags_for_build_mode(), visibility = ["PUBLIC"], @@ -1354,12 +1390,13 @@ rn_xplat_cxx_library2( ], labels = [ "depslint_never_remove", - "supermodule:xplat/default/public.react_native.infra", + "pfh:ReactNative_CommonInfrastructurePlaceholder", ], preprocessor_flags = get_objc_arc_preprocessor_flags() + get_preprocessor_flags_for_build_mode(), visibility = ["PUBLIC"], deps = [ "//fbobjc/Libraries/MobileUI/ComponentKit:ComponentKit", + "//xplat/js/react-native-github:RCTFabric", "//xplat/js/react-native-github:RCTLinking", "//xplat/js/react-native-github:RCTPushNotification", "//xplat/js/react-native-github:ReactInternal", @@ -1388,13 +1425,14 @@ rn_xplat_cxx_library2( ], labels = [ "depslint_never_remove", - "supermodule:xplat/default/public.react_native.infra", + "pfh:ReactNative_CommonInfrastructurePlaceholder", ], preprocessor_flags = get_objc_arc_preprocessor_flags() + get_preprocessor_flags_for_build_mode(), visibility = ["PUBLIC"], deps = [ ":RCTSurfaceHostingComponent", "//fbobjc/Libraries/MobileUI/ComponentKit:ComponentKit", + "//xplat/js/react-native-github:RCTFabric", "//xplat/js/react-native-github:RCTLinking", "//xplat/js/react-native-github:RCTPushNotification", "//xplat/js/react-native-github:ReactInternal", @@ -1408,7 +1446,7 @@ rn_xplat_cxx_library2( "React/RCTConvert+CoreLocation.h": RCTVIEWS_PATH + "RCTConvert+CoreLocation.h", }, labels = [ - "supermodule:xplat/default/public.react_native.infra", + "pfh:ReactNative_CommonInfrastructurePlaceholder", ], visibility = [ "//fbobjc/Libraries/FBReactKit:RCTMapView", diff --git a/Brewfile b/Brewfile deleted file mode 100644 index cf32f503c64381..00000000000000 --- a/Brewfile +++ /dev/null @@ -1,2 +0,0 @@ -brew "node@16" -brew "watchman" diff --git a/Brewfile.lock.json b/Brewfile.lock.json deleted file mode 100644 index a25b11a29801a6..00000000000000 --- a/Brewfile.lock.json +++ /dev/null @@ -1,96 +0,0 @@ -{ - "entries": { - "brew": { - "node@12": { - "version": "12.22.9", - "bottle": { - "rebuild": 0, - "root_url": "https://ghcr.io/v2/homebrew/core", - "files": { - "arm64_monterey": { - "cellar": ":any", - "url": "https://ghcr.io/v2/homebrew/core/node/12/blobs/sha256:bd8e7c10aff49ccc4a6bc4885ff1368863ced239dc795db73fb357707fae8bd1", - "sha256": "bd8e7c10aff49ccc4a6bc4885ff1368863ced239dc795db73fb357707fae8bd1" - }, - "arm64_big_sur": { - "cellar": ":any", - "url": "https://ghcr.io/v2/homebrew/core/node/12/blobs/sha256:fee8d40df865286e3e2d1d1f0b0e7f50042d49f9f1b7e53dd1f697bd33a4f50f", - "sha256": "fee8d40df865286e3e2d1d1f0b0e7f50042d49f9f1b7e53dd1f697bd33a4f50f" - }, - "monterey": { - "cellar": ":any", - "url": "https://ghcr.io/v2/homebrew/core/node/12/blobs/sha256:e4353eda968bd35510b880d8a2aa1c2d1385bc1f00ef5e0d1c4d2b5bf6d1840a", - "sha256": "e4353eda968bd35510b880d8a2aa1c2d1385bc1f00ef5e0d1c4d2b5bf6d1840a" - }, - "big_sur": { - "cellar": ":any", - "url": "https://ghcr.io/v2/homebrew/core/node/12/blobs/sha256:5633a57b983e0c3993e0f653c0fdf589142e5cea3f55c40009989a4af527f3c1", - "sha256": "5633a57b983e0c3993e0f653c0fdf589142e5cea3f55c40009989a4af527f3c1" - }, - "catalina": { - "cellar": ":any", - "url": "https://ghcr.io/v2/homebrew/core/node/12/blobs/sha256:a992a4b5b262ec6935125ca18f21207f5948b709859ebd8d7367e802ea236a49", - "sha256": "a992a4b5b262ec6935125ca18f21207f5948b709859ebd8d7367e802ea236a49" - }, - "x86_64_linux": { - "cellar": ":any_skip_relocation", - "url": "https://ghcr.io/v2/homebrew/core/node/12/blobs/sha256:f00822df96f1337acdf4ce4d5aceddf1f4cadd940bdf9981ce79cb223ae7592d", - "sha256": "f00822df96f1337acdf4ce4d5aceddf1f4cadd940bdf9981ce79cb223ae7592d" - } - } - } - }, - "watchman": { - "version": "2022.01.17.00", - "bottle": { - "rebuild": 0, - "root_url": "https://ghcr.io/v2/homebrew/core", - "files": { - "arm64_monterey": { - "cellar": ":any", - "url": "https://ghcr.io/v2/homebrew/core/watchman/blobs/sha256:59b1b04b08f3bed07f73c35bcdf40da70b2ecb31d31652144b19fc4547b9716a", - "sha256": "59b1b04b08f3bed07f73c35bcdf40da70b2ecb31d31652144b19fc4547b9716a" - }, - "arm64_big_sur": { - "cellar": ":any", - "url": "https://ghcr.io/v2/homebrew/core/watchman/blobs/sha256:b94520541990f7c26c611416d7e059bff421547d1f68efda96fd68538280dfa4", - "sha256": "b94520541990f7c26c611416d7e059bff421547d1f68efda96fd68538280dfa4" - }, - "monterey": { - "cellar": ":any", - "url": "https://ghcr.io/v2/homebrew/core/watchman/blobs/sha256:3caca0db1ffe6ca2354976be03bb9c76f4512b5a5e1923d9610f8559fa6f86e1", - "sha256": "3caca0db1ffe6ca2354976be03bb9c76f4512b5a5e1923d9610f8559fa6f86e1" - }, - "big_sur": { - "cellar": ":any", - "url": "https://ghcr.io/v2/homebrew/core/watchman/blobs/sha256:146c5006c33b266101858632275e4996cccf99ba5c5a02c98b0a5cb4c72d0860", - "sha256": "146c5006c33b266101858632275e4996cccf99ba5c5a02c98b0a5cb4c72d0860" - }, - "catalina": { - "cellar": ":any", - "url": "https://ghcr.io/v2/homebrew/core/watchman/blobs/sha256:da7d2aea136a9c80606232cebd2f120c0336bba57601166cd71f5fdb7a07a369", - "sha256": "da7d2aea136a9c80606232cebd2f120c0336bba57601166cd71f5fdb7a07a369" - }, - "x86_64_linux": { - "cellar": "/home/linuxbrew/.linuxbrew/Cellar", - "url": "https://ghcr.io/v2/homebrew/core/watchman/blobs/sha256:f2fd1a6cde41f21cf627dc92ca6762136195540c26dd3999b2f9278165f4ac37", - "sha256": "f2fd1a6cde41f21cf627dc92ca6762136195540c26dd3999b2f9278165f4ac37" - } - } - } - } - } - }, - "system": { - "macos": { - "catalina": { - "HOMEBREW_VERSION": "3.3.11", - "HOMEBREW_PREFIX": "/usr/local", - "Homebrew/homebrew-core": "84eb4bfe413a805ceb7ed68e14dab083bdf3beb9", - "CLT": "12.4.0.0.1.1610135815", - "Xcode": "12.4", - "macOS": "10.15.7" - } - } - } -} diff --git a/CHANGELOG.md b/CHANGELOG.md index a72434de861cee..6b190ae10648c2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,833 @@ # Changelog +## v0.70.3 + +### Fixed + +- Stop styles from being reset when detaching Animated.Values in old renderer ([2f58e52006](https://github.com/facebook/react-native/commit/2f58e520061a31ab90f7bbeef59e2bf723605106) by [@javache](https://github.com/javache)) +- Revert "Fix TextInput dropping text when used as uncontrolled component with `defaultValue`" to fix TextInputs not being settable to undefined programmatically ([e2645a5](https://github.com/facebook/react-native/commit/e2645a59f6211116d2069967443502910c167d6f)) by Garrett Forbes Monroe + +#### Android specific + +- Use NMake generator for Hermes build on Windows ([9d08d55bbe](https://github.com/facebook/react-native/commit/9d08d55bbef4e79a8843deef90bef828f7b9a6ef) by [@mganandraj](https://github.com/mganandraj)) +- Fixing failure building RN codegen CLI on Windows ([85c0c0f21f](https://github.com/facebook/react-native/commit/85c0c0f21fdb52543e603687a3c42dc40dff572b) by [@mganandraj](https://github.com/mganandraj)) + +#### iOS specific + +- Add xcode 14 workaround (turn off signing resource bundles) for `React-Core` ([967de03f30](https://github.com/facebook/react-native/commit/967de03f304404ac8817936da37ca39514a09e33) by [@kelset](https://github.com/kelset)) + +## v0.70.2 + +### Added + +#### iOS specific + +- Add support for "Prefer Cross-Fade Transitions" into AccessibilityInfo ([be7c50fefd](https://github.com/facebook/react-native/commit/be7c50fefd7f13201fb538ded93d91b374341173) by [@gabrieldonadel](https://github.com/gabrieldonadel)) + +### Changed + +- Bump CLI to 9.1.3 and Metro to 0.72.3 ([f164556037](https://github.com/facebook/react-native/commit/f1645560376b734a87f0eba1fef69f6cba312cc1) by [@kelset](https://github.com/kelset)) + +### Fixed + +- Inform ScrollView of Keyboard Events Before Mount ([26d148029c](https://github.com/facebook/react-native/commit/26d148029c7fde117f33b0d6c8b34286c45a0ef2) by [@NickGerleman](https://github.com/NickGerleman)) + +#### Android specific + +- Fix port as -1 if dev server without specifying port on Android ([3d7e1380b4](https://github.com/facebook/react-native/commit/3d7e1380b4e609f5340ee80c19d566b17e620427) by [@Kudo](https://github.com/Kudo)) + +## v0.70.1 + +### Added + +- Add more debugging settings for *HermesExecutorFactory* ([32d12e89f8](https://github.com/facebook/react-native/commit/32d12e89f864a106433c8e54c10691d7876333ee) by [@Kudo](https://github.com/Kudo)) +- Support TypeScript array types for turbo module (component only) ([33d1291e1a](https://github.com/facebook/react-native/commit/33d1291e1a96497a4f994e9d622248a745ee1ea6) by [@ZihanChen-MSFT](https://github.com/ZihanChen-MSFT)) + +### Changed + +- Accept TypeScript type `T | null | undefined` as a maybe type of T in turbo module. ([9ecd203eec](https://github.com/facebook/react-native/commit/9ecd203eec97e7d21d10311d950c9f8f30c7a4b1) by [@ZihanChen-MSFT](https://github.com/ZihanChen-MSFT)) +- Bump react-native-gradle-plugin to 0.70.3 ([e33633644c](https://github.com/facebook/react-native/commit/e33633644c70ea39af6e450fcf31d9458051fd5f) by [@dmytrorykun](https://github.com/dmytrorykun)) +- Bump react-native-codegen to 0.70.5 ([6a8c38eef2](https://github.com/facebook/react-native/commit/6a8c38eef272e79e52a35941afa9c3fe9e8fc191) by [@dmytrorykun](https://github.com/dmytrorykun)) +- Hermes version bump for 0.70.1 ([5132211228](https://github.com/facebook/react-native/commit/5132211228a5b9e36d58c1f7e2c99ccaabe1ba3d) by [@dmytrorykun](https://github.com/dmytrorykun)) + +### Fixed + +- Fix hermes profiler ([81564c1a3d](https://github.com/facebook/react-native/commit/81564c1a3dae4222858de2a9a34089097f665e82) by [@janicduplessis](https://github.com/janicduplessis)) + +#### Android specific + +- Support PlatformColor in borderColor ([2d5db284b0](https://github.com/facebook/react-native/commit/2d5db284b061aec33af671b25065632e20217f62) by [@danilobuerger](https://github.com/danilobuerger)) +- Avoid crash in ForwardingCookieHandler if webview is disabled ([5451cd48bd](https://github.com/facebook/react-native/commit/5451cd48bd0166ba70d516e3a11c6786bc22171a) by [@Pajn](https://github.com/Pajn)) +- Correctly resolve classes with FindClass(..) ([361b310bcc](https://github.com/facebook/react-native/commit/361b310bcc8dddbff42cf63495649291c894d661) by [@evancharlton](https://github.com/evancharlton)) + +#### iOS specific + +- Fix KeyboardAvoidingView height when "Prefer Cross-Fade Transitions" is enabled ([4b9382c250](https://github.com/facebook/react-native/commit/4b9382c250261aab89b271618f8b68083ba01785) by [@gabrieldonadel](https://github.com/gabrieldonadel)) +- Fix React module build error with swift integration on new architecture mode ([3afef3c167](https://github.com/facebook/react-native/commit/3afef3c16702cefa5115b059a08741fba255b2db) by [@Kudo](https://github.com/Kudo)) +- Fix ios pod install error ([0cae4959b7](https://github.com/facebook/react-native/commit/0cae4959b750ea051dcd04e4c9374e02b1de6e7a) by [@Romick2005](https://github.com/Romick2005)) + +## 0.70.0 + +### Breaking + +- Remove jest/preprocessor from the react-native package ([0301cb285b](https://github.com/facebook/react-native/commit/0301cb285b2e85b48a397fe58d565196654d9754) by [@motiz88](https://github.com/motiz88)) +- Remove nonstandard Promise.prototype.done ([018d5cf985](https://github.com/facebook/react-native/commit/018d5cf985497273dd700b56168cf1cf64f498d5) by [@motiz88](https://github.com/motiz88)) + +### Added + +- Support TypeScript array types for turbo module (module only) ([f0c4c291e1](https://github.com/facebook/react-native/commit/f0c4c291e12a8e76f91d3841d65291f0f1f16714) by [@ZihanChen-MSFT](https://github.com/ZihanChen-MSFT)) +- Added files for `avn`, `nodenv`, and other managers that set the node.js version in reactive native project including testing ([933fbb1b2b](https://github.com/facebook/react-native/commit/933fbb1b2b4d2b7c802bf1f2be4c47e5b442a850) by [@ramonmedel](https://github.com/ramonmedel)) +- Support BigInt in Hermes ([11bae63bb1](https://github.com/facebook/react-native/commit/11bae63bb1f833802ec6ce01342ebdd1d61e9252) by [@jpporto](https://github.com/jpporto)) +- The old Hermes instrumented stats migrated to the new one ([c37f719567](https://github.com/facebook/react-native/commit/c37f7195675df67d23c3c008ec5ab5fd7b8d0394) by [@jpporto](https://github.com/jpporto)) +- Modified **getDefaultJSExecutorFactory** method ([87cfd386cb](https://github.com/facebook/react-native/commit/87cfd386cb2e02bfa440c94706d9d0274f83070c) by [@KunalFarmah98](https://github.com/KunalFarmah98)) +- `EventEmitter#emit` now freezes the set of listeners before iterating over them, meaning listeners that are added or removed will not affect that iteration. ([e5c5dcd9e2](https://github.com/facebook/react-native/commit/e5c5dcd9e26e9443f59864d9763b049e0bda98e7) by [@yungsters](https://github.com/yungsters)) +- Added File and Blob globals to eslint community config ([d881c87231](https://github.com/facebook/react-native/commit/d881c872314e55e17b198a41c86528d79092d222) by [@shamilovtim](https://github.com/shamilovtim)) +- C++ TurboModule methods can now use mixed types ([3c569f546c](https://github.com/facebook/react-native/commit/3c569f546ca78b23fbcb9773a1273dd9710f8c60) by [@appden](https://github.com/appden)) +- Add useNativeDriver as a param for setValue for Animated ([73191edb72](https://github.com/facebook/react-native/commit/73191edb7255b1ba5e9a0955a25c14250186a676) by [@genkikondo](https://github.com/genkikondo)) +- Add `Animated.Numeric` Flow type ([9eb7629ac6](https://github.com/facebook/react-native/commit/9eb7629ac66abc23b91b81d420891d68bbd4f578) by [@motiz88](https://github.com/motiz88)) +- Add LTI annotations to function params ([c940eb0c49](https://github.com/facebook/react-native/commit/c940eb0c49518b82a3999dcac3027aa70018c763), [e7a4dbcefc](https://github.com/facebook/react-native/commit/e7a4dbcefc9e393c41f4a796d522211bc1e60b6f), [d96744e277](https://github.com/facebook/react-native/commit/d96744e27711c4fa4dfad1b5a796283a232e60af) by [@pieterv](https://github.com/pieterv)) + +#### Android specific + +- Accessibility announcement for list and grid in FlatList ([2d5882132f](https://github.com/facebook/react-native/commit/2d5882132fb2c533fe9bbba83576b8fac4aca727), [105a2397b6](https://github.com/facebook/react-native/commit/105a2397b6b187a9669ba1c028508a7bb9664009) by [@fabriziobertoglio1987](https://github.com/fabriziobertoglio1987)) +- Add READ_VOICEMAIL and WRITE_VOICEMAIL permissions to PermisionsAndroid library. ([8a2be3e143](https://github.com/facebook/react-native/commit/8a2be3e1438dd145ccb5374d6ef60811047d23aa) by [@zolbooo](https://github.com/zolbooo)) +- Add POST_NOTIFICATIONS, NEARBY_WIFI_DEVICES permission ([0a854c7c8b](https://github.com/facebook/react-native/commit/0a854c7c8b7ffc382c43fa460651a4b4de34c3c7) by [@vincent-paing](https://github.com/vincent-paing)) +- Extend the React Native Gradle plugin to accept a config from package.json ([5f3c5aa529](https://github.com/facebook/react-native/commit/5f3c5aa529ed75414eb339c3d8fd2c9628534621) by [@cortinico](https://github.com/cortinico)) +- Ability to pass a Typeface object to ReactFontManager in addition to a font resource ID ([e2dd2e2a6e](https://github.com/facebook/react-native/commit/e2dd2e2a6ed17b366a3e2ec0942ea1d82a404c5d) by [@thurn](https://github.com/thurn)) +- Option to enable lazyViewManager support with `ViewManagerOnDemandReactPackage` ([d4b59cd9d0](https://github.com/facebook/react-native/commit/d4b59cd9d02a8c4eda3ac4bf89cfe8161847adf0) by [@javache](https://github.com/javache)) +- Support for dataUri in form data ([c663c0ec9d](https://github.com/facebook/react-native/commit/c663c0ec9deee7281f819f222bb29ad79e99f3b8) by [@hetanthakkar1](https://github.com/hetanthakkar1)) +- Add android-only prop documentation at the TextInput js level. ([f2e23215ca](https://github.com/facebook/react-native/commit/f2e23215ca14c3c630aa931cdd114187589ac0fb)) +- Update template to gitignore `android/app/.cxx` ([542d43df9d](https://github.com/facebook/react-native/commit/542d43df9d84a88f742c273391f2596546b4c804) by [@leotm](https://github.com/leotm)) + +#### iOS specific + +- Add Mac Catalyst compatibility (can be enabled in Podfile) ([2fb6a3393d](https://github.com/facebook/react-native/commit/2fb6a3393d545a93518d1b2906bd9453458660a0) by [@Arkkeeper](https://github.com/Arkkeeper)) +- Enabled Hermes Intl ([3fa3aeba93](https://github.com/facebook/react-native/commit/3fa3aeba93f226b97e324f3643b98382947e5985) by [@neildhar](https://github.com/neildhar)) +- HTTP Response headers added to the error object passed to JS code. ([9eb2826f9b](https://github.com/facebook/react-native/commit/9eb2826f9beac5b7476f33e68803ca5a024867db)) +- Add userInterfaceStyle to Alert to override user interface style for iOS 13+ ([47bd78f64f](https://github.com/facebook/react-native/commit/47bd78f64f334b770edc7fabd4b9cceb07a7a503) by [@luoxuhai](https://github.com/luoxuhai)) +- Add function to cleanup codegen folders ([71692889b0](https://github.com/facebook/react-native/commit/71692889b0d89b033c07ef87ee3dbf6d62d79235) by [@cipolleschi](https://github.com/cipolleschi)) +- Cocoapods function to add the `CLANG_CXX_LANGUAGE_STANDARD` to all the targets if needed ([ca8174e15f](https://github.com/facebook/react-native/commit/ca8174e15f77cbeecb7ff7a5a583abb668817777) by [@f-meloni](https://github.com/f-meloni)) +- Support codegen from a single folder ([05aaba9514](https://github.com/facebook/react-native/commit/05aaba95145df0b7f541e391a9f64ba3402cac35) by [@cipolleschi](https://github.com/cipolleschi)) +- Run script phases tests in CI ([c171a6e157](https://github.com/facebook/react-native/commit/c171a6e1572f64b2ab9b26d431c07581d4ae832b) by [@cipolleschi](https://github.com/cipolleschi)) + +### Changed + +- Bump React Native Codegen to 0.70.0 ([a22ceecc84](https://github.com/facebook/react-native/commit/a22ceecc849fc62c926643f4d121cf1e4575c693) by [@dmytrorykun](https://github.com/dmytrorykun), [2a274c1a08](https://github.com/facebook/react-native/commit/2a274c1a082c3291d2df1a4b960bf654e217a4dd) by [@cortinico](https://github.com/cortinico), [ce4246a05c](https://github.com/facebook/react-native/commit/ce4246a05c96cd6fe805499960b105267ac044bb) by [@dmytrorykun](https://github.com/dmytrorykun)) +- Upgrade RN CLI to v9.0.0, Metro to 0.72.1 ([0c2fe96998](https://github.com/facebook/react-native/commit/0c2fe969984fff0676f99fe034b3e49d38ed7db6) by [@thymikee](https://github.com/thymikee), [7e580b97bf](https://github.com/facebook/react-native/commit/7e580b97bf63436978d053926e04adeb9ae6f75f) by [@kelset](https://github.com/kelset), [c504d038c4](https://github.com/facebook/react-native/commit/c504d038c470f7a13fb345f57261172c7c85248c) by [@thymikee](https://github.com/thymikee), [f1d624823f](https://github.com/facebook/react-native/commit/f1d624823fe23eb3d30de00cf78beb71dc1b8413) by [@kelset](https://github.com/kelset), [2b49ac6f8b](https://github.com/facebook/react-native/commit/2b49ac6f8b04953be4cd5bf0b1325986b117763c) by [@thymikee](https://github.com/thymikee)) +- Doc: fix minimum iOS version in requirements section ([ec3c8f4380](https://github.com/facebook/react-native/commit/ec3c8f43800a027a0a717367360421089e7293fd) by [@Simon-TechForm](https://github.com/Simon-TechForm)) +- Remove "Early" in Js error reporting pipeline ([0646551d76](https://github.com/facebook/react-native/commit/0646551d7690cd54847eb468f8e43d71ebebdda9) by [@sshic](https://github.com/sshic)) +- Update @react-native/eslint-plugin-specs to 0.70.0 ([d07fae9b23](https://github.com/facebook/react-native/commit/d07fae9b23c258a60045b666167efd5259b962ce), [afd76f69c7](https://github.com/facebook/react-native/commit/afd76f69c7d2408654ba67ac2ed4d612abfbe0ce) by [@dmytrorykun](https://github.com/dmytrorykun), [ea8d8e2f49](https://github.com/facebook/react-native/commit/ea8d8e2f49ea3ce15faeab500b661a1cacacf8a8) by [@cortinico](https://github.com/cortinico)) +- Do not depend on hermes-engine NPM package anymore ([78cd689f9a](https://github.com/facebook/react-native/commit/78cd689f9a634b152ea09ed6cb4fa858ee26e653) by [@cortinico](https://github.com/cortinico)) +- Add ability to pass `ItemSeparatorComponent` as React Element ([5854b11bf9](https://github.com/facebook/react-native/commit/5854b11bf9d42bab9dbe62b9152a3d3a94e42c13) by [@retyui](https://github.com/retyui)) +- Hermes version bump. ([0b4b7774e2](https://github.com/facebook/react-native/commit/0b4b7774e2d71259962ed36b7acb5c3989c3be9c) by [@dmytrorykun](https://github.com/dmytrorykun), [8c682ddd59](https://github.com/facebook/react-native/commit/8c682ddd599b75a547975104cb6f90eec8753daf) by [@dmytrorykun](https://github.com/dmytrorykun), [eb6767813a](https://github.com/facebook/react-native/commit/eb6767813a0efe04a9e79955b8f6ee909a4a76bf) by [@cortinico](https://github.com/cortinico)) +- Codemod `{...null}` to `{}` in xplat/js ([f392ba6725](https://github.com/facebook/react-native/commit/f392ba67254e95126974fafabf3e4ef0300e24e8) by [@gkz](https://github.com/gkz)) +- Fix TextInput dropping text when used as uncontrolled component with `defaultValue` ([51f49ca998](https://github.com/facebook/react-native/commit/51f49ca9982f24de08f5a5654a5210e547bb5b86)) +- Suppress errors ahead of launch ([67e12a19cb](https://github.com/facebook/react-native/commit/67e12a19cb236fbe0809fbbc9e516b37a5848a6a) by [@gkz](https://github.com/gkz)) +- Suppress missing 'this' annotations ([6c563a507f](https://github.com/facebook/react-native/commit/6c563a507fd8c41e04a1e62e2ba87993c6eb1e2f) by [@pieterv](https://github.com/pieterv)) +- Suppress missing annotations ([66c6a75650](https://github.com/facebook/react-native/commit/66c6a75650f91d61e7e87a8e661d87101e26cf9c) by [@pieterv](https://github.com/pieterv)) +- Use RuntimeConfig instead of VM Experiment Flag to set up the micro task queue. ([753038cf34](https://github.com/facebook/react-native/commit/753038cf345a45d95ab9b9343447f524e1b36840) by [@fbmal7](https://github.com/fbmal7)) +- Update direct Metro dependencies to 0.72.0 ([05dcebc211](https://github.com/facebook/react-native/commit/05dcebc21175a78c6533a8856aed644c45276169) by [@kelset](https://github.com/kelset), [64788cc9fe](https://github.com/facebook/react-native/commit/64788cc9fe42fbedc3e3b1c9c516a079cfa71cd1) by [@huntie](https://github.com/huntie), [bdeb4e0655](https://github.com/facebook/react-native/commit/bdeb4e065532dfb1bb4c9c1e87e8a869a737e48a) by [@jacdebug](https://github.com/jacdebug), [894f652639](https://github.com/facebook/react-native/commit/894f6526399098d825ef32c02eb201cd8ba41873) by [@robhogan](https://github.com/robhogan), [08ebc1cfd8](https://github.com/facebook/react-native/commit/08ebc1cfd88a629389c43abf23b40a2bdf1b1579) by [@arushikesarwani94](https://github.com/arushikesarwani94)) +- ECOSYSTEM.md: update Partner entries ([5471afeebf](https://github.com/facebook/react-native/commit/5471afeebf59853ce31df1ade6a4591414b6aa2f) by [@Simek](https://github.com/Simek)) +- Move ScrollView's contentOffset to common props ([7c581f3d30](https://github.com/facebook/react-native/commit/7c581f3d3007954413d68daf2e868ce93e120615) by [@genkikondo](https://github.com/genkikondo)) +- Upgrade react-native-gradle-plugin to 0.70.2 ([1518f838b7](https://github.com/facebook/react-native/commit/1518f838b70951882f7b414c90407d3eb584cab4), [2176173dcc](https://github.com/facebook/react-native/commit/2176173dcc029ab21bfcdfe5c9e150581db47409) by [@dmytrorykun](https://github.com/dmytrorykun)) +- Update a few metro deps as follow up from the commit from main ([7c7ba1babd](https://github.com/facebook/react-native/commit/7c7ba1babd41b6b60f0dc9f48c34d00235d2fef5) by [@kelset](https://github.com/kelset)) + +#### Android specific + +- Bump Android Gradle Plugin to 7.2.1 ([53c8fc9488](https://github.com/facebook/react-native/commit/53c8fc94882893dd8c337fd29543ae11fd467267) by [@leotm](https://github.com/leotm), [c274456e5b](https://github.com/facebook/react-native/commit/c274456e5b635825560852baa5787e96640800d8) by [@dulmandakh](https://github.com/dulmandakh)) +- Rename NativeModuleCallExceptionHandler to JSExceptionHandler for broader usage ([b6f7689d70](https://github.com/facebook/react-native/commit/b6f7689d701d0409c23ab364356aeb95710c20fa) by [@sshic](https://github.com/sshic)) +- Simplify the Android.mk file in the App Template ([7fb0bb40d2](https://github.com/facebook/react-native/commit/7fb0bb40d2206c734a1feb6b555c22d6d5f2436e) by [@cortinico](https://github.com/cortinico)) +- Make Hermes the default engine on Android ([a7db8df207](https://github.com/facebook/react-native/commit/a7db8df2076f68ae9451ce1c77d7eb09d8cfeb14) by [@cortinico](https://github.com/cortinico)) +- Revamp touch event dispatching methods ([089ff4555a](https://github.com/facebook/react-native/commit/089ff4555af27eec4561b1627298702b4ecee482) by [@sshic](https://github.com/sshic)) +- Demonstrating Dark Mode correctly in the `StatusBar` for the starter template App. ([763dc52387](https://github.com/facebook/react-native/commit/763dc5238721a21847b6d6670b5fa268e3bf2ed4) by [@mrbrentkelly](https://github.com/mrbrentkelly)) +- Bump Gradle to 7.5.0 ([5c8186623a](https://github.com/facebook/react-native/commit/5c8186623ae15388949cfc4143edae86863a447b) by [@leotm](https://github.com/leotm), [99e7373dd2](https://github.com/facebook/react-native/commit/99e7373dd2f20184153377109e0e8e48b5bf46f7) by [@dulmandakh](https://github.com/dulmandakh)) +- Generalized the return type of ViewManagerOnDemandReactPackage.getViewManagerNames ([51e029ec3c](https://github.com/facebook/react-native/commit/51e029ec3ce42ae8df3d367d8f553ec2148eeafc) by [@javache](https://github.com/javache)) +- Don't assert on current activity when call startActivityForResult ([bf6884dc90](https://github.com/facebook/react-native/commit/bf6884dc903154ae32daa50ce7983a9f014be781) by [@sshic](https://github.com/sshic)) +- Adapt template to new architecture autolinking on Android ([9ad7cbc3eb](https://github.com/facebook/react-native/commit/9ad7cbc3eb365190e0bfe290e1025553a807b298) by [@thymikee](https://github.com/thymikee)) +- Replaced reactnativeutilsjni with reactnativejni in the build process to reduce size ([54a4fcbfdc](https://github.com/facebook/react-native/commit/54a4fcbfdcc8111b3010b2c31ed3c1d48632ce4c) by [@SparshaSaha](https://github.com/SparshaSaha)) +- Bump Soloader to 0.10.4 ([b9adf2db20](https://github.com/facebook/react-native/commit/b9adf2db20bf9e1436fa58182d886fd9461df9af) by [@mikehardy](https://github.com/mikehardy)) +- Update the new app template to use CMake instead of Android.mk ([dfd7f70eff](https://github.com/facebook/react-native/commit/dfd7f70effeacfeb06d9c2d4762a279a079ee004) by [@cortinico](https://github.com/cortinico)) +- Refactored usage of kotlin plugin ([be35c6dafb](https://github.com/facebook/react-native/commit/be35c6dafbdb46d2ec165460d4bb12f34de6e878) by [@hurali97](https://github.com/hurali97)) +- Bump Gradle to 7.5.1 ([7a911e0730](https://github.com/facebook/react-native/commit/7a911e073094b533cb5a7ce76932c02f83f4fe5d) by [@AlexanderEggers](https://github.com/AlexanderEggers)) +- Fix error of release builds with Hermes enabled for Windows users ([7fcdb9d9d8](https://github.com/facebook/react-native/commit/7fcdb9d9d8f964d24a5ec3d423c67f49b7650ed8) by [@JoseLion](https://github.com/JoseLion)) + +#### iOS specific + +- Move and test Hermes setup from react_native_pods script into a dedicated file ([468b86bd37](https://github.com/facebook/react-native/commit/468b86bd3710b1d43a492c94fb314cc472f03b86) by [@cipolleschi](https://github.com/cipolleschi)) +- Use the correct operator to decide whether Hermes is enabled or not. ([61488449b9](https://github.com/facebook/react-native/commit/61488449b996da5881e4711e0813e9c90b6e57a1) by [@cipolleschi](https://github.com/cipolleschi)) +- Hermes is now the default engine on iOS. This setting is controlled via `flags[:hermes_enabled]` in the Podfile. ([1115bc77db](https://github.com/facebook/react-native/commit/1115bc77db1090042effc021837f70b28694fa09) by [@hramos](https://github.com/hramos)) +- Move LocalPodspecPatch to dedicated file ([8fe2b591c7](https://github.com/facebook/react-native/commit/8fe2b591c7e073d629e95cd7b67aa1dfa96ece38) by [@cipolleschi](https://github.com/cipolleschi)) +- Move the `modify_flags_for_new_architecture` method to separate ruby file ([71da21243c](https://github.com/facebook/react-native/commit/71da21243c85283445c6cefa64d1ace13823ab69) by [@cipolleschi](https://github.com/cipolleschi)) +- Refactoring part of the react_native_pods.rb script ([4f732ba9ee](https://github.com/facebook/react-native/commit/4f732ba9ee2a1e162729c97d5c12ea771b3a424a), [7a2704455f](https://github.com/facebook/react-native/commit/7a2704455f3edf203d2ecc8135fabf2667f718d8) by [@cipolleschi](https://github.com/cipolleschi)) +- When Hermes is enabled, it will use the same copy of JSI as React Native ([340612a200](https://github.com/facebook/react-native/commit/340612a200505ca829bae1f9bce800d3673dac04) by [@hramos](https://github.com/hramos)) +- Move `use_flipper` logic inside `use_react_native` and simplify the Flipper dependencies logic ([0bd5239553](https://github.com/facebook/react-native/commit/0bd523955385a3b1e622077b7ee4ea0df3c5c158) by [@f-meloni](https://github.com/f-meloni)) +- Export `flipper.rb` script file ([e07a7eb16b](https://github.com/facebook/react-native/commit/e07a7eb16b97e1222e23f935a3d4bb3dac848ef2) by [@cipolleschi](https://github.com/cipolleschi)) +- Use `outputDir` as base directory for the codegen and remove the possibility to customize the intermediate path. The generated code requires specific paths in the `#include` directive. ([e4d0153a67](https://github.com/facebook/react-native/commit/e4d0153a675fbdd8718f433b2e9f8bfdccec4b2f) by [@cipolleschi](https://github.com/cipolleschi)) +- Refactor part of the codegen scripts and add tests. ([0465c3fd10](https://github.com/facebook/react-native/commit/0465c3fd102525b005826f3c68923d7e9851d6b8), [305a054865](https://github.com/facebook/react-native/commit/305a0548652a405d9f638fb2c054781951dfc996) by [@cipolleschi](https://github.com/cipolleschi)) +- CodeGen now supports the `"all"` library type. ([6718500eaa](https://github.com/facebook/react-native/commit/6718500eaaeb92b8a74320dcee961ac96f6f12fa) by [@cipolleschi](https://github.com/cipolleschi)) +- Fix the test_ios_unit test ([fdbe4719e2](https://github.com/facebook/react-native/commit/fdbe4719e2e2b599e86d42c49d42c4da97ef431a) by [@cipolleschi](https://github.com/cipolleschi)) +- Update Podfile to allow `PRODUCTION=1 pod install` ([77752fc403](https://github.com/facebook/react-native/commit/77752fc4037e66d5b0a5851bae79c4d3285ed334) by [@leotm](https://github.com/leotm)) +- Destruct use_reactnative parameters and ad ddocumentation ([79a37e5a88](https://github.com/facebook/react-native/commit/79a37e5a88e179090ade7145a453a46719c87b3f) by [@cipolleschi](https://github.com/cipolleschi)) +- Move codegen in separate files ([7d069b2583](https://github.com/facebook/react-native/commit/7d069b25835ad20654a46ebb1e09631d826598e0) by [@cipolleschi](https://github.com/cipolleschi)) +- Silence warning due to react-native internal details. ([a4599225f5](https://github.com/facebook/react-native/commit/a4599225f5a6a2d6801dd80b7728c1bbe5b2ec3a) by [@cipolleschi](https://github.com/cipolleschi)) + +### Removed + +- Remove previously deprecated Transform style-attribute props ([7cfd77debd](https://github.com/facebook/react-native/commit/7cfd77debd36f867f5ddfdb9cc44fbe6137aaeba) by [@Zachinquarantine](https://github.com/Zachinquarantine)) +- Remove deprecated `isTVOS` constant. ([6075d64acf](https://github.com/facebook/react-native/commit/6075d64acf6f8d74e18ef6568c9438f73fe56d44) by [@Zachinquarantine](https://github.com/Zachinquarantine)) +- The diffs renames the required variable which was causing conflicts in names with Apple core SDK's ([086c13dd5f](https://github.com/facebook/react-native/commit/086c13dd5fba3f77acbc70c9bdedc9299118b526) by [@arinjay](https://github.com/arinjay)) +- Removed `EventEmitter.prototype.removeSubscription` method. ([870755fa7e](https://github.com/facebook/react-native/commit/870755fa7e7011ac46d269d5fb66d2a1d1543442) by [@yungsters](https://github.com/yungsters)) +- Remove deprecated removeListener methods ([2596b2f695](https://github.com/facebook/react-native/commit/2596b2f6954362d2cd34a1be870810ab90cbb916) by [@matinzd](https://github.com/matinzd)) +- Remove APPLETVOS variants from BUCk targets. ([cf2e27c388](https://github.com/facebook/react-native/commit/cf2e27c3888ded6f851ba267597ef13f1d0cfd8c) by [@d16r](https://github.com/d16r)) + +#### iOS specific + +- Remove `emulateUnlessSupported` ([c73e021a4b](https://github.com/facebook/react-native/commit/c73e021a4b11bbae3a7868670d140fe3d5dac6ae) by [@ken0nek](https://github.com/ken0nek)) +- Remove USE_CODEGEN_DISCOVERY flag ([2e720c3610](https://github.com/facebook/react-native/commit/2e720c361001d996ed35d8bfbf4dc67c31fb895d) by [@cipolleschi](https://github.com/cipolleschi)) + +### Fixed + +- Throw JSINativeException from asHostObject ([ef6ab3f5ca](https://github.com/facebook/react-native/commit/ef6ab3f5cad968d7b2c9127d834429b0f4e1b2cf) by [@neildhar](https://github.com/neildhar)) +- Use new Babel parser instead of deprecated one ([97291bfa31](https://github.com/facebook/react-native/commit/97291bfa3157ac171a2754e19a52d006040961fb) by [@Kerumen](https://github.com/Kerumen)) +- Fixed a crash on deserialization of props when using 'px'/'em' units. ([70788313fe](https://github.com/facebook/react-native/commit/70788313fedd40fe2e6d1cf15980ce3cca5adaac) by [@nlutsenko](https://github.com/nlutsenko)) +- Fix nullability lost on readonly types in TurboModule specs ([c006722e6c](https://github.com/facebook/react-native/commit/c006722e6cdbe02711cb50ea7a739e0d4d81c7e7) by [@appden](https://github.com/appden)) +- Make tests pass for windows ([9596bf045d](https://github.com/facebook/react-native/commit/9596bf045d527e27608ac4b7b2990a4e6846fdeb) by [@cipolleschi](https://github.com/cipolleschi)) +- Handle possible null exception on ReactEditText with AppCompat 1.4.0 ([24a1f5c66c](https://github.com/facebook/react-native/commit/24a1f5c66c8633f9b41eef45df3297ffc1d2b606) by [@mikemasam](https://github.com/mikemasam)) +- Fixed the disappearance of items when scrolling after zooming VirtualizedList. ([13a72e0ccc](https://github.com/facebook/react-native/commit/13a72e0ccceb2db6aeacd03b4f429d200392c17b) by [@islandryu](https://github.com/islandryu)) +- Improved Flow type inference in Animated `.interpolate()` ([7b86fa2b79](https://github.com/facebook/react-native/commit/7b86fa2b795647f5c89e04e4c3ee4b83bc27ef77) by [@motiz88](https://github.com/motiz88)) +- Add Jest mock for Vibration module ([79529a1c77](https://github.com/facebook/react-native/commit/79529a1c77e7e1b174fdbe8103a2199c9ac924ff) by [@hduprat](https://github.com/hduprat)) +- Allow ReactInstrumentationTest to use custom JSIModules ([eb2a83b0be](https://github.com/facebook/react-native/commit/eb2a83b0be4658654fc6ca6f4671e45f1898798d) by [@christophpurrer](https://github.com/christophpurrer)) +- Working around Long paths limitation on Windows ([883a93871c](https://github.com/facebook/react-native/commit/883a93871cb1fbca4434600a322f63afbba333da) by [@mganandraj](https://github.com/mganandraj)) +- Fix eslint-plugin-specs prepack npm lifecycle hook now that we use npm 8 ([8441c4a6f7](https://github.com/facebook/react-native/commit/8441c4a6f7bfeda73f89f076fe7d8d1132e4b9be) by [@kelset](https://github.com/kelset)) +- Codegen should ignore `.d.ts` files ([0f0d52067c](https://github.com/facebook/react-native/commit/0f0d52067cb89fdb39a99021f0745282ce087fc2) by [@tido64](https://github.com/tido64)) +- Avoid full copy of large folly::dynamic objects in JSIExecutor#defaultTimeoutInvoker ([521011d4cc](https://github.com/facebook/react-native/commit/521011d4cc713dfce97dc8872fd0f5171e587b5d) by [@christophpurrer](https://github.com/christophpurrer)) + +#### Android specific + +- Fixed HorizontalScrollView API scrollToEnd causing NPE in side-effects. ([e5ba6ab7b4](https://github.com/facebook/react-native/commit/e5ba6ab7b482c380e35765b898e522e9d4e1d3b0) by [@ryancat](https://github.com/ryancat)) +- Fix InputAccessoryView crash on Android ([afa5df1764](https://github.com/facebook/react-native/commit/afa5df1764324f2574d102abeae7199d4b02d183) by [@hduprat](https://github.com/hduprat)) +- Bring back non-rootview touch handling based on reactTag ([8b837268b4](https://github.com/facebook/react-native/commit/8b837268b49fd4e72a05f955c20702c457a68fab) by [@fkgozali](https://github.com/fkgozali)) +- Make Text not focusable by default ([8ced165e53](https://github.com/facebook/react-native/commit/8ced165e53135d9d33cfdc55a9d4660f8eb5b3c5) by [@kacieb](https://github.com/kacieb)) +- Revert [PR 33924](https://github.com/facebook/react-native/pull/33924) because of issues with TextInputs with numeric keyboard types not respecting the secureTextEntry prop ([edb27e3aa1](https://github.com/facebook/react-native/commit/edb27e3aa1210ef33d55c1840065457c31b19cb0) by [@charlesbdudley](https://github.com/charlesbdudley)) +- Fix edge case when we enqueue a pending event to views on stopped surface ([ea7c9f2ad9](https://github.com/facebook/react-native/commit/ea7c9f2ad9a78b16234306932edc1d78b783ac27) by [@ryancat](https://github.com/ryancat)) +- Fix a bug where the keyboard, once set as email, won't change back to default. ([ec307e0167](https://github.com/facebook/react-native/commit/ec307e0167deca7f17640cd3c5a60f6be5f47b62) by [@larkox](https://github.com/larkox)) +- NPE in `ReactEditText.setInputType` when React Native is used with some versions of a AppCompat 1.4.x. (and possibly others) ([92ebb298e2](https://github.com/facebook/react-native/commit/92ebb298e2e5ad640754e09ce3a37d3de1d28f58)) +- Fix NPE on `ReactEditText` due to null mFabricViewStateManager ([ba6bf5a3ce](https://github.com/facebook/react-native/commit/ba6bf5a3ce7039a7e407a6632ee41aa3d504f833) by [@cortinico](https://github.com/cortinico)) +- Scroll views would still receive scroll events when nested in a view with `pointer-events: "none"` ([fced96bf52](https://github.com/facebook/react-native/commit/fced96bf5202e8b89b804ccc1004abacc9f91660) by [@javache](https://github.com/javache)) +- Fixed an edge case that event dispatching is failed after pre-allocation of a view and before the view is mounted. ([a093fe5f2f](https://github.com/facebook/react-native/commit/a093fe5f2fae4e9996b0cbffdfccdce8e58e8cf1) by [@ryancat](https://github.com/ryancat)) +- Avoid crash by handling missing views in dispatchViewManagerCommand ([ee1a191cb1](https://github.com/facebook/react-native/commit/ee1a191cb1c10085722d57fc276734f83e86a4f3) by [@hsource](https://github.com/hsource)) +- Pass react build dir to cmake ([6ab7a99518](https://github.com/facebook/react-native/commit/6ab7a99518f8ba0d53e62e35d230ebec78e50217) by [@janicduplessis](https://github.com/janicduplessis)) +- Fix missing space in ReactPropertyException message ([24560b6718](https://github.com/facebook/react-native/commit/24560b67184da00e05491af38289865c4b934ee8) by [@markv](https://github.com/markv)) +- Fix import path breakage ([2e1e62f2bf](https://github.com/facebook/react-native/commit/2e1e62f2bf043ea0bf9926e1f5786ca54a22005e) by [@aniketmathur](https://github.com/aniketmathur)) +- When `onEndReachedThreshold` is set to 0 `onEndReached` function on `VirtualizedList` properly fires once the user scrolls to the bottom of the list. ([b869680c11](https://github.com/facebook/react-native/commit/b869680c1196a6549154a4b9cb7ffa10eab1989c)) +- Fix rendering of transparent borders in RN Android ([a9659ce86d](https://github.com/facebook/react-native/commit/a9659ce86d94dd34768b067763740a5c41917e42) by [@mdvacca](https://github.com/mdvacca)) +- Exception with `Cannot load WebView` message will initialising WebView (along with existing checks) ([9e0d8696cc](https://github.com/facebook/react-native/commit/9e0d8696cc68436a0d309cafde252c55fc337be4) by [@rachitmishra](https://github.com/rachitmishra)) +- Fix accessibilityState overwriting view's disabled state on Android ([f35d18caa3](https://github.com/facebook/react-native/commit/f35d18caa302351319840ec85337182f4f148e5e) by [@okwasniewski](https://github.com/okwasniewski)) +- Make sure *.ts files are considered for task avoidance in the Gradle Plugin ([1a9fb6cb68](https://github.com/facebook/react-native/commit/1a9fb6cb682aa5ff83462e1e2869eb99f3b873fd) by [@cortinico](https://github.com/cortinico)) +- Fix missing import on New Architecture build script in template ([a22f30d2ce](https://github.com/facebook/react-native/commit/a22f30d2ce866cb1488b26bb18eee0620a0ac259) by [@cortinico](https://github.com/cortinico)) + +#### iOS specific + +- Use `NODE_BINARY` from `.xcode.env` when running packager from Xcode ([ff785dbcf5](https://github.com/facebook/react-native/commit/ff785dbcf5c464a4d850fa738e977702efd8abd3) by [@elsurudo](https://github.com/elsurudo)) +- Bug with error message formatting when bundle is missing ([f501979f3d](https://github.com/facebook/react-native/commit/f501979f3d1e5c053eed16967a3d3385eab8e15f) by [@BenLorantfy](https://github.com/BenLorantfy)) +- Fix the race condition when calling readAsDataURL after new Blob(blobs) ([bd12e41188](https://github.com/facebook/react-native/commit/bd12e41188c8d85c0acbd713f10f0bd34ea0edca) by [@wood1986](https://github.com/wood1986)) +- Fix the way the orientation events are published, to avoid false publish on orientation change when app changes state to inactive ([7d42106d4c](https://github.com/facebook/react-native/commit/7d42106d4ce20c644bda4d928fb0abc163580cee) by [@lbaldy](https://github.com/lbaldy)) +- Fix sed error when installing `glog` ([4a7e4b9ca6](https://github.com/facebook/react-native/commit/4a7e4b9ca6ef4fb52611b6c3cb788f624d1f81a4) by [@alphashuro](https://github.com/alphashuro)) +- Don't validate ENTRY_FILE in react-native-xcode.sh ([780fe80fca](https://github.com/facebook/react-native/commit/780fe80fcaf213d84d9d087132af933bd02d1349) by [@janicduplessis](https://github.com/janicduplessis)) +- `_scrollViewComponentView` is set to `RCTPullToRefreshViewComponentView's` superview ([4e4b9e2111](https://github.com/facebook/react-native/commit/4e4b9e2111faaf5652ae1f5b885730b378f3de98) by [@dmytrorykun](https://github.com/dmytrorykun)) +- Use `GCC_PREPROCESSOR_DEFINITIONS` to set `FB_SONARKIT_ENABLED` ([77e6bff629](https://github.com/facebook/react-native/commit/77e6bff629312f20cdacb1e798cd2464ac50db9e) by [@janicduplessis](https://github.com/janicduplessis)) +- Fix Hermes not being properly downloaded during pod install ([d5e0659fcc](https://github.com/facebook/react-native/commit/d5e0659fccf2767beb7aae55461e9690ba335c81) by [@cortinico](https://github.com/cortinico)) +- Typo in the documation for the `automaticallyAdjustKeyboardInsets` prop ([927b43d47c](https://github.com/facebook/react-native/commit/927b43d47c2cd42538265cb06154b12cb0be6816) by [@jeremybarbet](https://github.com/jeremybarbet)) +- Deprecate iOS/tvOS SDK 11.0 support now that 12.4+ is required ([f56d701e56](https://github.com/facebook/react-native/commit/f56d701e567af0c252a2e297bf81cd4add59378a) by [@leotm](https://github.com/leotm)) +- Fix blank spaces that don't recover as you scroll when in an RTL locale and e.nativeEvent.zoomScale is -1. ([bc7b5c3011](https://github.com/facebook/react-native/commit/bc7b5c3011460935614a47a03cd077cd1059de72), [2f491bfa9f](https://github.com/facebook/react-native/commit/2f491bfa9f86c3db2e459e331f39bc3cf12e7239)) +- Fixed paddingTop not being applied when using padding and paddingVertical in multiline textinput ([2fb107c9a6](https://github.com/facebook/react-native/commit/2fb107c9a63aacd2c880ad6abedaad67ffb6022b) by [@hetanthakkar1](https://github.com/hetanthakkar1)) +- Fixed the ability to pass the port to use for Metro when running `react-native run-ios --port `. ([7dc0b5153e](https://github.com/facebook/react-native/commit/7dc0b5153e4eb91c333238a58fe8c75a47cb5f81) by [@lindboe](https://github.com/lindboe)) +- Fix missing imports ([c78babac39](https://github.com/facebook/react-native/commit/c78babac39b7c64e03e137d8fddd91e783303426)) +- Fix React-bridging headers import not found ([c4b51e8d76](https://github.com/facebook/react-native/commit/c4b51e8d7679c3c20b843072581acd23a931fc83) by [@Kudo](https://github.com/Kudo)) +- Fix Hermes executor not available when `use_frameworks` is enabled ([88b7b640a7](https://github.com/facebook/react-native/commit/88b7b640a74bafd918b8b1cd5d58e1f5ddfb730a) by [@Kudo](https://github.com/Kudo)) + +### Security + +- Add GitHub token permissions for workflows ([3da3d82320](https://github.com/facebook/react-native/commit/3da3d82320bd035c6bd361a82ea12a70dba4e851) by [@varunsh-coder](https://github.com/varunsh-coder)) +- Bump RCT-Folly to 2021-07-22 ([68f3a42fc7](https://github.com/facebook/react-native/commit/68f3a42fc7380051714253f43b42175de361f8bd) by [@luissantana](https://github.com/luissantana)) + +## v0.69.6 + +### Changed + +- Bump version of `promise` from 8.0.3 to 8.2.0, enabling `Promise.allSettled` ([951538c080](https://github.com/facebook/react-native/commit/951538c080ef745da304fb308fa91d597e0dd98a) by [@retyui](https://github.com/retyui)) + +### Fixed + +- Fix hermes profiler ([81564c1a3d](https://github.com/facebook/react-native/commit/81564c1a3dae4222858de2a9a34089097f665e82) by [@janicduplessis](https://github.com/janicduplessis)) + +#### Android specific + +- Correctly resolve classes with FindClass(..) ([361b310bcc](https://github.com/facebook/react-native/commit/361b310bcc8dddbff42cf63495649291c894d661) by [@evancharlton](https://github.com/evancharlton)) + +#### iOS specific + +- Fix the way the orientation events are published, to avoid false publish on orientation change when app changes state to inactive ([7d42106d4c](https://github.com/facebook/react-native/commit/7d42106d4ce20c644bda4d928fb0abc163580cee) by [@lbaldy](https://github.com/lbaldy)) +- Fix React module build error with swift integration on new architecture mode ([3afef3c167](https://github.com/facebook/react-native/commit/3afef3c16702cefa5115b059a08741fba255b2db) by [@Kudo](https://github.com/Kudo)) + +## v0.69.5 + +### Changed + +- Bump react-native-codegen to 0.69.2 ([df3d52bfbf](https://github.com/facebook/react-native/commit/df3d52bfbf4254cd16e1dc0ca0af2743cd7e11c1) by [@dmytrorykun](https://github.com/dmytrorykun)) + +#### Android specific + +- Replaced reactnativeutilsjni with reactnativejni in the build process to reduce size ([54a4fcbfdc](https://github.com/facebook/react-native/commit/54a4fcbfdcc8111b3010b2c31ed3c1d48632ce4c) by [@SparshaSaha](https://github.com/SparshaSaha)) + +### Fixed + +- Codegen should ignore `.d.ts` files ([0f0d52067c](https://github.com/facebook/react-native/commit/0f0d52067cb89fdb39a99021f0745282ce087fc2) by [@tido64](https://github.com/tido64)) + +## v0.69.4 + +### Changed + +- Upgrade RN CLI to v8.0.4 ([66c68c37ce](https://github.com/facebook/react-native/commit/66c68c37ce94f6c1160e7f260c0d1887539c6605) by [@thymikee](https://github.com/thymikee)) + +#### Android specific + +- Modified **getDefaultJSExecutorFactory** method ([87cfd386cb](https://github.com/facebook/react-native/commit/87cfd386cb2e02bfa440c94706d9d0274f83070c) by [@KunalFarmah98](https://github.com/KunalFarmah98)) + +## v0.69.3 + +### Fixed + +#### iOS specific + +- Fix React-bridging header not found for third party modules ([fa2acc32d1](https://github.com/facebook/react-native/commit/fa2acc32d1490f6e418689dec321f8bd4ef7bb28) by [@Kudo](https://github.com/Kudo)) + +## v0.69.2 + +### Changed + +- Set react-shallow-renderer v16.15.0 for react v18 compat ([a39a7c453d](https://github.com/facebook/react-native/commit/a39a7c453d87086935ff07d549ba8220cbcf30bd) by [@mikehardy](https://github.com/mikehardy)) +- Upgrade RN CLI to v8.0.3 ([28cbd21d21](https://github.com/facebook/react-native/commit/28cbd21d21f2ffb3f38b2449a4983f013947ce0a) by [@thymikee](https://github.com/thymikee)) + +#### iOS specific + +- Hermes pod: change logic to use the hermes tag to set the pod source correctly ([46a9edc854](https://github.com/facebook/react-native/commit/46a9edc8544ae070149a97ea3d919b88dd6e2942) by [@kelset](https://github.com/kelset)) +- Fix the race condition when calling readAsDataURL after new Blob(blobs) ([bd12e41188](https://github.com/facebook/react-native/commit/bd12e41188c8d85c0acbd713f10f0bd34ea0edca) by [@wood1986](https://github.com/wood1986)) +- Make sure that Flipper pods are not installed when creating a release build ([23accbf58d](https://github.com/facebook/react-native/commit/23accbf58d2fa03ad020e07f00012a32609c7218) by [@cipolleschi](https://github.com/cipolleschi)) + +## v0.69.1 + +### Changed + +#### iOS specific + +- Make all Yoga headers public and add #ifdef __cplusplus ([43f831b23c](https://github.com/facebook/react-native/commit/43f831b23caf22e59af5c6d3fdd62fed3d20d4ec) by [@janicduplessis](https://github.com/janicduplessis)) + +### Fixed + +- Use monotonic clock for performance.now() ([114d31feee](https://github.com/facebook/react-native/commit/114d31feeeb47f5a57419e5088c3cbe9340f757a)) + +#### iOS specific + +- Fix build for React-RCTText ([4ea38e16bf](https://github.com/facebook/react-native/commit/4ea38e16bf533955557057656cba5346d2372acd) by [@ph4r05](https://github.com/ph4r05)) +- Fix RCT-Folly build error when use_frameworks! and hermes are both enabled ([79baca678a](https://github.com/facebook/react-native/commit/79baca678a743560fa16fdd551f1d0d018d34304) by [@Kudo](https://github.com/Kudo)) +- Fix use_frameworks! for 0.69 ([f97c6a5b49](https://github.com/facebook/react-native/commit/f97c6a5b498eec95e99a02c7842cb2ae160cd6cd) by [@Kudo](https://github.com/Kudo)) + +## v0.69.0 + +### Breaking + +- Support for `console.disableYellowBox` [has been dropped](https://github.com/facebook/react-native/commit/b633cc130533f0731b2577123282c4530e4f0abe) +- Already deprecated prop types have been removed ([cdfddb4dad](https://github.com/facebook/react-native/commit/cdfddb4dad7c69904850d7e5f089a32a1d3445d1), [3e229f27bc](https://github.com/facebook/react-native/commit/3e229f27bc9c7556876ff776abf70147289d544b), [10199b1581](https://github.com/facebook/react-native/commit/10199b158138b8645550b5579df87e654213fe42)) +- `removeListener`, deprecated since RN0.65, [was removed](https://github.com/facebook/react-native/commit/8dfbed786b40082a7a222e00dc0a621c0695697d) from Appearance +- If you were using `SegmentedComponentIOS`, you will now need to move to the [segmented-control](https://github.com/react-native-segmented-control/segmented-control) library ([235f168574](https://github.com/facebook/react-native/commit/235f1685748442553e53f8ec6d904bc0314a8ae6)) + +### Added + +- Add Hermes scripts to package ([004b8609d9](https://github.com/facebook/react-native/commit/004b8609d97b14a6d5cb8c9e63afdbe343c500da) by [@hramos](https://github.com/hramos)) +- Expose scheduler through FabricUIManager ([1730949e94](https://github.com/facebook/react-native/commit/1730949e94aa23927a90d2a64d91977b7e2904d6) by [@cortinico](https://github.com/cortinico)) +- Add event listeners to Scheduler ([e51e19ecc1](https://github.com/facebook/react-native/commit/e51e19ecc1d1b8ac5c860eac55338ef13471844f) by [@cortinico](https://github.com/cortinico)) +- C++ TurboModule methods can return functions ([c7380ba113](https://github.com/facebook/react-native/commit/c7380ba1131b26b487ecae87239a4cf82afefd15) by [@appden](https://github.com/appden)) +- Add support for devtools' profiler ([fefa7b6ac8](https://github.com/facebook/react-native/commit/fefa7b6ac8a1e0e33fa7a1070936c5c83c873c0a) by [@jpporto](https://github.com/jpporto)) +- Add getAll function to FormData class for getting all parts containing that key. This is also available in web API. ([d05a5d1551](https://github.com/facebook/react-native/commit/d05a5d15512ab794ef80b31ef91090d5d88b3fcd) by [@matinzd](https://github.com/matinzd)) +- Automatic type conversions for C++ TurboModules ([31f0796237](https://github.com/facebook/react-native/commit/31f079623732fb017b1fa38d56abe855d7738ece) by [@appden](https://github.com/appden)) +- New bridging API for JSI <-> C++ ([30cb78e709](https://github.com/facebook/react-native/commit/30cb78e709bccb4f7bf7aab3f6b0f1ba4261f577) by [@appden](https://github.com/appden)) +- Add asBool() method to JSI ([603620b739](https://github.com/facebook/react-native/commit/603620b7394da5855e2255790bfea9ad7d80ddf9) by [@appden](https://github.com/appden)) +- CustomEvent and Event polyfills for React Native ([6abbef1200](https://github.com/facebook/react-native/commit/6abbef1200af9adab1848de17955d77fbe0ad5da) by [@JoshuaGross](https://github.com/JoshuaGross)) +- Implement Runtime.getHeapUsage for hermes chrome inspector ([cff9590864](https://github.com/facebook/react-native/commit/cff9590864c4be153a4eb49757b7cac8b3f23f66) by [@janicduplessis](https://github.com/janicduplessis)) +- Introduce ReactNativeFeatureFlags file to control FeatureFlags in React Native ([33aba77456](https://github.com/facebook/react-native/commit/33aba774564acdec216e02e28f17ad08ad7bc26b) by [@mdvacca](https://github.com/mdvacca)) +- Added fail-safe check to catch MissingWebViewPackage Exception ([8c573d9336](https://github.com/facebook/react-native/commit/8c573d933652ae4da1008502c53fce93057101c0) by [@Kunal-Airtel2022](https://github.com/Kunal-Airtel2022)) +- Add ability to access properties with symbol keys through JSI ([9010bfe457](https://github.com/facebook/react-native/commit/9010bfe457b77862024214ce6210504ff1786ef5) by [@neildhar](https://github.com/neildhar)) +- Allow color styles to be animated using native driver ([201f355479](https://github.com/facebook/react-native/commit/201f355479cafbcece3d9eb40a52bae003da3e5c) by [@genkikondo](https://github.com/genkikondo)) +- Make react-native depend on react-native-gradle-plugin ([3346efb7d4](https://github.com/facebook/react-native/commit/3346efb7d422bd8eb7f48650b454071f9981fa0b) by [@cortinico](https://github.com/cortinico)) +- Add RawEventTelemetryEventEmitter interface to ReactNativePrivateInterface ([1f15a64028](https://github.com/facebook/react-native/commit/1f15a6402869b001cae049facc17126924b97197) by [@JoshuaGross](https://github.com/JoshuaGross)) +- Implement Runtime.getHeapUsage for hermes chrome inspector ([3568a72987](https://github.com/facebook/react-native/commit/3568a7298738a651d76c70763362c297ab601ee8) by [@janicduplessis](https://github.com/janicduplessis)) +- Add support for C++17 in OSS ([c2e4ae39b8](https://github.com/facebook/react-native/commit/c2e4ae39b8a5c6534a3fa4dae4130166eda15169) by [@sammy-SC](https://github.com/sammy-SC)) + +#### Android specific + +- Generate `Nullable` for optional objects and arrays in module codegen. ([ffaa5d69bc](https://github.com/facebook/react-native/commit/ffaa5d69bc268918891121e2d60e7ca08ee82530)) +- Expose an API to enable Concurrent Root on Android ([d7b64b8d4b](https://github.com/facebook/react-native/commit/d7b64b8d4b2f403ce00b27c5df89ffb3a64dc6de) by [@cortinico](https://github.com/cortinico)) +- Add scrollEventThrottle prop support in Android ([cf55fd587e](https://github.com/facebook/react-native/commit/cf55fd587e6cc82a73079be6076d244ab72fa359) by [@ryancat](https://github.com/ryancat)) +- Accessibility announcement for list and grid in FlatList ([dd6325bafe](https://github.com/facebook/react-native/commit/dd6325bafe1a539d348f3710e717a6344576b859) by [@fabriziobertoglio1987](https://github.com/fabriziobertoglio1987)) +- Introduce ModuleDataCleaner.cleanDataFromModules(ReactContext) ([184dfb8f8b](https://github.com/facebook/react-native/commit/184dfb8f8bd4dfbb8d1575e9554e3f3361793015) by [@RSNara](https://github.com/RSNara)) +- Introduce ReactContext.getNativeModules() ([b978308519](https://github.com/facebook/react-native/commit/b978308519f71c6c7fda4b38a842aa219a349275) by [@RSNara](https://github.com/RSNara)) +- MapBuffer implementation for JVM -> C++ communication ([cf6f3b680b](https://github.com/facebook/react-native/commit/cf6f3b680b43fae31e97b14af681293503025a0c)) +- Make links independently focusable by Talkback ([7b5b114d57](https://github.com/facebook/react-native/commit/7b5b114d578142d18bf4a7a5279b179a9ac8d958) by [@fabriziobertoglio1987](https://github.com/fabriziobertoglio1987)) +- Support animating text color with native driver ([87cdb607e4](https://github.com/facebook/react-native/commit/87cdb607e4792156d433c44b89932e7dae3371da) by [@genkikondo](https://github.com/genkikondo)) +- Added an experimental prop serialization path based on MapBuffer ([cbcdaae2b5](https://github.com/facebook/react-native/commit/cbcdaae2b5dda2a44c95d83dcb5b5aa0f43bc6f9)) +- Allow to setup a Gradle Enterprise instance via an external script ([f11dcfaea1](https://github.com/facebook/react-native/commit/f11dcfaea14249b059aea2474ce36a0665140d4f) by [@cortinico](https://github.com/cortinico)) +- Support platform color with AnimatedColor ([cb42049e0a](https://github.com/facebook/react-native/commit/cb42049e0ae262afe907ace1099414836ab0018d) by [@genkikondo](https://github.com/genkikondo)) +- Support running animations with AnimatedColor with native driver ([3f49e6763e](https://github.com/facebook/react-native/commit/3f49e6763e66447f6ae17dc2f032e27330b7b74a) by [@genkikondo](https://github.com/genkikondo)) +- Add public API to ReactRootView to control if JS touch events are dispatched ([0a517ae438](https://github.com/facebook/react-native/commit/0a517ae43892fb764d829f8bae56c1ac58356b1b) by [@ryancat](https://github.com/ryancat)) + +#### iOS specific + +- Prepare a method in the AppDelegate to control the concurrentRoot. ([8ac8439e0d](https://github.com/facebook/react-native/commit/8ac8439e0dcc0cc4a9c0cc99f614a5e19bae56eb) by [@cipolleschi](https://github.com/cipolleschi)) +- `hotkeysEnabled` property is added to `RCTDevMenu` which allows enabling/disabling hotkeys that triggers developer menu popup ([1a1a304ed2](https://github.com/facebook/react-native/commit/1a1a304ed2023d60547aef65b1a7bf56467edf08)) +- Allow modifying iOS image cache limits ([61b013e7ad](https://github.com/facebook/react-native/commit/61b013e7ad8a1cc28ee39434d2fd96b74b96cf5f) by [@danilobuerger](https://github.com/danilobuerger)) +- Add dismissActionSheet method to ActionSheetIOS ([64ebe5bbdd](https://github.com/facebook/react-native/commit/64ebe5bbdd32fc3b3a243a8a81a6f724d8f81267) by [@gabrieldonadel](https://github.com/gabrieldonadel)) +- Integrated the `accessibilityLanguage` prop to all the available components. The prop is available for any platform but it will work only on iOS. ([7b05b091fd](https://github.com/facebook/react-native/commit/7b05b091fd97f95b778369277ac2147730abc7b8) by [@dgopsq](https://github.com/dgopsq)) +- Support running animations with AnimatedColor with native driver ([49f3f47b1e](https://github.com/facebook/react-native/commit/49f3f47b1e9b840e4374d46b105604f4d2c22dd5) by [@genkikondo](https://github.com/genkikondo)) + +### Changed + +- Update direct Metro dependencies to 0.70.1 ([b74e964e70](https://github.com/facebook/react-native/commit/b74e964e705c40834acad7020562e870cdad9db1), ([c92b64b16a](https://github.com/facebook/react-native/commit/c92b64b16a5710c1dfaea9af4c271931e4669636) by [@arushikesarwani94](https://github.com/arushikesarwani94)), ([f89a0b765c](https://github.com/facebook/react-native/commit/f89a0b765c09c9aba573f03777cc76673989628f) by [@robhogan](https://github.com/robhogan)) +- Upgrade RN CLI to v8.0.0 ([0605880c9e](https://github.com/facebook/react-native/commit/0605880c9ed0aec812f3198eb5075db64fba969a), [1e0226f933](https://github.com/facebook/react-native/commit/1e0226f933814bf9ada87eaa14348bfff863ead1), [24bb7f7380](https://github.com/facebook/react-native/commit/24bb7f7380662925f078d78a03fbc954af2da3d6), [7dceb9b63c](https://github.com/facebook/react-native/commit/7dceb9b63c0bfd5b13bf6d26f9530729506e9097) by [@thymikee](https://github.com/thymikee)) +- Replace use-subscripton with use-sync-external-store ([93b50be8c2](https://github.com/facebook/react-native/commit/93b50be8c2341a0daf41f6fdc656896c4907c4dc) by [@rickhanlonii](https://github.com/rickhanlonii)) +- Expose UIManager from Scheduler ([54db5f2012](https://github.com/facebook/react-native/commit/54db5f201292ebf267800d92b7dd5bfa22431963) by [@cortinico](https://github.com/cortinico)) +- Optimized VirtualizedList context when used with nested lists ([ceb0a54608](https://github.com/facebook/react-native/commit/ceb0a546083509192c059cdd93d6aa379e38ef4e) by [@javache](https://github.com/javache)) +- Remove usage of std::string in EarlyJsErrorHandler. ([30051b2c41](https://github.com/facebook/react-native/commit/30051b2c4185bff015c72069488b5f6ba3391ad7) by [@sshic](https://github.com/sshic)) +- `eslint-config`: add support for ESLint 8 ([864a8c11b2](https://github.com/facebook/react-native/commit/864a8c11b2a7540f607ebc0e084edd7393169359) by [@wcandillon](https://github.com/wcandillon)) +- `eslint-config`: add support for TypeScript 4.5+ ([199ac680c7](https://github.com/facebook/react-native/commit/199ac680c7867a982e25620219bffa18f85f5404) by [@rnike](https://github.com/rnike)) +- Upgraded react-devtools-core dependency to 4.24.0 ([a7a781ff4a](https://github.com/facebook/react-native/commit/a7a781ff4a13e744f4eb3007ef0657740b277a72)) +- Avoid flattening nodes with event props ([980c52de41](https://github.com/facebook/react-native/commit/980c52de41258f6cf2d2360144ea7ca16a19c9f8)) +- Type the argument of Animated.interpolate as read-only ([6584304c10](https://github.com/facebook/react-native/commit/6584304c100ce4d51a5c4d606170a6ad0dc00875) by [@motiz88](https://github.com/motiz88)) +- Update gradle-download-task to 5.0.1 to support concurrent downloads ([a86cae7aac](https://github.com/facebook/react-native/commit/a86cae7aacc9837536e7d679870a57dcd0f45475) by [@michel-kraemer](https://github.com/michel-kraemer)) +- Logging a soft error when ReactRootView has an id other than -1 instead of crashing the app in hybrid apps ([1ca2c24930](https://github.com/facebook/react-native/commit/1ca2c2493027c1b027146cd41e17dd8a4fc33a41) by [@Kunal-Airtel2022](https://github.com/Kunal-Airtel2022)) +- Upgrade to React 18 ([41cbccd98d](https://github.com/facebook/react-native/commit/41cbccd98dd6c98d1f662674164cf455105a1359) by [@rickhanlonii](https://github.com/rickhanlonii)) + +#### Android specific + +- Gradle: extend the algoritm to find hermesc paths ([aeac6ab677](https://github.com/facebook/react-native/commit/aeac6ab6773cd2c0ca7abe9e5aa3f22fa81683e5) by [@cortinico](https://github.com/cortinico)) +- Bump boost for Android to 1.76 to align with iOS ([5cd6367f0b](https://github.com/facebook/react-native/commit/5cd6367f0b86543274a15bb6d0e53a8545fed845) by [@kelset](https://github.com/kelset)) +- Adopt `MapBuffer` interface for `ReadableMapBuffer` ([81e4249315](https://github.com/facebook/react-native/commit/81e42493158edd5e7b88f98c19c87e9d61ba4aba)) +- Mark intent as nullable ([5ffa0b0aa6](https://github.com/facebook/react-native/commit/5ffa0b0aa6c523234c634167be1f94b0d9edb0f7) by [@sshic](https://github.com/sshic)) +- Use CMake to build ReactAndroid module ([e3830ddffd](https://github.com/facebook/react-native/commit/e3830ddffd9260fe071e0c9f9df40b379d54cf26)) +- Update template/android and RN Tester to use `hermes-engine` from the `react-native` NPM package. ([4d91f40fbd](https://github.com/facebook/react-native/commit/4d91f40fbdf0012689b04084113299676342c0dc) by [@cortinico](https://github.com/cortinico)) +- Build Hermes from Source ([a3d9892ed9](https://github.com/facebook/react-native/commit/a3d9892ed9c993d16fa36fa6b713e2ead43fcc77) by [@cortinico](https://github.com/cortinico)) +- Rename field with default values for ReactConfig to DEFAULT_CONFIG ([964e816752](https://github.com/facebook/react-native/commit/964e81675286c80a8e322127aa7c052f62621098)) +- Moved `com/react/facebook/uimanager/interfaces` files into `com/react/facebook/uimanager` to enable Kotlin build ([b1a779392d](https://github.com/facebook/react-native/commit/b1a779392d483c649d428debfe4a6405247b8c0e)) +- Bump AGP to 7.1.0 and fix bundle inclusion in release mode ([200488e87c](https://github.com/facebook/react-native/commit/200488e87cf4bc355e03c78cd814b97b23452117) by [@gabrieldonadel](https://github.com/gabrieldonadel)) +- Release react-native-gradle-plugin 0.0.5 ([42272211e4](https://github.com/facebook/react-native/commit/42272211e4a1b7cff7770b59cf1bcf649cbdd6fc) by [@cortinico](https://github.com/cortinico)) +- ViewPagerAndroid recommendation link. ([7e8cce3d2d](https://github.com/facebook/react-native/commit/7e8cce3d2ddffbe36bcb3c9ec2f006f7e1b42a79) by [@maaxg](https://github.com/maaxg)) +- Bump android Appcompat to 1.4.1 ([6b61995647](https://github.com/facebook/react-native/commit/6b61995647c789a567845521fed7b0cc1e0cddb7) by [@gabrieldonadel](https://github.com/gabrieldonadel)) +- Remove `react-native-gradle-plugin` as a dependency from template's package.json ([cd79317672](https://github.com/facebook/react-native/commit/cd79317672e5c99636346f2abb641a688a4ceb82) by [@cortinico](https://github.com/cortinico)) +- Use 2g as a default heap size for gradle builds ([09e418ef8e](https://github.com/facebook/react-native/commit/09e418ef8e98fd026cf828696ff2475993b76ac2)) +- Use new StatusBar API on Android 11 (API 30)+ ([50c8e973f0](https://github.com/facebook/react-native/commit/50c8e973f067d4ef1fc3c2eddd360a0709828968) by [@ieatfood](https://github.com/ieatfood)) +- Change static string to public ([ab45138394](https://github.com/facebook/react-native/commit/ab45138394f41aeb13370882837968636de04c24) by [@sshic](https://github.com/sshic)) + +#### iOS specific + +- Use pre-built HermesC if available in current React Native release ([644fe430fd](https://github.com/facebook/react-native/commit/644fe430fdecc0bf1fa098d1c2d52178da6c987c) by [@hramos](https://github.com/hramos)) +- When building Hermes from source, the filesystem will now be prepared using the new hermes-utils.js scripts, outside of CocoaPods ([aaa01f7710](https://github.com/facebook/react-native/commit/aaa01f77106f891696d9ec508e2ee71111a6af2a) by [@hramos](https://github.com/hramos)) +- Expose scheduler through RCTSurfacePresenter ([614aa86916](https://github.com/facebook/react-native/commit/614aa86916394d8ee2ecb236f38de6bb7e161ca2) by [@cortinico](https://github.com/cortinico)) +- Adopt UIGraphicsImageRenderer API ([d70d7fd0b3](https://github.com/facebook/react-native/commit/d70d7fd0b3984ee54622afc4692a6c945618c345) by [@matrush](https://github.com/matrush)) +- Build Hermes from source when Hermes is used ([bb01b75637](https://github.com/facebook/react-native/commit/bb01b75637edc1159a3bdb3af86936e1c92f39c1) by [@hramos](https://github.com/hramos)) +- Update CodeGen scripts to accept custom node executable ([323db75c36](https://github.com/facebook/react-native/commit/323db75c36d26d771f6b231c8eabc5afc0da74d3) by [@cipolleschi](https://github.com/cipolleschi)) +- Fixed the fallback behavior when the `.xcode.env` file is missing, actually using the old `find-node-for-xcode.sh` script ([705c6f57d6](https://github.com/facebook/react-native/commit/705c6f57d66b4499f43489292183a58413402a74) by [@cipolleschi](https://github.com/cipolleschi)) +- Adding a link in a message for the users. ([2c52131f5e](https://github.com/facebook/react-native/commit/2c52131f5e0eb4668681242fcdd8150afe3c5827) by [@cipolleschi](https://github.com/cipolleschi)) +- Bump ruby to 2.7.5 ([2c87b7466e](https://github.com/facebook/react-native/commit/2c87b7466e098c5cd230e02b279fc7bc7a357615) by [@danilobuerger](https://github.com/danilobuerger)) +- This PR removes the `find-node.sh` scripts and replaces it with an `.xcode.env` file that is sourced by the script phases that needs it. The `.xcode.env` file is versioned: to customize a local environment, an unversioned `.xcode.local.env` can be used. ([0480f56c5b](https://github.com/facebook/react-native/commit/0480f56c5b5478b6ebe5ad88e347cad2810bfb17) by [@cipolleschi](https://github.com/cipolleschi)) +- Update `PushNotificationIOS.checkPermissions` to include iOS 10+ notification settings. ([17ecd2fb5b](https://github.com/facebook/react-native/commit/17ecd2fb5b3cfb8aa0282ed406b16dc3b9777018)) +- Enable SonarKit in React-Core when the configuration is `'Debug'` ([b5343a6b0d](https://github.com/facebook/react-native/commit/b5343a6b0dd07c1b4ef9dac549df67a4d68ebd1e) by [@cipolleschi](https://github.com/cipolleschi)) +- When Hermes is enabled, the Hermes Engine will be built from source instead of using the pre-built `hermes-engine` CocoaPod. ([12ad1fffe8](https://github.com/facebook/react-native/commit/12ad1fffe87c0c5ab2e001f318ff4f8d3eda7479) by [@hramos](https://github.com/hramos)) +- Replaced folly::Optional with std::optional from C++17 in Objc module generator. ([45e2941367](https://github.com/facebook/react-native/commit/45e2941367fbf13584193bbda598173802289167) by [@philIip](https://github.com/philIip)) +- Removed methodName parameter that was used only for a warning message and moved the warning parameter to be calculated inline. ([cfb11ca2f6](https://github.com/facebook/react-native/commit/cfb11ca2f67c59c090b8a58b2b7bdaacef0e19df)) +- Fix the crash caused by nil partialLoadHandler ([46bc521513](https://github.com/facebook/react-native/commit/46bc521513c9c78e5ffc49cf3e571757e1a91cef)) +- Synchronously render cached images ([189c2c8958](https://github.com/facebook/react-native/commit/189c2c8958442541c6b4f42860b2943ece612da2)) +- Updated Flipper-Glog to 0.5.0.4 ([cd60ffdb62](https://github.com/facebook/react-native/commit/cd60ffdb62b2183cd24baef3075d56f758cea24a)) +- Add function to report early js errors ([1804951595](https://github.com/facebook/react-native/commit/180495159517dc0bfa103621e5ff62fc04cb3c8b) by [@sshic](https://github.com/sshic)) + +### Deprecated + +- Deprecate the use of `react-native/jest/preprocessor.js` by external projects ([c1e9aa9a27](https://github.com/facebook/react-native/commit/c1e9aa9a272aed3cba60c4aeff783eeb8bffce68) by [@motiz88](https://github.com/motiz88)) +- Deprecate the Promise.prototype.done method and log a warning when it's called in development. ([35800962c1](https://github.com/facebook/react-native/commit/35800962c16a33eb8e9ff1adfd428cf00bb670d3) by [@motiz88](https://github.com/motiz88)) + +#### iOS specific + +- Deprecating support for iOS/tvOS SDK 11.0, 12.4+ is now required ([5f2835b14d](https://github.com/facebook/react-native/commit/5f2835b14d35681c268dd64d6ec284ea5f053be3), ([c71e6efbcd](https://github.com/facebook/react-native/commit/c71e6efbcd2b95faee327d9763d321488120bc5e), ([982ca30de0](https://github.com/facebook/react-native/commit/982ca30de079d7e80bd0b50365d58b9048fb628f) by [@philIip](https://github.com/philIip)) + +#### iOS specific + +- Removed lint restricting `DynamicColorIOS` to only two properties ([13b0b06522](https://github.com/facebook/react-native/commit/13b0b0652259ada468cc044b0b604edb666b2eb9)) + +### Fixed + +- Remove unactionable warning about `codegenNativeComponent` when on 'Paper' ([494b73cb33](https://github.com/facebook/react-native/commit/494b73cb33197fa865e9ead8fdca11bce6822917) by [@tido64](https://github.com/tido64)) +- Fix typo in Value's constructor with a Symbol ([a7a0f86a73](https://github.com/facebook/react-native/commit/a7a0f86a73ab51be31fb2c3205612d7ff1fb5384) by [@jpporto](https://github.com/jpporto)) +- Avoid full copy of large folly::dynamic objects by switching to std::move semantics ([3f98c8e4c2](https://github.com/facebook/react-native/commit/3f98c8e4c2c8f40b81c1a90aa65c1bdc9327faed) by [@NikoAri](https://github.com/NikoAri)) +- Fix performance issue on Animated.interpolate with big input range ([f503b21203](https://github.com/facebook/react-native/commit/f503b212039f79f00ea56b65ecf3cd150b82f087) by [@Almouro](https://github.com/Almouro)) +- Update function spacing linting rules ([8650220cf9](https://github.com/facebook/react-native/commit/8650220cf99739c4b904a37ce4f19ce7dfd3bdbb) by [@joeframbach](https://github.com/joeframbach)) +- Add supportsFromJs and supportsToJs template variables ([087624ccaf](https://github.com/facebook/react-native/commit/087624ccaf2e484c0b6425e57edf9afd62a06e9a) by [@appden](https://github.com/appden)) +- The Array appended to FormData is transmitted as a string ([d2e8e7d58e](https://github.com/facebook/react-native/commit/d2e8e7d58e680e0bb3b4da1f820dd4dd840639f5) by [@bang9](https://github.com/bang9)) +- AppState.removeEventListener correctly removes listener for blur and focus events ([9aab25ec53](https://github.com/facebook/react-native/commit/9aab25ec536473ffe6d22c5efeae8fea6bd769be) by [@AntoineDoubovetzky](https://github.com/AntoineDoubovetzky)) +- `focus()` on TextInput to respect its `editable` state ([8a5460ce80](https://github.com/facebook/react-native/commit/8a5460ce80e69c11a007121d4278d55642f6b10e) by [@vonovak](https://github.com/vonovak)) +- Restore Windows build with RawPropsParser.cpp ([2d64d1d693](https://github.com/facebook/react-native/commit/2d64d1d69360161c047c86a026403d8074ba28bb) by [@TatianaKapos](https://github.com/TatianaKapos)) +- Fix babel-plugin-codegen crash when export init is null ([ae756647c9](https://github.com/facebook/react-native/commit/ae756647c9b8a88ba615fd30185f621825a33427) by [@janicduplessis](https://github.com/janicduplessis)) +- Fixed compilation warning due to `using namespace` being used as part of header ([009d80bf5a](https://github.com/facebook/react-native/commit/009d80bf5a55dd74be448960b1344ac7599c6bae) by [@arhelmus](https://github.com/arhelmus)) +- Allow including TurboModule.h in mixed rtti/no-rtti environment, even if TurboModule.h/cpp is compiled without RTTI. ([1f87729697](https://github.com/facebook/react-native/commit/1f87729697370a4ab31e2bb9ab1780438d9e146f) by [@nlutsenko](https://github.com/nlutsenko)) +- Remove prettier from dependencies in eslint-config ([2db1bca952](https://github.com/facebook/react-native/commit/2db1bca95224ce39484c3f27508aec9a21ce126a) by [@Kerumen](https://github.com/Kerumen)) +- Switch Component doesn't disable click functionality when disabled ([b2e625a517](https://github.com/facebook/react-native/commit/b2e625a51723becea4cef0433448fbec679669ee) by [@fabriziobertoglio1987](https://github.com/fabriziobertoglio1987)) +- Support numeric color values in StyleSheet's Flow types ([83b1975b90](https://github.com/facebook/react-native/commit/83b1975b90569a36020da33156615a13fcc7ba92) by [@motiz88](https://github.com/motiz88)) +- Fix build break on Windows with ReactCommon ([42b391775f](https://github.com/facebook/react-native/commit/42b391775f663df335f6f2553104fc2fa35b1bee) by [@chiaramooney](https://github.com/chiaramooney)) +- Fixed opacity value in TouchableOpacity ([3eddc9abb7](https://github.com/facebook/react-native/commit/3eddc9abb70eb54209c68aab7dbd69e363cc7b29) by [@hetanthakkar1](https://github.com/hetanthakkar1)) +- Remove illegal private property access in VirtualizedSectionList.scrollToLocation ([b2f871a6fa](https://github.com/facebook/react-native/commit/b2f871a6fa9c92dd0712055384b9eca6d828e37d) by [@motiz88](https://github.com/motiz88)) +- JS animated node value updates properly when listener is attached ([1f778014a7](https://github.com/facebook/react-native/commit/1f778014a7e95c5c473898c38d5b1e0725cd373c) by [@genkikondo](https://github.com/genkikondo)) +- Working around Long paths limitation on Windows ([7b76abc0d3](https://github.com/facebook/react-native/commit/7b76abc0d3a0a5bec37f314c80954e412fc5f5ec) by [@mganandraj](https://github.com/mganandraj)) +- Fix VirtualizedList with initialScrollIndex not rendering all elements when data is updated ([c5c17985da](https://github.com/facebook/react-native/commit/c5c17985dae402725abb8a3a94ccedc515428711) by [@AntoineDoubovetzky](https://github.com/AntoineDoubovetzky)) + +#### Android specific + +- Add back hermes inspector support ([6b6adcc111](https://github.com/facebook/react-native/commit/6b6adcc111123bec2c4c110070b2506385e74664) by [@Kudo](https://github.com/Kudo)) +- Fixed issue where any node with an AccessibilityDelegate set (which was any node with any accessibility propoerty), was using ExploreByTouchHelper's built in AccessibilityNodeProvider, and not properly populating their AccessibilityNodeInfo's, leading to focus issues and issues with automated test services like UIAutomator. ([70fcab76a4](https://github.com/facebook/react-native/commit/70fcab76a4dcf65e628ac897620fe050758574e3) by [@blavalla](https://github.com/blavalla)) +- Fix Extras usage in Android implementation of Linking.sendIntent() ([86f8d0bb52](https://github.com/facebook/react-native/commit/86f8d0bb528a75777c357ae214643ed58c326ca9)) +- Fix typo in gradle plugin deprecation message ([41cfd2f976](https://github.com/facebook/react-native/commit/41cfd2f9768e4742eedd299ab467d316d016705e) by [@mikehardy](https://github.com/mikehardy)) +- Fixed `TimingModule` related functions for headless JS tasks, eg. `setTimeout` ([dac56ce077](https://github.com/facebook/react-native/commit/dac56ce0776e0e4d23ed4f8b324f2e2432aefa6a) by [@marcesengel](https://github.com/marcesengel)) +- Improve support for Android users on M1 machine ([c5babd993a](https://github.com/facebook/react-native/commit/c5babd993a2bed2994ecc4710fa9e424b3e6cfc2) by [@cortinico](https://github.com/cortinico)) +- Do not use `rootProject` directly in Gradle scripts ([b2bc5aa5c9](https://github.com/facebook/react-native/commit/b2bc5aa5c903ad057a53d4caa82b0fe74e01c07c) by [@cortinico](https://github.com/cortinico)) +- Adding null check for context in redbox surface delegate ([9527ab1584](https://github.com/facebook/react-native/commit/9527ab1584869d7966c562e8aa7cbf48788156a3) by [@ryancat](https://github.com/ryancat)) +- Fix crash on empty snapToOffsets array ([145fd041c7](https://github.com/facebook/react-native/commit/145fd041c7afe9a18f08f461487bb515ab2f516a) by [@ryancat](https://github.com/ryancat)) +- Fix StatusBar not updating to use translucent values when set to the same value across different activities ([d34a75e9e5](https://github.com/facebook/react-native/commit/d34a75e9e5932adcac4a16f5b815bb909c3aa0dd)) +- Fix underlineColorAndroid transparent not working on API 21 ([52aee50a70](https://github.com/facebook/react-native/commit/52aee50a704bbeab91f5fa05fe3220dee304422f) by [@fabriziobertoglio1987](https://github.com/fabriziobertoglio1987)) +- Fixed regression on content in scroll view not responding to touch when fling got interrupted ([bb8ff9260f](https://github.com/facebook/react-native/commit/bb8ff9260fe6a783171f35ce1a459927d8179d08) by [@ryancat](https://github.com/ryancat)) +- Fixes android build error when compiling as library ([c34ef5841c](https://github.com/facebook/react-native/commit/c34ef5841cf3a63a9cc96add577d6bf6d52e4397) by [@nickfujita](https://github.com/nickfujita)) +- Cancel post touch process when new touch is received ([0368081858](https://github.com/facebook/react-native/commit/0368081858193d7c2537acd9080d11bb701ee98b) by [@ryancat](https://github.com/ryancat)) +- Improve rendering of images when resampled and corner radius applied ([f743bed657](https://github.com/facebook/react-native/commit/f743bed657591b078300a6519e3d68db542fd757) by [@javache](https://github.com/javache)) +- Fix transform when calculate overflowInset ([0975e96d53](https://github.com/facebook/react-native/commit/0975e96d53546ac05b2154352fe56e5d82e2a1f8) by [@ryancat](https://github.com/ryancat)) +- Fix ReactHorizontalScrollView contentOffset ([9f6f97151c](https://github.com/facebook/react-native/commit/9f6f97151c44a0f727c9dd938222be1860ecf3f9) by [@genkikondo](https://github.com/genkikondo)) +- Text Component does not announce disabled and disables click functionality when disabled ([7b2d8178b1](https://github.com/facebook/react-native/commit/7b2d8178b155f5f1b247614c46e5e20f31bbd438) by [@fabriziobertoglio1987](https://github.com/fabriziobertoglio1987)) +- Fix StatusBar on Android API 30 ([9ed2df628d](https://github.com/facebook/react-native/commit/9ed2df628ddd410cc3383e68b0386471432445c0) by [@ieatfood](https://github.com/ieatfood)) +- Use root locale when converting string case. ([5341ad8962](https://github.com/facebook/react-native/commit/5341ad896245c40a00b6faead1b90d01aac58f8c) by [@halaei](https://github.com/halaei)) +- Fix DarkMode on Calendar DateTimePicker ([97064ae1fb](https://github.com/facebook/react-native/commit/97064ae1fbf84a8a6b653c02c5872191b7d2d622) by [@mdvacca](https://github.com/mdvacca)) +- Fix ScrollView contentOffset ([be260b9f47](https://github.com/facebook/react-native/commit/be260b9f479a3b55ee43d2959d2c49fd3c1eb4ac) by [@genkikondo](https://github.com/genkikondo)) +- Do not bundle libhermes.so or libjsc.so inside the React Native Android AAR ([fa85417179](https://github.com/facebook/react-native/commit/fa854171798e67b8a10820f77d7198315e1784ed) by [@cortinico](https://github.com/cortinico)) +- Enable hitSlop to be set using a single number. ([d682753244](https://github.com/facebook/react-native/commit/d682753244feba28c6a15c31966a3da075a090e6) by [@javache](https://github.com/javache)) +- Fix crash caused by Image.queryCache parsing null ([ae3d4f7008](https://github.com/facebook/react-native/commit/ae3d4f700843ae4cbb6927ee620095136d1abc3f) by [@skychx](https://github.com/skychx)) +- Fix NullPointerException when disaptching events ([fbeb51ef51](https://github.com/facebook/react-native/commit/fbeb51ef5133303a5cb71569507d44403ded3447) by [@mdvacca](https://github.com/mdvacca)) + +#### iOS specific + +- ScrollView's contentInsetAdjustmentBehavior is reset to Never at every reuse to avoid layout artifacts. ([28a65f4387](https://github.com/facebook/react-native/commit/28a65f438789c29309d6e7c58063a73ca721ef43)) +- Prevent Nullptr segfault in TurboModule init path ([7f3cc256b5](https://github.com/facebook/react-native/commit/7f3cc256b5bcbf2e64540ca69401f62ec6869f0e) by [@RSNara](https://github.com/RSNara)) +- Expose the extraData dict attached to JavaScript errors to the native ExceptionManager on iOS, similar to Android ([a65ae8eff6](https://github.com/facebook/react-native/commit/a65ae8eff6ec6f9ad283ac8e96f00802421a14da) by [@GijsWeterings](https://github.com/GijsWeterings)) +- `RCTLocalizationProvider` Fall back to input when no localization is available ([18196512db](https://github.com/facebook/react-native/commit/18196512db6b8b4469a5e1b098d8892ae72d743a) by [@robhogan](https://github.com/robhogan)) +- Update iOS LogBox to render its UIWindow with the key window's UIWindowScene ([d31d83f410](https://github.com/facebook/react-native/commit/d31d83f4109c167ec612058c805fd65f69b82476) by [@vincentriemer](https://github.com/vincentriemer)) +- Remove Gemfile.lock from template ([1907bd31f0](https://github.com/facebook/react-native/commit/1907bd31f066865aa1c5fe4ec88e98ee46448771) by [@danilobuerger](https://github.com/danilobuerger)) +- Fix `pod install` when `RCT-Folly` version has been updated. ([b2517c3bdc](https://github.com/facebook/react-native/commit/b2517c3bdccc3f9d935f4ee06f959d6ce8f27bbe) by [@fortmarek](https://github.com/fortmarek)) +- Fix usage of cocoapods with --project-directory flag and new arch ([2f813f873a](https://github.com/facebook/react-native/commit/2f813f873a1692044ea3461e59ca732a4d952300) by [@danilobuerger](https://github.com/danilobuerger)) +- Ensure LogBoxView is sized relative to the key window instead of the full screen ([84f8c9ad55](https://github.com/facebook/react-native/commit/84f8c9ad550f98295d2e718b4b1d6b1ac724b898) by [@vincentriemer](https://github.com/vincentriemer)) +- Improved template fastlane gitignore ([f43f05d292](https://github.com/facebook/react-native/commit/f43f05d292fd2fbdf3d5fdfd194ed81b0e346657) by [@danilobuerger](https://github.com/danilobuerger)) +- Set RCTView borderColor to UIColor ([267d36d0af](https://github.com/facebook/react-native/commit/267d36d0afb4b3713df9b679c2019c44ac6bcc3f) by [@danilobuerger](https://github.com/danilobuerger)) +- Fix action sheet callback invoked more than once on iPad ([8935d6e697](https://github.com/facebook/react-native/commit/8935d6e697dffb0971f5a8ee1dfbc580080de3e0) by [@janicduplessis](https://github.com/janicduplessis)) +- Resolve border platform color based on current trait collection ([9a35818797](https://github.com/facebook/react-native/commit/9a3581879764f3f1b2743905e3e54611e96bb618) by [@danilobuerger](https://github.com/danilobuerger)) +- Enable custom sound for local push notifications. ([eb19499484](https://github.com/facebook/react-native/commit/eb1949948406195c4c02c6041d07cba074ae820c)) +- Invoke registerForRemoteNotifications on main UI thread. ([3633a05299](https://github.com/facebook/react-native/commit/3633a05299d99b12acc5c3c056b977463df1924e)) +- Bump flipper pods to get arm64 catalyst slice ([f811da7cc2](https://github.com/facebook/react-native/commit/f811da7cc20cc49ca5c8d4e023d6c61e36e15dd1) by [@fortmarek](https://github.com/fortmarek)) +- Fix `pod install --project-directory=ios` failing when Hermes is enabled ([1b22e8a039](https://github.com/facebook/react-native/commit/1b22e8a039081887ffd450596d822bff975d6900), ([eb7cc85a91](https://github.com/facebook/react-native/commit/eb7cc85a9146d058694247178f03d57cc125c97a) by [@tido64](https://github.com/tido64)) +- Fix compilation warning in yoga ([52d8a797e7](https://github.com/facebook/react-native/commit/52d8a797e7a6be3fa472f323ceca4814a28ef596) by [@cuva](https://github.com/cuva)) +- Prevent deadlock when dispatching events from observers on the same thread. ([68fd1e5508](https://github.com/facebook/react-native/commit/68fd1e55085e871a854563721ee29ca698239607) by [@Pickleboyonline](https://github.com/Pickleboyonline)) +- In RCTSurfaceHostingComponent, access ckComponent from main queue to pass assertion ([1874c81003](https://github.com/facebook/react-native/commit/1874c81003b468554c227541fec5e29c4adfb82f) by [@p-sun](https://github.com/p-sun)) +- Fix modal redbox for onDismiss ([46f68aceb2](https://github.com/facebook/react-native/commit/46f68aceb20a10c95c92b5ffeb90f289b015a559) by [@HeyImChris](https://github.com/HeyImChris)) +- Attempt to fix crash during app termination ([9cd43340a7](https://github.com/facebook/react-native/commit/9cd43340a7e2443564c2ff5e8e85d37f6e1e47ef) by [@sammy-SC](https://github.com/sammy-SC)) + +### Security + +- Encode URL params in URLSearchParams.toString() ([1042a8012f](https://github.com/facebook/react-native/commit/1042a8012fb472bd5c882b469fe507dd6279d562) by [@sshic](https://github.com/sshic)) + +## v0.68.4 + +### Changed + +- Bump version of `promise` from 8.0.3 to 8.2.0, enabling `Promise.allSettled` ([951538c080](https://github.com/facebook/react-native/commit/951538c080ef745da304fb308fa91d597e0dd98a) by [@retyui](https://github.com/retyui)) +- Bump react-native-codegen to 0.0.18 ([40a3ae3613](https://github.com/facebook/react-native/commit/40a3ae3613394fe5f0d728bada538d2d5b78a8a4) by [@dmytrorykun](https://github.com/dmytrorykun)) + +#### Android specific + +- Correctly resolve classes with FindClass(..) ([361b310bcc](https://github.com/facebook/react-native/commit/361b310bcc8dddbff42cf63495649291c894d661) by [@evancharlton](https://github.com/evancharlton)) + +### Fixed + +- Codegen should ignore `.d.ts` files ([0f0d52067c](https://github.com/facebook/react-native/commit/0f0d52067cb89fdb39a99021f0745282ce087fc2) by [@tido64](https://github.com/tido64)) + +#### iOS specific + +- Fix the way the orientation events are published ([7d42106d4c](https://github.com/facebook/react-native/commit/7d42106d4ce20c644bda4d928fb0abc163580cee) by [lbaldy](https://github.com/lbaldy)) + +## v0.68.3 + +### Changed + +#### Android specific + +- Let's not build reactnativeutilsjni shared library ([af9225ec5f](https://github.com/facebook/react-native/commit/af9225ec5fd22da802e3da4d786fa7f6ec956b0f) by [@SparshaSaha](https://github.com/SparshaSaha)) +- Modified **getDefaultJSExecutorFactory** method ([87cfd386cb](https://github.com/facebook/react-native/commit/87cfd386cb2e02bfa440c94706d9d0274f83070c) by [@KunalFarmah98](https://github.com/KunalFarmah98)) + +### Fixed + +- Use monotonic clock for performance.now() ([114d31feee](https://github.com/facebook/react-native/commit/114d31feeeb47f5a57419e5088c3cbe9340f757a)) + +#### Android specific + +- Logging a soft error when ReactRootView has an id other than -1 instead of crashing the app in hybrid apps ([1ca2c24930](https://github.com/facebook/react-native/commit/1ca2c2493027c1b027146cd41e17dd8a4fc33a41) by [@Kunal-Airtel2022](https://github.com/Kunal-Airtel2022)) + +## v0.68.2 + +### Changed + +- Bump used version of react-native-codegen to 0.0.17 ([dfda480a98](https://github.com/facebook/react-native/commit/dfda480a9888d95c542cea40f25e8e783565c1db) by [@cortinico](https://github.com/cortinico)) +- Bump react-native-codegen to 0.0.17 ([a5ddc2e165](https://github.com/facebook/react-native/commit/a5ddc2e16523ea336ffbecf7acfd4820469a29e7) by [@cortinico](https://github.com/cortinico)) + +### Fixed + +#### Android specific + +- Working around Long paths limitation on Windows ([62ef6f5fa1](https://github.com/facebook/react-native/commit/62ef6f5fa1ecb918bde130a6024b65afcd34c7e3) by [@mganandraj](https://github.com/mganandraj)) + +## v0.68.1 + +### Changed + +#### Android specific + +- Bump React Native Gradle plugin to 0.0.6 ([9573d7b84d](https://github.com/facebook/react-native/commit/9573d7b84d35233fbb39a4067cfef65490aa34a7) by [@cortinico](https://github.com/cortinico)) +- Don't require yarn for codegen tasks ([d5da70e17e](https://github.com/facebook/react-native/commit/d5da70e17e8c8210cd79a4d7b09c6a5ded4b5607) by [@danilobuerger](https://github.com/danilobuerger)) + +### Fixed + +- Fix dynamic_cast (RTTI) by adding key function to ShadowNodeWrapper and related classes ([58a2eb7f37](https://github.com/facebook/react-native/commit/58a2eb7f37c2dc27ad3575618778ad5b23599b27) by [@kmagiera](https://github.com/kmagiera)) +- Pin use-subscription to < 1.6.0 ([5534634892](https://github.com/facebook/react-native/commit/5534634892f47a3890e58b661faa2260373acb25) by [@danilobuerger](https://github.com/danilobuerger)) + +#### Android specific + +- Use NDK 23 only for Windows users. ([e48a580080](https://github.com/facebook/react-native/commit/e48a580080bdae58b375f30fbcf8a83cc1915b2f) by [@cortinico](https://github.com/cortinico)) +- Improve support for Android users on M1 machine ([4befd2a29c](https://github.com/facebook/react-native/commit/4befd2a29cb94b026d9c048a041aa9f1817295b5) by [@cortinico](https://github.com/cortinico)) +- Template: Specify abiFilters if enableSeparateBuildPerCPUArchitecture is not set. ([5dff920177](https://github.com/facebook/react-native/commit/5dff920177220ae5f4e37c662c63c27ebf696c83) by [@cortinico](https://github.com/cortinico)) +- Fix for building new architecture sources on Windows ([5a8033df98](https://github.com/facebook/react-native/commit/5a8033df98296c941b0a57e49f2349e252339bf9) by [@mganandraj](https://github.com/mganandraj)) + +## v0.68.0 + +### Breaking Changes + +- CI moved to Node 16. ([f1488db109](https://github.com/facebook/react-native/commit/f1488db109d13e748b071c02b40e90cdca1cc79d) by [@kelset](https://github.com/kelset)). + This change enforces Node >= 14 for React Native builds. +- Bump Android Gradle Plugin to 7.0.1. ([272cfe5d13](https://github.com/facebook/react-native/commit/272cfe5d1371c38a281cf3883ff0254a8d3505a3) by [@dulmandakh](https://github.com/dulmandakh)) + This version of Android Gradle plugin enforces JDK 11 for Android builds. Do not upgrade to AGP 7.1 as it is not supported by this version of react-native. +- Removed `fallbackResource` from `RCTBundleURLProvider` API ([0912ee179c](https://github.com/facebook/react-native/commit/0912ee179c210fb6b2ed9afbb3f2fbc5fb8a2bb3)) by [@philIip](https://github.com/philIip) + +### New Architecture + +*If you are interested in enabling the new architecture, please refer to [the dedicated documentation](https://reactnative.dev/docs/next/new-architecture-intro).* + +- Do not include Facebook license on users codegen'd code ([450967938a](https://github.com/facebook/react-native/commit/450967938ab25c4dabb9d5ecd9f7b57afb1c78dd) by [@cortinico](https://github.com/cortinico)) + +#### Android specific + +- Setup a `newArchEnabled` property to Opt-in the New Architecture in the template ([8d652fba4c](https://github.com/facebook/react-native/commit/8d652fba4ce07256784a1b7e86713c810336856d) by [@cortinico](https://github.com/cortinico)) + +#### iOS specific + +- Add fabric option to the default app template. ([2e9a376c84](https://github.com/facebook/react-native/commit/2e9a376c8488d1fb11c0b5d604137712321fd90d) by [@sota000](https://github.com/sota000)) +- Add turbo module support in the default app template. ([8ec0e6919c](https://github.com/facebook/react-native/commit/8ec0e6919c5fab118c8b54538860ee36009bfaa7) by [@sota000](https://github.com/sota000)) +- Rename the new architecture flag to RCT_NEW_ARCH_ENABLED. ([c0c5439959e](https://github.com/facebook/react-native/commit/c0c5439959e21d7806178bb9139c2cd19b857506) by [@sota000](https://github.com/sota000)) + +### Added + +- Create @fb-tools-support/yarn package ([7db294d6d5](https://github.com/facebook/react-native/commit/7db294d6d5b00a38f305dd52be3e0961f35695c8) by [@motiz88](https://github.com/motiz88)) +- Support string color values in Animated.Color ([d3a0c4129d](https://github.com/facebook/react-native/commit/d3a0c4129d6a5a7beced4e9aa62b2da4e3f4fed4)) +- New Animated.Color node ([ea90a76efe](https://github.com/facebook/react-native/commit/ea90a76efef60df0f46d29228289f8fc1d26f350)) +- Added linter warning config for unstable nested components ([988fefc44d](https://github.com/facebook/react-native/commit/988fefc44d39957e8c5e1eecb02dfd1ce119f34c) by [@javache](https://github.com/javache)) +- Option to supply `platformConfig` to NativeAnimated ([4a227ce2ab](https://github.com/facebook/react-native/commit/4a227ce2ab3f8c181150461ab28b831979093db0) by [@rozele](https://github.com/rozele)) +- Animated.event can be used to extract values with numeric keys from native events ([b2105711a0](https://github.com/facebook/react-native/commit/b2105711a0b90859f8e3fc1aaec4998e252c2d14) by [@javache](https://github.com/javache)) +- Adds a setSelection imperative method to TextInput ([771ca921b5](https://github.com/facebook/react-native/commit/771ca921b59cc3b3fd12c8fe3b08ed150bcf7a04) by [@lyahdav](https://github.com/lyahdav)) +- Native-only prop to optimize text hit testing on some RN platforms ([f3bf2e4f51](https://github.com/facebook/react-native/commit/f3bf2e4f51897f1bb71e37002c288ebf3b23cf78) by [@rozele](https://github.com/rozele)) + +#### Android specific + +- Added DoNotStripAny proguard rules ([48318b1542](https://github.com/facebook/react-native/commit/48318b1542910b939ab977c0bc82e98f098abe50) by [@ShikaSD](https://github.com/ShikaSD)) +- Add new API in ScrollView and HorizontalScrollView to process pointerEvents prop. ([48f6967ae8](https://github.com/facebook/react-native/commit/48f6967ae88100110160e1faf03e6c0d37e404bd) by [@ryancat](https://github.com/ryancat)) +- Add `accessibilityLabelledBy` props ([36037fa81b](https://github.com/facebook/react-native/commit/36037fa81bbdcc460057e7e7cf608cd364ca48a6) by [@grgr-dkrk](https://github.com/grgr-dkrk)) +- Added missing constructor to WritableNativeArray ([c68c47d2ba](https://github.com/facebook/react-native/commit/c68c47d2bafa8e8e25b534d6cdd1a63bc77a1cf4) by [@piaskowyk](https://github.com/piaskowyk)) +- Add new API for custom fling animator to provide predicted travel distance for its fling animation. ([fe6277a30d](https://github.com/facebook/react-native/commit/fe6277a30d3ec19e4772991e30ae20c3a9cfe565) by [@ryancat](https://github.com/ryancat)) +- Adding new API `onChildEndedNativeGesture` to the RootView interface to let its implementations notify the JS side that a child gesture is ended. ([9b33c31ee0](https://github.com/facebook/react-native/commit/9b33c31ee024bae30e441107f838e1b5044525ba) by [@ryancat](https://github.com/ryancat)) +- Make the `reactNativeArchitectures` property more discoverable ([0f39a1076d](https://github.com/facebook/react-native/commit/0f39a1076dc154995a2db79352adc36452f46210) by [@cortinico](https://github.com/cortinico)) +- Added `isAccessibilityServiceEnabled` to get if accessibility services are enabled ([c8b83d4e0b](https://github.com/facebook/react-native/commit/c8b83d4e0b33c2af45093f7b2262ee578ece2faf) by [@grgr-dkrk](https://github.com/grgr-dkrk)) +- Add bundleForVariant option ([d2c10da5d5](https://github.com/facebook/react-native/commit/d2c10da5d5687833545691f281473381e4466c2e) by [@grit96](https://github.com/grit96)) +- Add ACCEPT_HANDOVER, ACTIVITY_RECOGNITION, ANSWER_PHONE_CALLS, READ_PHONE_NUMBERS & UWB_RANGING to PermissionsAndroid ([4b25a0aaa0](https://github.com/facebook/react-native/commit/4b25a0aaa077caf9c437bcfeef8a226eda5a102e) by [@iBotPeaches](https://github.com/iBotPeaches)) + +#### iOS specific + +- Add new argument to announceForAccessibility to allow queueing on iOS ([4d1357918a](https://github.com/facebook/react-native/commit/4d1357918a4dcb331ccea2140699f487ca45ea30) by [@peterc1731](https://github.com/peterc1731)) +- Add volta support to find-node.sh ([765844055b](https://github.com/facebook/react-native/commit/765844055ba0d02262a11114bad5da67e935d8df) by [@liamjones](https://github.com/liamjones)) +- Support fnm when detecting node binary ([c9e4d34885](https://github.com/facebook/react-native/commit/c9e4d3488578d65e55198ad597252a2ac8cc5f73) by [@MoOx](https://github.com/MoOx)) +- Find-node.sh now respects .nvmrc ([35bcf934b1](https://github.com/facebook/react-native/commit/35bcf934b186e581d100d43e563044300759557f) by [@igrayson](https://github.com/igrayson)) +- Add macros to be able to stub C functions in tests ([749a9207b6](https://github.com/facebook/react-native/commit/749a9207b6f0545c03ca83efbda7971ffd4d2d57) by [@philIip](https://github.com/philIip)) + + +### Changed + +- Bump RN CLI to v7.0.3, and Metro to 67 ([848ba6fb1d](https://github.com/facebook/react-native/commit/848ba6fb1db81bbb44efd373af9e81f31f227aef) by [@kelset](https://github.com/kelset)) and ([df2e934a69](https://github.com/facebook/react-native/commit/df2e934a697b5b207053db3bbcf71492932a6062) by [@kelset](https://github.com/kelset)) +- Upgraded react-devtools-core dependency to 4.23.0 ([1cc217d5ef](https://github.com/facebook/react-native/commit/1cc217d5effdbee4cf2f64063a443ecb331673d4) by [@bvaughn](https://github.com/bvaughn)) +- Bump Flipper to 0.125.0 ([50057158ca](https://github.com/facebook/react-native/commit/50057158ca32842d70160541e3cb5d4bd512f8f5) by [@cortinico](https://github.com/cortinico)) +- Export Flow type for deceleration rate for use in other files to keep deceleration rate prop values consistently typed ([9b0ed920ef](https://github.com/facebook/react-native/commit/9b0ed920ef087c4c18504adacf9d4f557812cf1b)) +- Upgrade deprecated-react-native-prop-types dependency ([badd30885f](https://github.com/facebook/react-native/commit/badd30885fb999124b6b54b3fb016edbd988c16b) by [@chiaramooney](https://github.com/chiaramooney)) +- Improved error message in react.gradle ([7366a866b3](https://github.com/facebook/react-native/commit/7366a866b381db6fc5615153e7788aa4828cfd96) by [@vonovak](https://github.com/vonovak)) +- Upgraded packages to the latest versions for ESLint v7. ([cf763cdf81](https://github.com/facebook/react-native/commit/cf763cdf816e1cad20caf2347c54bc96c7f6dd47) by [@yungsters](https://github.com/yungsters)) +- Updated the links for the discussions and changelog ([daf37a1fce](https://github.com/facebook/react-native/commit/daf37a1fce43403e6320e1e3023e86fd1b970bdf) by [@MikeyAlmighty](https://github.com/MikeyAlmighty)) +- XMLHttpRequest.getAllResponseHeaders() now returns headers with names lowercased and sorted in ascending order, as per specification ([b2415c4866](https://github.com/facebook/react-native/commit/b2415c48669391ee1ab7c6450748c4d91097a666) by [@ascherkus](https://github.com/ascherkus)) +- Bump react-native-codegen to 0.0.9 ([e3a71b019f](https://github.com/facebook/react-native/commit/e3a71b019fa78e2b4b3454ccc59ea9c8cc543b29) by [@cortinico](https://github.com/cortinico)) +- Accessing `Image.propTypes`, `Text.propTypes`, `TextInput.propTypes`, `ColorPropType`, `EdgeInsetsPropType`, `PointPropType`, or `ViewPropTypes` now emits a deprecation warning. ([3f629049ba](https://github.com/facebook/react-native/commit/3f629049ba9773793978cf9093c7a71af15e3e8d) by [@yungsters](https://github.com/yungsters)) +- Bump `core-workflow-apply-version-label` version ([e973b3afc2](https://github.com/facebook/react-native/commit/e973b3afc274f892a0e5a6fdea9004dc5d84eb2b) by [@lucasbento](https://github.com/lucasbento)) +- Add `vendor/bundle` into .gitignore template ([2f67f5d68b](https://github.com/facebook/react-native/commit/2f67f5d68b17010c49f2996a788fe68c1fe2e9f6) by [@MoOx](https://github.com/MoOx)) + +#### Android specific + +- Add allowsEdgeAntialiasing on views with rotations or skew transforms ([e6a3410afe](https://github.com/facebook/react-native/commit/e6a3410afe7d9a4cecf3db0a95503d2ff05bb862)) +- Bump Kotlin version to 1.6.10 ([d0f0234656](https://github.com/facebook/react-native/commit/d0f0234656dc981b422d1e9aa0885afd5fd29879) by [@AKB48](https://github.com/AKB48)) +- Bump Soloader to 0.10.3 ([f45889ef95](https://github.com/facebook/react-native/commit/f45889ef95ec694520e91b0032e591a087e088e5) by [@osartun](https://github.com/osartun)) +- Bump Gradle to 7.3 ([c180627ac7](https://github.com/facebook/react-native/commit/c180627ac7e5e155707b3c9433c4582839e1820e) by [@dulmandakh](https://github.com/dulmandakh)) +- Bump Android compile and target SDK to 31 ([00ac034353](https://github.com/facebook/react-native/commit/00ac034353cbc867991bf79cb1dd103353f47126) by [@ShikaSD](https://github.com/ShikaSD)) +- Use side-by-side NDK for Android ([bd7caa64f5](https://github.com/facebook/react-native/commit/bd7caa64f5d6ee5ea9484e92c3629c9ce711f73c) by [@cortinico](https://github.com/cortinico)) +- Leverage Gradle implicit dependency substitution for Gradle Plugin ([0fccbd53af](https://github.com/facebook/react-native/commit/0fccbd53af86083a8742a33282dc183d07eb27a2) by [@cortinico](https://github.com/cortinico)) +- Remove unused import of JMessageQueueThread.h ([705236e363](https://github.com/facebook/react-native/commit/705236e3637e4f80e5fa4bd7234df9f1e14a5d3d) by [@sshic](https://github.com/sshic)) +- Made `MessageQueueThread#runOnQueue` return a boolean. Made `MessageQueueThreadImpl#runOnQueue` return false when the runnable is not submitted. ([89faf0c9a8](https://github.com/facebook/react-native/commit/89faf0c9a87f6de68ca416d10566dbcbe80d9450)) +- Assume *.ktx assets are packaged as Android drawables ([cb610ddca7](https://github.com/facebook/react-native/commit/cb610ddca79fe29b88568545ab011671fc392c9a) by [@motiz88](https://github.com/motiz88)) +- Add ViewConfigs to support onEnter/onExit/onMove events ([44143b50fd](https://github.com/facebook/react-native/commit/44143b50fdcafe22caa43d76ec3210132ce3af21) by [@mdvacca](https://github.com/mdvacca)) +- Let react_native_assert really abort the app ([2ae06df58f](https://github.com/facebook/react-native/commit/2ae06df58f5f5eaf4386c14d28af25b643401bf3) by [@cortinico](https://github.com/cortinico)) +- Bugfix for multiple shadow threads rendered at the same time, small probability crash. ([9d71b166a6](https://github.com/facebook/react-native/commit/9d71b166a6c9d9afec7186c6a33aedc6975aa43c) by [@chenmo187](https://github.com/chenmo187)) +- RootView's onChildStartedNativeGesture now takes the child view as its first argument ([03e513de41](https://github.com/facebook/react-native/commit/03e513de41bf60f071eacbbb9604c83605abf625) by [@javache](https://github.com/javache)) +- Add ReactInstanceEventListenerV2 for migration ([ce74aa4ed3](https://github.com/facebook/react-native/commit/ce74aa4ed335d4c36ce722d47937b582045e05c4) by [@sshic](https://github.com/sshic)) +- Improved logic of findTargetPathAndCoordinatesForTouch ([dfe42d6b75](https://github.com/facebook/react-native/commit/dfe42d6b75005f519c0e2c87c75e7886dce3345c) by [@javache](https://github.com/javache)) +- Set a resolution strategy for com.facebook.react:react-native when on New Architecture ([e695bc0bb5](https://github.com/facebook/react-native/commit/e695bc0bb50fc1c712e9862ed8fe4e7cc6619fae) by [@cortinico](https://github.com/cortinico)) +- Make hermes-executor-common a static lib ([b2cf24f41c](https://github.com/facebook/react-native/commit/b2cf24f41cb5f15653b34d396ef2a1c90defdf43) by [@janicduplessis](https://github.com/janicduplessis)) +- Static link for hermes-inspector ([20b0eba581](https://github.com/facebook/react-native/commit/20b0eba581a00e5e7e300f6377379b836617c147) by [@janicduplessis](https://github.com/janicduplessis)) + +#### iOS specific + +- Don't capitalize the first letter of a word that is starting by a number ([8b5a5d4645](https://github.com/facebook/react-native/commit/8b5a5d4645136ef3d6ee043348e583cbbac87ee3) by [@MaeIg](https://github.com/MaeIg)) +- updated `jsBundleURLForBundleRoot:fallbackResource` to `jsBundleURLForBundleRoot:` ([aef843bfe6](https://github.com/facebook/react-native/commit/aef843bfe60bda6bcc98d3fb4a6c295c9f4b66e3) by [@philIip](https://github.com/philIip)) +- Remove iOS 11 availability check ([9b059b6709](https://github.com/facebook/react-native/commit/9b059b67092f4e7d568867a2b3a51dfd7c6f1db6) by [@ken0nek](https://github.com/ken0nek)) +- Refactor: Assign string label to each case in RCTPLTag enum for startup performance logging ([60e60a9b3d](https://github.com/facebook/react-native/commit/60e60a9b3d42d342eaf5ddee4841b121f6474a6c) by [@p-sun](https://github.com/p-sun)) +- IOS Ruby Updates ([1e6add1a43](https://github.com/facebook/react-native/commit/1e6add1a43355bb88c57400a7420a656966bef97) by [@barbieri](https://github.com/barbieri)) +- Update Flipper pods to support re-enable macCatalyst ([2a5265dff7](https://github.com/facebook/react-native/commit/2a5265dff7e654f57b43335804840692313f2a56) by [@mikehardy](https://github.com/mikehardy)) +- Apple Silicon builds of glog & Flipper-Glog ([274c617f5b](https://github.com/facebook/react-native/commit/274c617f5bda263ff29115b3dcc013e47085a78d) by [@rayzr522](https://github.com/rayzr522)) + +### Fixed + +- Fix error "mockModal is not a function" ([507b05f4c0](https://github.com/facebook/react-native/commit/507b05f4c02b46109f483a2b79c924a775fd7bd3) by [@AntoineDoubovetzky](https://github.com/AntoineDoubovetzky)) +- Fixes execution of animation when a toValue of AnimatedValue is used. ([8858c21124](https://github.com/facebook/react-native/commit/8858c2112421be5212c024f9e404e66437a41389)) +- Fix RN version syntax to match new nightly build structure. ([3d1d4ee457](https://github.com/facebook/react-native/commit/3d1d4ee4572600425b8eb5d0d6512bb0d2a6ea44) by [@chiaramooney](https://github.com/chiaramooney)) +- Fix typo in _updateBottomIfNecessary function on KeyboardAvoidingView component ([0cc80b4d0c](https://github.com/facebook/react-native/commit/0cc80b4d0cb78a835977dbe5100262a16882bbea) by [@gabrieldonadel](https://github.com/gabrieldonadel)) +- Fix: Removes interface only check from third party components GenerateThirdPartyFabricComponentsProvider ([3e6902244a](https://github.com/facebook/react-native/commit/3e6902244a0d189261dbbe327296db1349e37410) by [@Ubax](https://github.com/Ubax)) +- Set CxxModules' Instance before retrieving their Method vector. ([1d45b20b6c](https://github.com/facebook/react-native/commit/1d45b20b6c6ba66df0485cdb9be36463d96cf182) by [@JunielKatarn](https://github.com/JunielKatarn)) +- AnimatedValue.__detach should store getValue result with offset deducted ([fe53cae954](https://github.com/facebook/react-native/commit/fe53cae954b37528eeaa1258ac0060c4298473bb) by [@rozele](https://github.com/rozele)) +- AnimatedValue.stopAnimation callback with correct value for NativeAnimated ([8ba771c3dd](https://github.com/facebook/react-native/commit/8ba771c3ddc00b1499e95a2812b4cd5ac904c8df) by [@rozele](https://github.com/rozele)) +- ESLint no-undef rule clashing with TypeScript compiler for TS files ([ae67c5ac45](https://github.com/facebook/react-native/commit/ae67c5ac45a8044fc1db66aee8eae6e881d660e4) by [@fiznool](https://github.com/fiznool)) +- ESLint `no-shadow` rule returning false positive for TypeScript enums ([722a0ff6f8](https://github.com/facebook/react-native/commit/722a0ff6f88bed4d54579a2b8bc574e87948187f) by [@fiznool](https://github.com/fiznool)) +- Fix support for custom port ([b399c2e3d1](https://github.com/facebook/react-native/commit/b399c2e3d10fa521dbec87243d3e96f6bca7df1e) by [@enniel](https://github.com/enniel)) +- `onLayout` prop is handled correctly in `` ([9c5e177a79](https://github.com/facebook/react-native/commit/9c5e177a79c64c77f281ce727538973e8222e975)) +- Modal accepts a testID but didn't forward it to RCTModalHostView, therefore not making it show up for e2e tests depending on viewhierarchy. ([5050e7eaa1](https://github.com/facebook/react-native/commit/5050e7eaa17cb417baf7c20eb5c4406cce6790a5) by [@GijsWeterings](https://github.com/GijsWeterings)) +- Remove unused and incorrect type declarations in WebSocketInterceptor ([91728e2266](https://github.com/facebook/react-native/commit/91728e2266375b954302ba0cd4b5daf641aefc23) by [@mischnic](https://github.com/mischnic)) +- Complete missing Flow declarations in URL ([98abf1b02f](https://github.com/facebook/react-native/commit/98abf1b02f64ad40d523335e677a2ede15b3650d) by [@mischnic](https://github.com/mischnic)) +- Pressable not passing hover props and event handlers to PressabilityConfig ([1b30dd074b](https://github.com/facebook/react-native/commit/1b30dd074b579c2ae138a1111d07ddb56761315d) by [@Saadnajmi](https://github.com/Saadnajmi)) +- Composite animations will now be ran immediately when the app is in testing mode ([b03e824c52](https://github.com/facebook/react-native/commit/b03e824c52123219a5c8fbd89473391bf0bc31c8) by [@javache](https://github.com/javache)) +- Remove duplicate class members ([c0e489b729](https://github.com/facebook/react-native/commit/c0e489b7293f15858cb706f1b8587600e429af28) by [@bradzacher](https://github.com/bradzacher)) +- Fix: Use same implementation for `performance.now()` on iOS and Android ([1721efb54f](https://github.com/facebook/react-native/commit/1721efb54ff9cc4f577b5ae27f13fcf56801a92c) by [@mrousavy](https://github.com/mrousavy)) + +#### Android specific + +- Enable cliPath to have an absolute path value ([5d560ca99f](https://github.com/facebook/react-native/commit/5d560ca99ff7220de11d2d76dbe77d73990894a8) by [@Krisztiaan](https://github.com/Krisztiaan)) +- Make sure configureNdkBuild* tasks are depending on preBuild ([2fdbf6a10f](https://github.com/facebook/react-native/commit/2fdbf6a10fe67fa3209a51a1105a97c16991f561) by [@cortinico](https://github.com/cortinico)) +- Added a null check to native.value in Switch to fix https://github.com/facebook/react-native/issues/32594 ([8d50bf1133](https://github.com/facebook/react-native/commit/8d50bf113352a6ccdf74c979e1022c6c2ccf6e56) by [@jonathanmos](https://github.com/jonathanmos)) +- Fix overflowInset calculation by using transform values ([8aa87814f6](https://github.com/facebook/react-native/commit/8aa87814f62e42741ebb01994796625473c1310f) by [@ryancat](https://github.com/ryancat)) +- Add missing sources jar into published android artifacts ([384e1a0c7b](https://github.com/facebook/react-native/commit/384e1a0c7bc50d2aab5b59bcedcea5a3e98f1659) by [@Kudo](https://github.com/Kudo)) +- Fix math for detecting if children views are in parent's overflowInset area. ([45244ebce2](https://github.com/facebook/react-native/commit/45244ebce228dfbc3412670e64c11491ba8d8c47) by [@ryancat](https://github.com/ryancat)) +- Fixed empty screen after retrying a BundleDownloader failure in dev mode ([c8d823b9bd](https://github.com/facebook/react-native/commit/c8d823b9bd9619dfa1f5851af003cc24ba2e8830) by [@samkline](https://github.com/samkline)) +- Fix crash from ScrollView that occurs while reporting an error from JS ([2151d11527](https://github.com/facebook/react-native/commit/2151d1152719a230565165f1a8dcfab172689eb3) by [@JoshuaGross](https://github.com/JoshuaGross)) +- Enable hitSlop to be set using a single number. ([589b129581](https://github.com/facebook/react-native/commit/589b129581903a737a64e14eab3f2e29620831d5) by [@javache](https://github.com/javache)) +- Fix fling and snap with recycler viewgroup where fling to the end of scrollable distance when it goes over current rendered children views. ([ead7b97944](https://github.com/facebook/react-native/commit/ead7b97944522e3066ceb2bd50c63c268c961277) by [@ryancat](https://github.com/ryancat)) +- Fixed edge case for quick small scrolls causing unexpected scrolling behaviors. ([f70018b375](https://github.com/facebook/react-native/commit/f70018b37532622f08f20b2c51cdbfca55d730ea) by [@ryancat](https://github.com/ryancat)) +- Fix crash on ReactEditText with AppCompat 1.4.0 ([e21f8ec349](https://github.com/facebook/react-native/commit/e21f8ec34984551f87a306672160cc88e67e4793) by [@cortinico](https://github.com/cortinico)) +- Do not .lowerCase the library name when codegenerating TurboModule Specs ([28aeb7b865](https://github.com/facebook/react-native/commit/28aeb7b8659b38ee3a27fae213c4d0800f4d7e31) by [@cortinico](https://github.com/cortinico)) +- Enable hitSlop to be set using a single number. ([a96bdb7154](https://github.com/facebook/react-native/commit/a96bdb7154b0d8c7f43977d8a583e8d2cbdcb795) by [@javache](https://github.com/javache)) +- Updated TextInput prop types to accomodate for new autoComplete values ([9eb0881c8f](https://github.com/facebook/react-native/commit/9eb0881c8fecd0e974b1cb9f479bad3075854340) by [@TheWirv](https://github.com/TheWirv)) +- Don't reconstruct app components https://github.com/facebook/react-native/issues/25040 ([fc962c9b6c](https://github.com/facebook/react-native/commit/fc962c9b6c4bf9f88decbe014ab9a9d5c1cf51bc) by [@Somena1](https://github.com/Somena1)) +- Do NOT skip the first child view in the scroll view group when measuring the lower and upper bounds for snapping. ([61e1b6f86c](https://github.com/facebook/react-native/commit/61e1b6f86cf98d8a74eeb9353143fe0c624fe6e6) by [@ryancat](https://github.com/ryancat)) +- Fix crash when a Switch is initialised with both backgroundColor and thumbColor. ([456cf3db14](https://github.com/facebook/react-native/commit/456cf3db14c443c483d63aa97c88b45ffd25799b) by [@smarki](https://github.com/smarki)) +- Fix devDisabledIn not working with multiple productFlavors ([055ea9c7b7](https://github.com/facebook/react-native/commit/055ea9c7b7dea030ef16da72d1f6ecb5d95ac468) by [@grit96](https://github.com/grit96)) +- Revert `ReactScrollView` to use `Context` instead of `ReactContext` in the constructor to be less restrictive. ([7b77cc637e](https://github.com/facebook/react-native/commit/7b77cc637e1faf4a2b134853f8415f277d0decdc) by [@ryancat](https://github.com/ryancat)) +- Fix onPress event for nested Text in RN Android ([e494e4beb6](https://github.com/facebook/react-native/commit/e494e4beb6a124008fd116178cbc38335bd87809) by [@mdvacca](https://github.com/mdvacca)) +- Fix enableVmCleanup not working for apps with product flavors ([a2b5e4cd82](https://github.com/facebook/react-native/commit/a2b5e4cd825a358419cef1e3823b72215b689686) by [@cortinico](https://github.com/cortinico)) +- Prevent NPE on ThemedReactContext ([f1b5fe1d3e](https://github.com/facebook/react-native/commit/f1b5fe1d3ea49294d8c89accfa27d76a1a97ccea) by [@sshic](https://github.com/sshic)) +- fix: jvm 11 error message from ReactPlugin.kt and react.gradle ([4e947ecb2d](https://github.com/facebook/react-native/commit/4e947ecb2dabfa0226af7f859c828847b4d891c0) by [@nomi9995](https://github.com/nomi9995)) + +#### iOS specific + +- ScrollView: Respect `contentInset` when animating new items with `autoscrollToTopThreshold`, make `automaticallyAdjustKeyboardInsets` work with `autoscrollToTopThreshold` (includes vertical, vertical-inverted, horizontal and horizontal-inverted ScrollViews) ([49a1460a37](https://github.com/facebook/react-native/commit/49a1460a379e3a71358fb38888477ce6ea17e81a) by [@mrousavy](https://github.com/mrousavy)) +- Prevent RCTConvert error for allowed null blob types ([e1b698c5f2](https://github.com/facebook/react-native/commit/e1b698c5f2b1d689fb3940f8c6a3e298d381ea3a) by [@habovh](https://github.com/habovh)) +- Migrate ScreenshotManager from NativeModule to TurboModule ([b13e41d98e](https://github.com/facebook/react-native/commit/b13e41d98e818279d1941f3425707d3c0ce407fc) by [@p-sun](https://github.com/p-sun)) +- Fix usage of cocoapods with --project-directory flag and new arch ([9e7d91f2fc](https://github.com/facebook/react-native/commit/9e7d91f2fc4d576b8fba81304a24e50134da93d6) by [@danilobuerger](https://github.com/danilobuerger)) +- Post RCTContentDidAppearNotification with new arch ([75105e692c](https://github.com/facebook/react-native/commit/75105e692c2be9bd192089a6a6ffde7572ee1ce1) by [@danilobuerger](https://github.com/danilobuerger)) +- Remove absolute paths from pods project ([42b01a32a1](https://github.com/facebook/react-native/commit/42b01a32a137f18ae9fd2f00914f2edb0e107421) by [@danilobuerger](https://github.com/danilobuerger)) +- Respect RCTSetDefaultFontHandler chosen font ([89efa1a0c1](https://github.com/facebook/react-native/commit/89efa1a0c1b633bf9edee66583800ad3fc54ce63) by [@danilobuerger](https://github.com/danilobuerger)) +- Fixed duplicated UUIDs problem during pod install phase. ([f595a4e681](https://github.com/facebook/react-native/commit/f595a4e681e75aaf737b6582f69855d76a1f33dd)) +- Fix `Time.h` patch not being applied when running `pod install --project-directory=ios` ([60cef850bd](https://github.com/facebook/react-native/commit/60cef850bd3fd12c32ee1196bd19a559592d1465) by [@tido64](https://github.com/tido64)) +- Fix WebSocket control frames having payloads longer than 125 bytes ([86db62b7a8](https://github.com/facebook/react-native/commit/86db62b7a8b28ac82dd0a0627a8b6c351875f682) by [@asmeikal](https://github.com/asmeikal)) +- Stop RedBox from appearing for LogBox handled errors ([9d2df5b8ae](https://github.com/facebook/react-native/commit/9d2df5b8ae95b3cfeae26f64bd1d50bd2b0bbae9) by [@liamjones](https://github.com/liamjones)) +- Enable hitSlop to be set using a single number. ([3addafa525](https://github.com/facebook/react-native/commit/3addafa5257ade685216900bebbad8c35e24e124) by [@javache](https://github.com/javache)) +- Fix `__apply_Xcode_12_5_M1_post_install_workaround` failing when one of the Pods has no IPHONEOS_DEPLOYMENT_TARGET set ([9cd4092336](https://github.com/facebook/react-native/commit/9cd40923362ff717a722f8f36c8250a29a5142b7) by [@Yonom](https://github.com/Yonom)) +- This is a quick speculative fix since we know `CFRunLoopPerformBlock` does not push/pop an autorelease pool. ([3fff164dfa](https://github.com/facebook/react-native/commit/3fff164dfa1c97f69b1701e974effc92a94152d6) by [@christophpurrer](https://github.com/christophpurrer)) +- Fixed RCTImageLoaderTests ([1542f83527](https://github.com/facebook/react-native/commit/1542f835273c08776b960929b5aa7cefbd225971) by [@philIip](https://github.com/philIip)) +- Fix Rosetta2 CocoaPods warning on Apple Silicon ([e918362be3](https://github.com/facebook/react-native/commit/e918362be3cb03ae9dee3b8d50a240c599f6723f) by [@oblador](https://github.com/oblador)) +- Fix `pod install --project-directory=ios` failing due to wrong path to `React-Codegen` ([ebb26cf2e4](https://github.com/facebook/react-native/commit/ebb26cf2e420616c8bf01a5148ca4f8419b238d3) by [@tido64](https://github.com/tido64)) + +### Deprecated + +#### Android specific + +- Gradle: Deprecate `reactRoot` in favor of `root` and `reactNativeDir` ([8bc324fd34](https://github.com/facebook/react-native/commit/8bc324fd34337ab159e2e21e213a6c5b06c548da) by [@cortinico](https://github.com/cortinico)) + + +### Removed + +- DeprecatedPropTypes (deep-link) modules removed from React Native. ([23717c6381](https://github.com/facebook/react-native/commit/23717c6381a41b1c5f189376bfa5bc73c7a4da87) by [@yungsters](https://github.com/yungsters)) +- `accessibilityStates` no longer passed through to RCTView. ([1121ed94ab](https://github.com/facebook/react-native/commit/1121ed94ab470be27207b0c8dbae5d19860c08da) by [@luism3861](https://github.com/luism3861)) + +#### iOS specific + +- Remove RCTUIManagerObserver from RCTNativeAnimatedTurboModule ([e9ed115bab](https://github.com/facebook/react-native/commit/e9ed115babbc82968380dae22fa928d4ce3cd6da) by [@p-sun](https://github.com/p-sun)) + + +## v0.67.4 + +### Fixed + +#### Android specific + +- Added a null check to native.value in Switch to fix https://github.com/facebook/react-native/issues/32594 ([8d50bf1133](https://github.com/facebook/react-native/commit/8d50bf113352a6ccdf74c979e1022c6c2ccf6e56) by [@jonathanmos](https://github.com/jonathanmos)) + +## v0.67.3 + +### Fixed + +#### Android specific + +- Text with adjustsFontSizeToFit changes the text layout infinitely ([c1db41f060](https://github.com/facebook/react-native/commit/c1db41f060908e6ab001aaace7c20c610056f59a)) + +#### iOS specific + +- Fix a broken input for the Korean alphabet in TextInput ([1a83dc36ce](https://github.com/facebook/react-native/commit/1a83dc36ce0af33ac7a3c311354fce4bfa5ba1a3) by [@bernard-kms](https://github.com/bernard-kms)) + ## v0.67.2 ### Fixed diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index cec92883ec6aa8..3fcb082d0504f6 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,185 +1,7 @@ # Contributing to microsoft/react-native-macos -This document describes how to set up your development environment and contribute changes to the **microsoft/react-native-macos** project. This is a working fork of **facebook/react-native** where changes for supporting macOS are being staged. -> **Note: This repository will be accepting PRs only specific to macOS support. To contribute to React Native, please see [Contributing to react-native](https://github.com/facebook/react-native/blob/master/CONTRIBUTING.md)** +Thank you for your interest in contributing to React Native! From commenting on and triaging issues, to reviewing and sending Pull Requests, all contributions are welcome. +We aim to build a vibrant and inclusive [ecosystem of partners, core contributors, and community](ECOSYSTEM.md) that goes beyond the main React Native GitHub repository. -This document assumes basic working knowledge with Git and related tools. We are providing instructions specific to this project. You can either do this with the command prompt or with a combination of the command prompt and [**SourceTree**](https://www.sourcetreeapp.com/). - -## Setting up your branch for changes - -### Creating your own fork - -If you wish to contribute changes back to the **microsoft/react-native-macos** repository, start by creating your own fork of the repository. This is essential. This will keep the number of branches on the main repository to a small count. There are lots of developers in this project and creating lots of branches on the main repository does not scale. In your own fork, you can create as many branches as you like. - -- Navigate to **[GitHub](https://www.github.com)** with a browser and log in to your GitHub account. For the sake of this document, let's assume your username is **johndoe**. -- Navigate to the **[microsoft/react-native-macos](https://github.com/microsoft/react-native-macos)** repository in the same browser session. -- Click on the **Fork** button at the top right corner of the page. -- Create the fork under your account. Your GitHub profile should now show **react-native-macos** as one of your repositories. -- Create a folder on your device and clone your fork of the **Microsoft** repository. e.g. `https://github.com/johndoe/react-native-macos.git`. Notice how your GitHub username is in the repository location. - -```bash -git clone https://github.com/johndoe/react-native-macos.git -``` - -### [Code of Conduct](https://github.com/facebook/react-native/blob/HEAD/CODE_OF_CONDUCT.md) - -As a reminder, all contributors are expected to adhere to the [Code of Conduct](https://github.com/facebook/react-native/blob/HEAD/CODE_OF_CONDUCT.md). - -### Setting up the upstream repository - -Before starting to contribute changes, please setup your upstream repository to the primary **microsoft/react-native-macos** repository. - - -1. **Replying and handling open issues.** We get a lot of issues every day, and some of them may lack necessary information. You can help out by guiding people through the process of filling out the issue template, asking for clarifying information, or pointing them to existing issues that match their description of the problem. We cover more about this process in the [Issue Triage wiki](https://github.com/facebook/react-native/wiki/Triaging-GitHub-Issues). -2. **Reviewing pull requests for the docs.** Reviewing [documentation updates](https://github.com/facebook/react-native-website/pulls) can be as simple as checking for spelling and grammar. If you encounter situations that can be explained better in the docs, click **Edit** at the top of most docs pages to get started with your own contribution. -3. **Help people write test plans.** Some pull requests sent to the main repository may lack a proper test plan. These help reviewers understand how the change was tested, and can speed up the time it takes for a contribution to be accepted. - -- When you run `git remote -v`, you should see only your fork in the output list - -```bash -git remote -v - - origin https://github.com/johndoe/react-native-macos.git (fetch) - origin https://github.com/johndoe/react-native-macos.git (push) -``` - -- Map the primary **react-native-macos** repository as the upstream remote - -```bash -git remote add upstream https://github.com/microsoft/react-native-macos.git -``` - -- Now running `git remote -v` should show the upstream repository also - -* [Issues](https://github.com/facebook/react-native/wiki/Triaging-GitHub-Issues) -* [Pull Requests](https://github.com/facebook/react-native/wiki/Managing-Pull-Requests) - -```bash -git remote -v - - origin https://github.com/johndoe/react-native-macos.git (fetch) - origin https://github.com/johndoe/react-native-macos.git (push) - upstream https://github.com/microsoft/react-native-macos.git (fetch) - upstream https://github.com/microsoft/react-native-macos.git (push) -``` - -- At this point you are ready to start branching and contributing back changes. - -### Setting up the branch - -For each bug or task you complete, it is recommended that you start with a fresh branch. If you have any lingering changes in your current branch that you want to save, go ahead and commit them. If you are just beginning, then you are good to go. On github, navigate to your repository which should be forked from **microsoft/react-native-macos** as described in the above sections. Above the list of files is a dropdown that should say master. Use the dropdown to create a new branch and name is according to what you will be working on. (I.e. DropdownHighlight, CleanUpExamples, etc). Now you have created a new branch. - -* **React Native website** which contains the source code for the website, including the documentation, located at -* **Releases** Conversations for new releases are happening [in this discussion repo](https://github.com/reactwg/react-native-releases/discussions). -* **Changelog** The changelog can be found [here](https://github.com/facebook/react-native/blob/main/CHANGELOG.md). -* **Discussions** about the future of React Native take place in the repository. -* **High-quality plugins** for React Native can be found throughout the [React Native Community GitHub Organization](http://github.com/react-native-community/). - -**SourceTree:** -If you are using SourceTree you will want your branch to show up in SourceTree so you can commit changes to your branch. It takes time for it to show up automatically, so you can make it show by running `git pull --all` in your command prompt from the root. Once you see your new branch in SourceTree under Remotes on the left navigation pane, double click on your branch to check it out locally. A dialog will come up and the default settings should be fine, click Ok. - -**Git Command Line** -If you are using the command line, you will want to make sure you have your branch locally. It takes time for it to show up automatically, so you can make it show by running `git pull --all` in your command prompt from the root. Run `git branch -a` to see if your new branch shows up. Now you will want to check out your branch locally. You can do this with `git checkout -b branch-name`. Confirm you are now working out of the branch with `git branch`. - -We use GitHub issues to track bugs exclusively. We have documented our issue handling processes in the [Issues wiki](https://github.com/facebook/react-native/wiki/Triaging-GitHub-Issues). - -### Merging upstream master into your fork master - -From time to time, your fork will get out of sync with the upstream remote. Use the following commands to get the master branch of your fork up up to date. - -```bash -git fetch upstream -git checkout master -git pull upstream master -git push -``` - -### Merging upstream master into your current branch - -Use these commands instead if you would like to update your *current* branch in your fork from the upstream remote. - -```bash -git fetch upstream -git pull upstream master -git push -``` -## Contributing - -### Building the Repository -This repo uses `yarn` to manage its dependencies so to pull in all the dependencies we need, you must run `yarn` from root (note this maps to `yarn install`). - -`pod install` generates an `xcworkspace` from the existing `xcodeproj` and newly installed depedencies. Use the machine specific steps below to install your pods. Then to begin your work, launch the `RNTester.xcworkspace` project, choose your target of macOS or iOS and hit `Run`. - -#### x86_64 -After doing so, you now have all the repo-level dependencies, but you still need to pull in the specific macOS/iOS xcode project dependencies. We use Cocoapods for this and to install them you must cd into the directory (e.g. `cd projects/rn-tester`)and run `pod install`. - -#### arm64 -To install cocoapods on an `M1` machine, `pod install` won't work as of writing this (July 23, 2021). Run the commands below to set up your pods xcworkspace. -``` -cd packages/rn-tester -sudo arch -x86_64 gem install ffi -sudo xcode-select -s /Applications/Xcode.app -arch -x86_64 pod install -``` - -The React Native blog is generated [from the Markdown sources for the blog](https://github.com/facebook/react-native-website/tree/HEAD/website/blog). - -### Make the fix -Now that your branch is set up and ready for commits, go ahead and fix the bug you are working on or make some small change that you want to check in. - -### Verify your changes -Manually test your fix by running RNTester. Run Unit Tests and Integration Tests in the RNTesterPods Xcode project. The following automated tests will be run as part of CI, you can also verify manually before submitting a PR. - -```bash -yarn test # run jest tests on JavaScript -yarn lint # run eslint on JavaScript -yarn flow-check-macos # run Flow checks on JavaScript -``` - -We recommend referring to the [CONTRIBUTING](https://github.com/facebook/react-native-website/blob/HEAD/CONTRIBUTING.md) document for the `react-native-website` repository to learn more about contributing to the website in general. - -### Commit your changes - -**SourceTree:** -In SourceTree, click on commit in the top left. This won't actually do anything to your files, it will just change to show the commit UI. In the bottom container, stage all of the files you want to submit by selecting them and clicking "Stage". Add a short message in the textbox at the bottom on what is included in your change. This will not show as your entire submission text, just for this commit. - -**Git Command Line** -To stage files using the command line, you need to run `git add MyFileOne.tsx` for each file. You can also look up how to add all files with changes under a directory. Next you will want to commit changes with `git commit –m "This change updates the padding in the dropdown"` - -You can commit multiple times until you are ready to make a pull request. You should keep the message short since it will not be used in the bug notes and is just for keeping track of the multiple commits in one pull request. - -### Provide changelog information -Run `yarn change` in the root of the repo. - -1. Fork the React Native repository and create your branch from `main`. -2. Make the desired changes to React Native sources. Use the `packages/rn-tester` app to test them out. -3. If you've added code that should be tested, add tests. -4. If you've changed APIs, update the documentation, which lives in [another repo](https://github.com/facebook/react-native-website/). -5. Ensure the test suite passes, either locally or on CI once you opened a pull request. -6. Make sure your code lints (for example via `yarn lint --fix`). -7. Push the changes to your fork. -8. Create a pull request to the React Native repository. -9. Review and address comments on your pull request. - 1. A bot may comment with suggestions. Generally we ask you to resolve these first before a maintainer will review your code. - 2. If changes are requested and addressed, please [request review](https://docs.github.com/en/github/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/requesting-a-pull-request-review) to notify reviewers to take another look. -10. If you haven't already, please complete the [Contributor License Agreement](https://github.com/facebook/react-native/wiki/Contributor-License-Agreement) ("CLA"). **[Complete your CLA here.](https://code.facebook.com/cla)** - -**SourceTree:** -In SourceTree click Push. - -**Git Command Line** -Run `git push`. - -Whenever you are ready to contribute code, check out our [step-by-step guide to sending your first pull request](https://github.com/facebook/react-native/wiki/How-to-Open-a-Pull-Request), or read the [How to Contribute Code](https://github.com/facebook/react-native/wiki/How-to-Contribute-Code) wiki for more details. - -Click "Create Pull Request". - -Tests help us prevent regressions from being introduced to the codebase. The GitHub repository is continuously tested using Circle and Appveyor, the results of which are available through the Checks functionality on [commits](https://github.com/facebook/react-native/commits/HEAD) and pull requests. You can learn more about running and writing tests in the [Tests wiki](http://github.com/facebook/react-native/wiki/Tests). - -Someone will also have to review your change before the change is allowed to be merged in. They may ask questions for more information or ask you to change things. Be sure to respond to their comments and push additional changes to the branch if they ask you to modify things before they sign off. - -Once you are happy with the changes, and want to merge them to the main **microsoft/react-native-macos** project, create a pull request from your branch directly to **microsoft/react-native-macos master**. - -Members on the **microsoft/react-native-macos** core team will help merge your changes. - -Now you are done! Celebrate! +To learn more about how to contribute check out the Contributing section on the React Native website: +* https://reactnative.dev/contributing/overview diff --git a/Gemfile b/Gemfile index 5efda89f452582..b15113b7e057d4 100644 --- a/Gemfile +++ b/Gemfile @@ -1,6 +1,6 @@ source 'https://rubygems.org' # You may use http://rbenv.org/ or https://rvm.io/ to install and use this version -ruby '2.7.5' +ruby '2.7.6' -gem 'cocoapods', '~> 1.11', '>= 1.11.2' +gem 'cocoapods', '~> 1.11', '>= 1.11.3' diff --git a/Gemfile.lock b/Gemfile.lock index 5e8c2d4dd3031d..04cca3b39bb360 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -9,8 +9,8 @@ GEM minitest (>= 5.1) tzinfo (~> 2.0) zeitwerk (~> 2.3) - addressable (2.8.0) - public_suffix (>= 2.0.2, < 5.0) + addressable (2.8.1) + public_suffix (>= 2.0.2, < 6.0) algoliasearch (1.27.5) httpclient (~> 2.8, >= 2.8.3) json (>= 1.5.1) @@ -71,14 +71,14 @@ GEM nanaimo (0.3.0) nap (1.1.0) netrc (0.11.0) - public_suffix (4.0.6) + public_suffix (4.0.7) rexml (3.2.5) ruby-macho (2.5.1) typhoeus (1.4.0) ethon (>= 0.9.0) tzinfo (2.0.6) concurrent-ruby (~> 1.0) - xcodeproj (1.21.0) + xcodeproj (1.22.0) CFPropertyList (>= 2.3.3, < 4.0) atomos (~> 0.1.3) claide (>= 1.0.2, < 2.0) @@ -97,4 +97,4 @@ RUBY VERSION ruby 2.7.5p203 BUNDLED WITH - 2.3.10 + 2.3.22 diff --git a/IntegrationTests/AccessibilityManagerTest.js b/IntegrationTests/AccessibilityManagerTest.js index f23972f25da1bd..e68cd5bb6826ef 100644 --- a/IntegrationTests/AccessibilityManagerTest.js +++ b/IntegrationTests/AccessibilityManagerTest.js @@ -16,7 +16,7 @@ import * as React from 'react'; const {TestModule} = NativeModules; class AccessibilityManagerTest extends React.Component<{...}> { - componentDidMount() { + componentDidMount(): void { invariant( NativeAccessibilityManager, "NativeAccessibilityManager doesn't exist", diff --git a/IntegrationTests/AppEventsTest.js b/IntegrationTests/AppEventsTest.js index 5ff829b20c5a5e..e1736962006f73 100644 --- a/IntegrationTests/AppEventsTest.js +++ b/IntegrationTests/AppEventsTest.js @@ -38,7 +38,6 @@ class AppEventsTest extends React.Component<{...}, State> { NativeAppEventEmitter.addListener('testEvent', this.receiveEvent); const event = {data: TEST_PAYLOAD, ts: Date.now()}; TestModule.sendAppEvent('testEvent', event); - // eslint-disable-next-line react/no-did-mount-set-state this.setState({sent: event}); } diff --git a/IntegrationTests/AsyncStorageTest.js b/IntegrationTests/AsyncStorageTest.js deleted file mode 100644 index 63697aedfece91..00000000000000 --- a/IntegrationTests/AsyncStorageTest.js +++ /dev/null @@ -1,245 +0,0 @@ -/** - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @format - * @flow - */ - -'use strict'; - -const React = require('react'); -const ReactNative = require('react-native'); -const {AsyncStorage, Text, View, StyleSheet} = ReactNative; -const {TestModule} = ReactNative.NativeModules; - -const deepDiffer = require('react-native/Libraries/Utilities/differ/deepDiffer'); -const nullthrows = require('nullthrows'); - -const DEBUG = false; - -const KEY_1 = 'key_1'; -const VAL_1 = 'val_1'; -const KEY_2 = 'key_2'; -const VAL_2 = 'val_2'; -const KEY_MERGE = 'key_merge'; -const VAL_MERGE_1 = {foo: 1, bar: {hoo: 1, boo: 1}, moo: {a: 3}}; -const VAL_MERGE_2 = {bar: {hoo: 2}, baz: 2, moo: {a: 3}}; -const VAL_MERGE_EXPECT = {foo: 1, bar: {hoo: 2, boo: 1}, baz: 2, moo: {a: 3}}; - -// setup in componentDidMount -let done = (result: ?boolean) => {}; -let updateMessage = (message: string) => {}; - -function runTestCase(description: string, fn) { - updateMessage(description); - fn(); -} - -function expectTrue(condition: boolean, message: string) { - if (!condition) { - throw new Error(message); - } -} - -// Type-safe wrapper around JSON.stringify -function stringify( - value: - | void - | null - | string - | number - | boolean - | {...} - | $ReadOnlyArray, -): string { - if (typeof value === 'undefined') { - return 'undefined'; - } - return JSON.stringify(value); -} - -function expectEqual(lhs, rhs, testname: string) { - expectTrue( - !deepDiffer(lhs, rhs), - 'Error in test ' + - testname + - ': expected\n' + - stringify(rhs) + - '\ngot\n' + - stringify(lhs), - ); -} - -function expectAsyncNoError(place, err) { - if (err instanceof Error) { - err = err.message; - } - expectTrue( - err === null, - 'Unexpected error in ' + place + ': ' + stringify(err), - ); -} - -function testSetAndGet() { - AsyncStorage.setItem(KEY_1, VAL_1, err1 => { - expectAsyncNoError('testSetAndGet/setItem', err1); - AsyncStorage.getItem(KEY_1, (err2, result) => { - expectAsyncNoError('testSetAndGet/getItem', err2); - expectEqual(result, VAL_1, 'testSetAndGet setItem'); - updateMessage('get(key_1) correctly returned ' + String(result)); - runTestCase('should get null for missing key', testMissingGet); - }); - }); -} - -function testMissingGet() { - AsyncStorage.getItem(KEY_2, (err, result) => { - expectAsyncNoError('testMissingGet/setItem', err); - expectEqual(result, null, 'testMissingGet'); - updateMessage('missing get(key_2) correctly returned ' + String(result)); - runTestCase('check set twice results in a single key', testSetTwice); - }); -} - -function testSetTwice() { - AsyncStorage.setItem(KEY_1, VAL_1, () => { - AsyncStorage.setItem(KEY_1, VAL_1, () => { - AsyncStorage.getItem(KEY_1, (err, result) => { - expectAsyncNoError('testSetTwice/setItem', err); - expectEqual(result, VAL_1, 'testSetTwice'); - updateMessage('setTwice worked as expected'); - runTestCase('test removeItem', testRemoveItem); - }); - }); - }); -} - -function testRemoveItem() { - AsyncStorage.setItem(KEY_1, VAL_1, () => { - AsyncStorage.setItem(KEY_2, VAL_2, () => { - AsyncStorage.getAllKeys((err, result) => { - expectAsyncNoError('testRemoveItem/getAllKeys', err); - expectTrue( - nullthrows(result).indexOf(KEY_1) >= 0 && - nullthrows(result).indexOf(KEY_2) >= 0, - 'Missing KEY_1 or KEY_2 in ' + '(' + nullthrows(result).join() + ')', - ); - updateMessage('testRemoveItem - add two items'); - AsyncStorage.removeItem(KEY_1, err2 => { - expectAsyncNoError('testRemoveItem/removeItem', err2); - updateMessage('delete successful '); - AsyncStorage.getItem(KEY_1, (err3, result2) => { - expectAsyncNoError('testRemoveItem/getItem', err3); - expectEqual( - result2, - null, - 'testRemoveItem: key_1 present after delete', - ); - updateMessage('key properly removed '); - AsyncStorage.getAllKeys((err4, result3) => { - expectAsyncNoError('testRemoveItem/getAllKeys', err4); - expectTrue( - nullthrows(result3).indexOf(KEY_1) === -1, - 'Unexpected: KEY_1 present in ' + nullthrows(result3).join(), - ); - updateMessage('proper length returned.'); - runTestCase('should merge values', testMerge); - }); - }); - }); - }); - }); - }); -} - -function testMerge() { - AsyncStorage.setItem(KEY_MERGE, stringify(VAL_MERGE_1), err1 => { - expectAsyncNoError('testMerge/setItem', err1); - AsyncStorage.mergeItem(KEY_MERGE, stringify(VAL_MERGE_2), err2 => { - expectAsyncNoError('testMerge/mergeItem', err2); - AsyncStorage.getItem(KEY_MERGE, (err3, result) => { - expectAsyncNoError('testMerge/setItem', err3); - expectEqual( - JSON.parse(nullthrows(result)), - VAL_MERGE_EXPECT, - 'testMerge', - ); - updateMessage('objects deeply merged\nDone!'); - runTestCase('multi set and get', testOptimizedMultiGet); - }); - }); - }); -} - -function testOptimizedMultiGet() { - let batch = [ - [KEY_1, VAL_1], - [KEY_2, VAL_2], - ]; - let keys = batch.map(([key, value]) => key); - AsyncStorage.multiSet(batch, err1 => { - // yes, twice on purpose - [1, 2].forEach(i => { - expectAsyncNoError(`${i} testOptimizedMultiGet/multiSet`, err1); - AsyncStorage.multiGet(keys, (err2, result) => { - expectAsyncNoError(`${i} testOptimizedMultiGet/multiGet`, err2); - expectEqual(result, batch, `${i} testOptimizedMultiGet multiGet`); - updateMessage( - 'multiGet([key_1, key_2]) correctly returned ' + stringify(result), - ); - done(); - }); - }); - }); -} - -class AsyncStorageTest extends React.Component<{...}, $FlowFixMeState> { - state: any | {|done: boolean, messages: string|} = { - messages: 'Initializing...', - done: false, - }; - - componentDidMount() { - done = () => - this.setState({done: true}, () => { - TestModule.markTestCompleted(); - }); - updateMessage = msg => { - this.setState({messages: this.state.messages.concat('\n' + msg)}); - DEBUG && console.log(msg); - }; - AsyncStorage.clear(testSetAndGet); - } - - render(): React.Node { - return ( - - - { - /* $FlowFixMe[incompatible-type] (>=0.54.0 site=react_native_fb,react_ - * native_oss) This comment suppresses an error found when Flow v0.54 - * was deployed. To see the error delete this comment and run Flow. - */ - this.constructor.displayName + ': ' - } - {this.state.done ? 'Done' : 'Testing...'} - {'\n\n' + this.state.messages} - - - ); - } -} - -const styles = StyleSheet.create({ - container: { - backgroundColor: 'white', - padding: 40, - }, -}); - -AsyncStorageTest.displayName = 'AsyncStorageTest'; - -module.exports = AsyncStorageTest; diff --git a/IntegrationTests/BUCK b/IntegrationTests/BUCK index 61e3de6466aaa5..0ac92a5c69e38a 100644 --- a/IntegrationTests/BUCK +++ b/IntegrationTests/BUCK @@ -1,4 +1,4 @@ -load("@fbsource//tools/build_defs:js_glob.bzl", "js_glob") +load("@fbsource//tools/build_defs:js_library_glob.bzl", "js_library_glob") load("@fbsource//tools/build_defs/oss:metro_defs.bzl", "rn_library") # This file was generated by running @@ -6,7 +6,7 @@ load("@fbsource//tools/build_defs/oss:metro_defs.bzl", "rn_library") rn_library( name = "IntegrationTests", - srcs = js_glob( + srcs = js_library_glob( [ "**/*", ], @@ -17,7 +17,9 @@ rn_library( "websocket_integration_test_server.js", ], ), - labels = ["supermodule:xplat/default/public.react_native.tests"], + labels = [ + "pfh:ReactNative_CommonInfrastructurePlaceholder", + ], skip_processors = True, visibility = ["PUBLIC"], deps = [ diff --git a/IntegrationTests/GlobalEvalWithSourceUrlTest.js b/IntegrationTests/GlobalEvalWithSourceUrlTest.js index dd3206f3c9a34d..6b1d83ed765ac4 100644 --- a/IntegrationTests/GlobalEvalWithSourceUrlTest.js +++ b/IntegrationTests/GlobalEvalWithSourceUrlTest.js @@ -20,7 +20,7 @@ const {View} = ReactNative; const {TestModule} = ReactNative.NativeModules; class GlobalEvalWithSourceUrlTest extends React.Component<{...}> { - componentDidMount() { + componentDidMount(): void { if (typeof global.globalEvalWithSourceUrl !== 'function') { throw new Error( 'Expected to find globalEvalWithSourceUrl function on global object but found ' + diff --git a/IntegrationTests/ImageSnapshotTest.js b/IntegrationTests/ImageSnapshotTest.js index 0d6aa3bb67f627..62895ae33e7759 100644 --- a/IntegrationTests/ImageSnapshotTest.js +++ b/IntegrationTests/ImageSnapshotTest.js @@ -16,7 +16,7 @@ const {Image} = ReactNative; const {TestModule} = ReactNative.NativeModules; class ImageSnapshotTest extends React.Component<{...}> { - componentDidMount() { + componentDidMount(): void { if (!TestModule.verifySnapshot) { throw new Error('TestModule.verifySnapshot not defined.'); } diff --git a/IntegrationTests/IntegrationTestsApp.js b/IntegrationTests/IntegrationTestsApp.js index bb8efcbcd497a4..442e70327482e5 100644 --- a/IntegrationTests/IntegrationTestsApp.js +++ b/IntegrationTests/IntegrationTestsApp.js @@ -20,7 +20,6 @@ const {AppRegistry, ScrollView, StyleSheet, Text, TouchableOpacity, View} = const TESTS = [ require('./IntegrationTestHarnessTest'), require('./TimersTest'), - require('./AsyncStorageTest'), require('./LayoutEventsTest'), require('./AppEventsTest'), require('./SimpleSnapshotTest'), @@ -46,11 +45,11 @@ require('./LoggingTestModule'); type Test = any; class IntegrationTestsApp extends React.Component<{...}, $FlowFixMeState> { - state = { + state: {test: ?Test} = { test: (null: ?Test), }; - render() { + render(): React.Node { if (this.state.test) { return ( diff --git a/IntegrationTests/LayoutEventsTest.js b/IntegrationTests/LayoutEventsTest.js index 42a8e0f2b5029d..afb2ae0817ed14 100644 --- a/IntegrationTests/LayoutEventsTest.js +++ b/IntegrationTests/LayoutEventsTest.js @@ -20,7 +20,7 @@ import type {ViewStyleProp} from 'react-native/Libraries/StyleSheet/StyleSheet'; const deepDiffer = require('react-native/Libraries/Utilities/differ/deepDiffer'); -function debug(...args) { +function debug(...args: Array) { // console.log.apply(null, arguments); } @@ -125,16 +125,19 @@ class LayoutEventsTest extends React.Component { } onViewLayout: (e: LayoutEvent) => void = (e: LayoutEvent) => { + // $FlowFixMe[incompatible-call] debug('received view layout event\n', e.nativeEvent); this.setState({viewLayout: e.nativeEvent.layout}, this.checkLayout); }; onTextLayout: (e: LayoutEvent) => void = (e: LayoutEvent) => { + // $FlowFixMe[incompatible-call] debug('received text layout event\n', e.nativeEvent); this.setState({textLayout: e.nativeEvent.layout}, this.checkLayout); }; onImageLayout: (e: LayoutEvent) => void = (e: LayoutEvent) => { + // $FlowFixMe[incompatible-call] debug('received image layout event\n', e.nativeEvent); this.setState({imageLayout: e.nativeEvent.layout}, this.checkLayout); }; diff --git a/IntegrationTests/SimpleSnapshotTest.js b/IntegrationTests/SimpleSnapshotTest.js index 27e5d2c12d5454..347de5c815d3c7 100644 --- a/IntegrationTests/SimpleSnapshotTest.js +++ b/IntegrationTests/SimpleSnapshotTest.js @@ -17,7 +17,7 @@ const {StyleSheet, View} = ReactNative; const {TestModule} = ReactNative.NativeModules; class SimpleSnapshotTest extends React.Component<{...}> { - componentDidMount() { + componentDidMount(): void { if (!TestModule.verifySnapshot) { throw new Error('TestModule.verifySnapshot not defined.'); } diff --git a/IntegrationTests/SyncMethodTest.js b/IntegrationTests/SyncMethodTest.js index febe02154375f9..ab5166c057e4dd 100644 --- a/IntegrationTests/SyncMethodTest.js +++ b/IntegrationTests/SyncMethodTest.js @@ -17,7 +17,7 @@ const {View} = ReactNative; const {TestModule, RNTesterTestModule} = ReactNative.NativeModules; class SyncMethodTest extends React.Component<{...}> { - componentDidMount() { + componentDidMount(): void { if ( RNTesterTestModule.echoString('test string value') !== 'test string value' ) { diff --git a/IntegrationTests/TimersTest.js b/IntegrationTests/TimersTest.js index 64b3f1233b6a65..3a74f97edf3131 100644 --- a/IntegrationTests/TimersTest.js +++ b/IntegrationTests/TimersTest.js @@ -39,7 +39,7 @@ class TimersTest extends React.Component { }; setTimeout(fn: () => void, time: number): TimeoutID { - const id = setTimeout(() => { + const id: TimeoutID = setTimeout(() => { this._timeoutIDs.delete(id); fn(); }, time); @@ -70,7 +70,7 @@ class TimersTest extends React.Component { } setImmediate(fn: () => void): ImmediateID { - const id = setImmediate(() => { + const id: any = setImmediate(() => { this._immediateIDs.delete(id); fn(); }); @@ -81,7 +81,7 @@ class TimersTest extends React.Component { } requestAnimationFrame(fn: () => void): AnimationFrameID { - const id = requestAnimationFrame(() => { + const id: AnimationFrameID = requestAnimationFrame(() => { this._animationFrameIDs.delete(id); fn(); }); @@ -253,7 +253,7 @@ class TimersTest extends React.Component { ); } - _incrementInterval() { + _incrementInterval(): void { if (this.state.count > 3) { throw new Error('interval incremented past end.'); } diff --git a/IntegrationTests/WebSocketTest.js b/IntegrationTests/WebSocketTest.js index 6fbcbfb6cd8fa2..648478bacf1011 100644 --- a/IntegrationTests/WebSocketTest.js +++ b/IntegrationTests/WebSocketTest.js @@ -69,11 +69,11 @@ class WebSocketTest extends React.Component<{...}, State> { }); }; - _socketIsConnected = () => { + _socketIsConnected = (): boolean => { return this.state.socketState === 1; //'OPEN' }; - _socketIsDisconnected = () => { + _socketIsDisconnected = (): boolean => { return this.state.socketState === 3; //'CLOSED' }; @@ -106,7 +106,7 @@ class WebSocketTest extends React.Component<{...}, State> { this._sendText(this.state.testMessage); }; - _receivedTestExpectedResponse = () => { + _receivedTestExpectedResponse = (): boolean => { return this.state.lastMessage === this.state.testExpectedResponse; }; diff --git a/IntegrationTests/launchWebSocketServer.command b/IntegrationTests/launchWebSocketServer.command index b6aebb19c23b09..003a8abdf9df6b 100755 --- a/IntegrationTests/launchWebSocketServer.command +++ b/IntegrationTests/launchWebSocketServer.command @@ -5,18 +5,16 @@ # This source code is licensed under the MIT license found in the # LICENSE file in the root directory of this source tree. +# [macOS] Keep this file around to help Azure Pipelines run the Websocket integration test + # Set terminal title echo -en "\033]0;Web Socket Test Server\a" clear THIS_DIR=$(cd -P "$(dirname "$(readlink "${BASH_SOURCE[0]}" || echo "${BASH_SOURCE[0]}")")" && pwd) pushd "$THIS_DIR" -./websocket_integration_test_server.js 2>&1 | tee -a "${LOG_FILE}" +./websocket_integration_test_server.js popd -endLog - -if [ "$SERVERS_NO_WAIT" != "1" ]; then - echo "Process terminated. Press to close the window" - read -fi \ No newline at end of file +echo "Process terminated. Press to close the window" +read diff --git a/IntegrationTests/launchWebSocketServer.sh b/IntegrationTests/launchWebSocketServer.sh new file mode 100755 index 00000000000000..cc736a5ceffd42 --- /dev/null +++ b/IntegrationTests/launchWebSocketServer.sh @@ -0,0 +1,12 @@ +#!/bin/bash +# Copyright (c) Meta Platforms, Inc. and affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +THIS_DIR=$(cd -P "$(dirname "$(readlink "${BASH_SOURCE[0]}" || echo "${BASH_SOURCE[0]}")")" && pwd) +pushd "$THIS_DIR" || exit +./websocket_integration_test_server.js +popd || exit + +echo "Process terminated." diff --git a/Libraries/ActionSheetIOS/ActionSheetIOS.d.ts b/Libraries/ActionSheetIOS/ActionSheetIOS.d.ts new file mode 100644 index 00000000000000..89bdd373239937 --- /dev/null +++ b/Libraries/ActionSheetIOS/ActionSheetIOS.d.ts @@ -0,0 +1,80 @@ +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @format + */ + +import {ProcessedColorValue} from '../StyleSheet/processColor'; +import {ColorValue} from '../StyleSheet/StyleSheet'; + +/** + * @see: https://reactnative.dev/docs/actionsheetios#content + */ +export interface ActionSheetIOSOptions { + title?: string | undefined; + options: string[]; + cancelButtonIndex?: number | undefined; + destructiveButtonIndex?: number | number[] | undefined | null; + message?: string | undefined; + anchor?: number | undefined; + tintColor?: ColorValue | ProcessedColorValue | undefined; + cancelButtonTintColor?: ColorValue | ProcessedColorValue | undefined; + userInterfaceStyle?: 'light' | 'dark' | undefined; + disabledButtonIndices?: number[] | undefined; +} + +export interface ShareActionSheetIOSOptions { + message?: string | undefined; + url?: string | undefined; + subject?: string | undefined; + anchor?: number | undefined; + /** The activities to exclude from the ActionSheet. + * For example: ['com.apple.UIKit.activity.PostToTwitter'] + */ + excludedActivityTypes?: string[] | undefined; +} + +/** + * @see https://reactnative.dev/docs/actionsheetios#content + */ +export interface ActionSheetIOSStatic { + /** + * Display an iOS action sheet. The `options` object must contain one or more + * of: + * - `options` (array of strings) - a list of button titles (required) + * - `cancelButtonIndex` (int) - index of cancel button in `options` + * - `destructiveButtonIndex` (int) - index of destructive button in `options` + * - `title` (string) - a title to show above the action sheet + * - `message` (string) - a message to show below the title + */ + showActionSheetWithOptions: ( + options: ActionSheetIOSOptions, + callback: (buttonIndex: number) => void, + ) => void; + + /** + * Display the iOS share sheet. The `options` object should contain + * one or both of `message` and `url` and can additionally have + * a `subject` or `excludedActivityTypes`: + * + * - `url` (string) - a URL to share + * - `message` (string) - a message to share + * - `subject` (string) - a subject for the message + * - `excludedActivityTypes` (array) - the activities to exclude from the ActionSheet + * + * NOTE: if `url` points to a local file, or is a base64-encoded + * uri, the file it points to will be loaded and shared directly. + * In this way, you can share images, videos, PDF files, etc. + */ + showShareActionSheetWithOptions: ( + options: ShareActionSheetIOSOptions, + failureCallback: (error: Error) => void, + successCallback: (success: boolean, method: string) => void, + ) => void; +} + +export const ActionSheetIOS: ActionSheetIOSStatic; +export type ActionSheetIOS = ActionSheetIOSStatic; diff --git a/Libraries/ActionSheetIOS/ActionSheetIOS.js b/Libraries/ActionSheetIOS/ActionSheetIOS.js index 30ecf4a3d019a7..c9aaca1e3ad535 100644 --- a/Libraries/ActionSheetIOS/ActionSheetIOS.js +++ b/Libraries/ActionSheetIOS/ActionSheetIOS.js @@ -8,12 +8,13 @@ * @format */ +import type {ProcessedColorValue} from '../StyleSheet/processColor'; +import type {ColorValue} from '../StyleSheet/StyleSheet'; + import RCTActionSheetManager from './NativeActionSheetManager'; -const invariant = require('invariant'); const processColor = require('../StyleSheet/processColor'); -import type {ColorValue} from '../StyleSheet/StyleSheet'; -import type {ProcessedColorValue} from '../StyleSheet/processColor'; +const invariant = require('invariant'); /** * Display action sheets and share sheets on iOS. @@ -143,6 +144,13 @@ const ActionSheetIOS = { successCallback, ); }, + + dismissActionSheet: () => { + invariant(RCTActionSheetManager, "ActionSheetManager doesn't exist"); + if (typeof RCTActionSheetManager.dismissActionSheet === 'function') { + RCTActionSheetManager.dismissActionSheet(); + } + }, }; module.exports = ActionSheetIOS; diff --git a/Libraries/ActionSheetIOS/NativeActionSheetManager.js b/Libraries/ActionSheetIOS/NativeActionSheetManager.js index fb0a92ddb5d235..8247ac260aff99 100644 --- a/Libraries/ActionSheetIOS/NativeActionSheetManager.js +++ b/Libraries/ActionSheetIOS/NativeActionSheetManager.js @@ -9,6 +9,7 @@ */ import type {TurboModule} from '../TurboModule/RCTExport'; + import * as TurboModuleRegistry from '../TurboModule/TurboModuleRegistry'; export interface Spec extends TurboModule { @@ -47,6 +48,7 @@ export interface Spec extends TurboModule { |}) => void, successCallback: (completed: boolean, activityType: ?string) => void, ) => void; + +dismissActionSheet?: () => void; } export default (TurboModuleRegistry.get('ActionSheetManager'): ?Spec); diff --git a/Libraries/ActionSheetIOS/React-RCTActionSheet.podspec b/Libraries/ActionSheetIOS/React-RCTActionSheet.podspec index 53caeb76297ea0..75459a8a872d8c 100644 --- a/Libraries/ActionSheetIOS/React-RCTActionSheet.podspec +++ b/Libraries/ActionSheetIOS/React-RCTActionSheet.podspec @@ -24,7 +24,7 @@ Pod::Spec.new do |s| s.documentation_url = "https://reactnative.dev/docs/actionsheetios" s.license = package["license"] s.author = "Facebook, Inc. and its affiliates" - s.platforms = { :ios => "11.0", :osx => "10.15" } # [macOS] + s.platforms = { :ios => "12.4", :osx => "10.15" } # [macOS] s.source = source s.source_files = "*.{m}" s.preserve_paths = "package.json", "LICENSE", "LICENSE-docs" diff --git a/Libraries/AddressSanitizerCrash/AddressSanitizerCrash.js b/Libraries/AddressSanitizerCrash/AddressSanitizerCrash.js new file mode 100644 index 00000000000000..06790e7bc25a7b --- /dev/null +++ b/Libraries/AddressSanitizerCrash/AddressSanitizerCrash.js @@ -0,0 +1,13 @@ +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @format + * @flow strict-local + */ + +import NativeAddressSanitizerCrash from './NativeAddressSanitizerCrash'; + +module.exports = NativeAddressSanitizerCrash; diff --git a/Libraries/AddressSanitizerCrash/NativeAddressSanitizerCrash.js b/Libraries/AddressSanitizerCrash/NativeAddressSanitizerCrash.js new file mode 100644 index 00000000000000..e8e54586ad6e20 --- /dev/null +++ b/Libraries/AddressSanitizerCrash/NativeAddressSanitizerCrash.js @@ -0,0 +1,19 @@ +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @flow strict-local + * @format + */ + +import type {TurboModule} from '../TurboModule/RCTExport'; + +import * as TurboModuleRegistry from '../TurboModule/TurboModuleRegistry'; + +export interface Spec extends TurboModule {} + +export default (TurboModuleRegistry.get( + 'RCTAddressSanitizerCrash', +): ?Spec); diff --git a/Libraries/AddressSanitizerCrash/RCTAddressSanitizerCrash.js b/Libraries/AddressSanitizerCrash/RCTAddressSanitizerCrash.js deleted file mode 100644 index d2a098b6517e41..00000000000000 --- a/Libraries/AddressSanitizerCrash/RCTAddressSanitizerCrash.js +++ /dev/null @@ -1,24 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @format - * @flow - */ - -'use strict'; -import type {HostComponent} from '../Renderer/shims/ReactNativeTypes'; -import type {ViewProps} from '../Components/View/ViewPropTypes'; - -const {requireNativeComponent} = require('react-native'); - -type NativeProps = $ReadOnly<{| - ...ViewProps, -|}>; - -const RCTAddressSanitizerCrash: HostComponent = - requireNativeComponent('RCTAddressSanitizerCrash'); - -module.exports = RCTAddressSanitizerCrash; diff --git a/Libraries/Alert/Alert.d.ts b/Libraries/Alert/Alert.d.ts new file mode 100644 index 00000000000000..a05fe55a877f90 --- /dev/null +++ b/Libraries/Alert/Alert.d.ts @@ -0,0 +1,90 @@ +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @format + */ + +/** + * @see https://reactnative.dev/docs/alert#content + */ +export interface AlertButton { + text?: string | undefined; + onPress?: ((value?: string) => void) | undefined; + isPreferred?: boolean; + style?: 'default' | 'cancel' | 'destructive' | undefined; +} + +interface AlertOptions { + /** @platform android */ + cancelable?: boolean | undefined; + userInterfaceStyle?: 'unspecified' | 'light' | 'dark'; + /** @platform android */ + onDismiss?: (() => void) | undefined; +} + +/** + * Launches an alert dialog with the specified title and message. + * + * Optionally provide a list of buttons. Tapping any button will fire the + * respective onPress callback and dismiss the alert. By default, the only + * button will be an 'OK' button. + * + * This is an API that works both on iOS and Android and can show static + * alerts. To show an alert that prompts the user to enter some information, + * see `AlertIOS`; entering text in an alert is common on iOS only. + * + * ## iOS + * + * On iOS you can specify any number of buttons. Each button can optionally + * specify a style, which is one of 'default', 'cancel' or 'destructive'. + * + * ## Android + * + * On Android at most three buttons can be specified. Android has a concept + * of a neutral, negative and a positive button: + * + * - If you specify one button, it will be the 'positive' one (such as 'OK') + * - Two buttons mean 'negative', 'positive' (such as 'Cancel', 'OK') + * - Three buttons mean 'neutral', 'negative', 'positive' (such as 'Later', 'Cancel', 'OK') + * + * ``` + * // Works on both iOS and Android + * Alert.alert( + * 'Alert Title', + * 'My Alert Msg', + * [ + * {text: 'Ask me later', onPress: () => console.log('Ask me later pressed')}, + * {text: 'Cancel', onPress: () => console.log('Cancel Pressed'), style: 'cancel'}, + * {text: 'OK', onPress: () => console.log('OK Pressed')}, + * ] + * ) + * ``` + */ +export interface AlertStatic { + alert: ( + title: string, + message?: string, + buttons?: AlertButton[], + options?: AlertOptions, + ) => void; + prompt: ( + title: string, + message?: string, + callbackOrButtons?: ((text: string) => void) | AlertButton[], + type?: AlertType, + defaultValue?: string, + keyboardType?: string, + ) => void; +} + +export type AlertType = + | 'default' + | 'plain-text' + | 'secure-text' + | 'login-password'; + +export const Alert: AlertStatic; +export type Alert = AlertStatic; diff --git a/Libraries/Alert/Alert.js b/Libraries/Alert/Alert.js index 5c55623168c0ee..852af04e049ee0 100644 --- a/Libraries/Alert/Alert.js +++ b/Libraries/Alert/Alert.js @@ -8,8 +8,9 @@ * @flow */ -import Platform from '../Utilities/Platform'; import type {DialogOptions} from '../NativeModules/specs/NativeDialogManagerAndroid'; + +import Platform from '../Utilities/Platform'; import RCTAlertManager from './RCTAlertManager'; export type AlertType = @@ -21,6 +22,7 @@ export type AlertButtonStyle = 'default' | 'cancel' | 'destructive'; export type Buttons = Array<{ text?: string, onPress?: ?Function, + isPreferred?: boolean, style?: AlertButtonStyle, ... }>; @@ -34,6 +36,7 @@ export type DefaultInputsArray = Array<{ type Options = { cancelable?: ?boolean, + userInterfaceStyle?: 'unspecified' | 'light' | 'dark', onDismiss?: ?() => void, // [macOS modal?: ?boolean, @@ -55,7 +58,15 @@ class Alert { options?: Options, ): void { if (Platform.OS === 'ios') { - Alert.prompt(title, message, buttons, 'default'); + Alert.prompt( + title, + message, + buttons, + 'default', + undefined, + undefined, + options, + ); // [macOS } else if (Platform.OS === 'macos') { Alert.promptMacOS( @@ -105,6 +116,8 @@ class Alert { config.buttonPositive = buttonPositive.text || defaultPositiveText; } + /* $FlowFixMe[missing-local-annot] The type annotation(s) required by + * Flow's LTI update could not be added via codemod */ const onAction = (action, buttonKey) => { if (action === constants.buttonClicked) { if (buttonKey === constants.buttonNeutral) { @@ -118,7 +131,7 @@ class Alert { options && options.onDismiss && options.onDismiss(); } }; - const onError = errorMessage => console.warn(errorMessage); + const onError = (errorMessage: string) => console.warn(errorMessage); NativeDialogManagerAndroid.showAlert(config, onError, onAction); } } @@ -130,12 +143,14 @@ class Alert { type?: ?AlertType = 'plain-text', defaultValue?: string, keyboardType?: string, + options?: Options, ): void { if (Platform.OS === 'ios') { - let callbacks = []; + let callbacks: Array = []; const buttons = []; let cancelButtonKey; let destructiveButtonKey; + let preferredButtonKey; if (typeof callbackOrButtons === 'function') { callbacks = [callbackOrButtons]; } else if (Array.isArray(callbackOrButtons)) { @@ -146,8 +161,11 @@ class Alert { } else if (btn.style === 'destructive') { destructiveButtonKey = String(index); } + if (btn.isPreferred) { + preferredButtonKey = String(index); + } if (btn.text || index < (callbackOrButtons || []).length - 1) { - const btnDef = {}; + const btnDef: {[number]: string} = {}; btnDef[index] = btn.text || ''; buttons.push(btnDef); } @@ -163,7 +181,9 @@ class Alert { defaultValue, cancelButtonKey, destructiveButtonKey, + preferredButtonKey, keyboardType, + userInterfaceStyle: options?.userInterfaceStyle || undefined, }, (id, value) => { const cb = callbacks[id]; @@ -243,7 +263,7 @@ class Alert { callbackOrButtons.forEach((btn, index) => { callbacks[index] = btn.onPress; if (btn.text || index < (callbackOrButtons || []).length - 1) { - const btnDef = {}; + const btnDef: {[number]: string} = {}; btnDef[index] = btn.text || ''; buttons.push(btnDef); } diff --git a/Libraries/Alert/Alert.js.flow b/Libraries/Alert/Alert.js.flow new file mode 100644 index 00000000000000..7e5013a0936499 --- /dev/null +++ b/Libraries/Alert/Alert.js.flow @@ -0,0 +1,65 @@ +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @format + * @flow + */ + +export type AlertType = + | 'default' + | 'plain-text' + | 'secure-text' + | 'login-password'; +export type AlertButtonStyle = 'default' | 'cancel' | 'destructive'; +export type Buttons = Array<{ + text?: string, + onPress?: ?Function, + isPreferred?: boolean, + style?: AlertButtonStyle, + ... +}>; +// [macOS +export type DefaultInputsArray = Array<{ + default?: string, + placeholder?: string, + style?: AlertButtonStyle, +}>; +// macOS] +type Options = { + cancelable?: ?boolean, + userInterfaceStyle?: 'unspecified' | 'light' | 'dark', + onDismiss?: ?() => void, + ... +}; + +declare class Alert { + static alert( + title: ?string, + message?: ?string, + buttons?: Buttons, + options?: Options, + ): void; + static prompt( + title: ?string, + message?: ?string, + callbackOrButtons?: ?(((text: string) => void) | Buttons), + type?: ?AlertType, + defaultValue?: string, + keyboardType?: string, + options?: Options, + ): void; + static promptMacOS( + title: ?string, + message?: ?string, + callbackOrButtons?: ?((text: string) => void) | Buttons, + type?: ?AlertType, + defaultInputs?: DefaultInputsArray, + modal?: ?boolean, + critical?: ?boolean, + ): void; +} + +module.exports = Alert; diff --git a/Libraries/Alert/NativeAlertManager.js b/Libraries/Alert/NativeAlertManager.js index 0438af72442c75..9bd3836bb4d720 100644 --- a/Libraries/Alert/NativeAlertManager.js +++ b/Libraries/Alert/NativeAlertManager.js @@ -9,6 +9,7 @@ */ import type {TurboModule} from '../TurboModule/RCTExport'; + import * as TurboModuleRegistry from '../TurboModule/TurboModuleRegistry'; export type Args = {| @@ -19,7 +20,9 @@ export type Args = {| defaultValue?: string, cancelButtonKey?: string, destructiveButtonKey?: string, + preferredButtonKey?: string, keyboardType?: string, + userInterfaceStyle?: string, // [macOS defaultInputs?: Array, modal?: ?boolean, diff --git a/Libraries/Alert/RCTAlertManager.ios.js b/Libraries/Alert/RCTAlertManager.ios.js index 01f055da53d402..d4e9eab97ff66c 100644 --- a/Libraries/Alert/RCTAlertManager.ios.js +++ b/Libraries/Alert/RCTAlertManager.ios.js @@ -8,9 +8,10 @@ * @flow strict-local */ -import NativeAlertManager from './NativeAlertManager'; import type {Args} from './NativeAlertManager'; +import NativeAlertManager from './NativeAlertManager'; + module.exports = { alertWithArgs( args: Args, diff --git a/Libraries/Animated/Animated.d.ts b/Libraries/Animated/Animated.d.ts new file mode 100644 index 00000000000000..215f773cac2411 --- /dev/null +++ b/Libraries/Animated/Animated.d.ts @@ -0,0 +1,587 @@ +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @format + */ + +import type * as React from 'react'; +import {ScrollView} from '../Components/ScrollView/ScrollView'; +import {View} from '../Components/View/View'; +import {Image} from '../Image/Image'; +import {FlatListProps} from '../Lists/FlatList'; +import {DefaultSectionT, SectionListProps} from '../Lists/SectionList'; +import {ColorValue} from '../StyleSheet/StyleSheet'; +import {Text} from '../Text/Text'; +import {NativeSyntheticEvent} from '../Types/CoreEventTypes'; + +export namespace Animated { + type AnimatedValue = Value; + type AnimatedValueXY = ValueXY; + + class Animated { + // Internal class, no public API. + } + + class AnimatedNode { + /** + * Adds an asynchronous listener to the value so you can observe updates from + * animations. This is useful because there is no way to + * synchronously read the value because it might be driven natively. + * + * See https://reactnative.dev/docs/animatedvalue.html#addlistener + */ + addListener(callback: (value: any) => any): string; + /** + * Unregister a listener. The `id` param shall match the identifier + * previously returned by `addListener()`. + * + * See https://reactnative.dev/docs/animatedvalue.html#removelistener + */ + removeListener(id: string): void; + /** + * Remove all registered listeners. + * + * See https://reactnative.dev/docs/animatedvalue.html#removealllisteners + */ + removeAllListeners(): void; + + hasListeners(): boolean; + } + + class AnimatedWithChildren extends AnimatedNode { + // Internal class, no public API. + } + + type RgbaValue = { + readonly r: number; + readonly g: number; + readonly b: number; + readonly a: number; + }; + + type RgbaAnimatedValue = { + readonly r: AnimatedValue; + readonly g: AnimatedValue; + readonly b: AnimatedValue; + readonly a: AnimatedValue; + }; + + type AnimatedConfig = { + readonly useNativeDriver: boolean; + }; + + class AnimatedColor extends AnimatedWithChildren { + r: AnimatedValue; + g: AnimatedValue; + b: AnimatedValue; + a: AnimatedValue; + + constructor( + valueIn?: RgbaValue | RgbaAnimatedValue | ColorValue | null, + config?: AnimatedConfig | null, + ); + nativeColor: unknown; // Unsure what to do here + setValue: (value: RgbaValue | ColorValue) => void; + setOffset: (offset: RgbaValue) => void; + flattenOffset: () => void; + extractOffset: () => void; + addListener: (callback: (value: ColorValue) => unknown) => string; + removeListener: (id: string) => void; + removeAllListeners: () => void; + stopAnimation: (callback: (value: ColorValue) => unknown) => void; + resetAnimation: (callback: (value: ColorValue) => unknown) => void; + } + + class AnimatedInterpolation< + OutputT extends number | string, + > extends AnimatedWithChildren { + interpolate( + config: InterpolationConfigType, + ): AnimatedInterpolation; + } + + type ExtrapolateType = 'extend' | 'identity' | 'clamp'; + + type InterpolationConfigType = { + inputRange: number[]; + outputRange: number[] | string[]; + easing?: ((input: number) => number) | undefined; + extrapolate?: ExtrapolateType | undefined; + extrapolateLeft?: ExtrapolateType | undefined; + extrapolateRight?: ExtrapolateType | undefined; + }; + + type ValueListenerCallback = (state: {value: number}) => void; + + /** + * Standard value for driving animations. One `Animated.Value` can drive + * multiple properties in a synchronized fashion, but can only be driven by one + * mechanism at a time. Using a new mechanism (e.g. starting a new animation, + * or calling `setValue`) will stop any previous ones. + */ + export class Value extends AnimatedWithChildren { + constructor(value: number, config?: AnimatedConfig | null); + + /** + * Directly set the value. This will stop any animations running on the value + * and update all the bound properties. + */ + setValue(value: number): void; + + /** + * Sets an offset that is applied on top of whatever value is set, whether via + * `setValue`, an animation, or `Animated.event`. Useful for compensating + * things like the start of a pan gesture. + */ + setOffset(offset: number): void; + + /** + * Merges the offset value into the base value and resets the offset to zero. + * The final output of the value is unchanged. + */ + flattenOffset(): void; + + /** + * Sets the offset value to the base value, and resets the base value to zero. + * The final output of the value is unchanged. + */ + extractOffset(): void; + + /** + * Adds an asynchronous listener to the value so you can observe updates from + * animations. This is useful because there is no way to + * synchronously read the value because it might be driven natively. + */ + addListener(callback: ValueListenerCallback): string; + + removeListener(id: string): void; + + removeAllListeners(): void; + + /** + * Stops any running animation or tracking. `callback` is invoked with the + * final value after stopping the animation, which is useful for updating + * state to match the animation position with layout. + */ + stopAnimation(callback?: (value: number) => void): void; + + /** + * Interpolates the value before updating the property, e.g. mapping 0-1 to + * 0-10. + */ + interpolate( + config: InterpolationConfigType, + ): AnimatedInterpolation; + } + + type ValueXYListenerCallback = (value: {x: number; y: number}) => void; + + /** + * 2D Value for driving 2D animations, such as pan gestures. Almost identical + * API to normal `Animated.Value`, but multiplexed. Contains two regular + * `Animated.Value`s under the hood. + */ + export class ValueXY extends AnimatedWithChildren { + x: AnimatedValue; + y: AnimatedValue; + + constructor( + valueIn?: {x: number | AnimatedValue; y: number | AnimatedValue}, + config?: AnimatedConfig | null, + ); + + setValue(value: {x: number; y: number}): void; + + setOffset(offset: {x: number; y: number}): void; + + flattenOffset(): void; + + extractOffset(): void; + + stopAnimation(callback?: (value: {x: number; y: number}) => void): void; + + addListener(callback: ValueXYListenerCallback): string; + + removeListener(id: string): void; + + /** + * Converts `{x, y}` into `{left, top}` for use in style, e.g. + * + *```javascript + * style={this.state.anim.getLayout()} + *``` + */ + getLayout(): {[key: string]: AnimatedValue}; + + /** + * Converts `{x, y}` into a useable translation transform, e.g. + * + *```javascript + * style={{ + * transform: this.state.anim.getTranslateTransform() + * }} + *``` + */ + getTranslateTransform(): [ + {translateX: AnimatedValue}, + {translateY: AnimatedValue}, + ]; + } + + type EndResult = {finished: boolean}; + type EndCallback = (result: EndResult) => void; + + export interface CompositeAnimation { + /** + * Animations are started by calling start() on your animation. + * start() takes a completion callback that will be called when the + * animation is done or when the animation is done because stop() was + * called on it before it could finish. + * + * @param callback - Optional function that will be called + * after the animation finished running normally or when the animation + * is done because stop() was called on it before it could finish + * + * @example + * Animated.timing({}).start(({ finished }) => { + * // completion callback + * }); + */ + start: (callback?: EndCallback) => void; + /** + * Stops any running animation. + */ + stop: () => void; + /** + * Stops any running animation and resets the value to its original. + */ + reset: () => void; + } + + interface AnimationConfig { + isInteraction?: boolean | undefined; + useNativeDriver: boolean; + } + + /** + * Animates a value from an initial velocity to zero based on a decay + * coefficient. + */ + export function decay( + value: AnimatedValue | AnimatedValueXY, + config: DecayAnimationConfig, + ): CompositeAnimation; + + interface DecayAnimationConfig extends AnimationConfig { + velocity: number | {x: number; y: number}; + deceleration?: number | undefined; + } + + /** + * Animates a value along a timed easing curve. The `Easing` module has tons + * of pre-defined curves, or you can use your own function. + */ + export const timing: ( + value: AnimatedValue | AnimatedValueXY, + config: TimingAnimationConfig, + ) => CompositeAnimation; + + interface TimingAnimationConfig extends AnimationConfig { + toValue: + | number + | AnimatedValue + | {x: number; y: number} + | AnimatedValueXY + | AnimatedInterpolation; + easing?: ((value: number) => number) | undefined; + duration?: number | undefined; + delay?: number | undefined; + } + + interface SpringAnimationConfig extends AnimationConfig { + toValue: + | number + | AnimatedValue + | {x: number; y: number} + | AnimatedValueXY + | RgbaValue + | AnimatedColor + | AnimatedInterpolation; + overshootClamping?: boolean | undefined; + restDisplacementThreshold?: number | undefined; + restSpeedThreshold?: number | undefined; + velocity?: number | {x: number; y: number} | undefined; + bounciness?: number | undefined; + speed?: number | undefined; + tension?: number | undefined; + friction?: number | undefined; + stiffness?: number | undefined; + mass?: number | undefined; + damping?: number | undefined; + delay?: number | undefined; + } + + interface LoopAnimationConfig { + iterations?: number | undefined; // default -1 for infinite + /** + * Defaults to `true` + */ + resetBeforeIteration?: boolean | undefined; + } + + /** + * Creates a new Animated value composed from two Animated values added + * together. + */ + export function add( + a: Animated, + b: Animated, + ): AnimatedAddition; + + class AnimatedAddition< + OutputT extends number | string, + > extends AnimatedInterpolation {} + + /** + * Creates a new Animated value composed by subtracting the second Animated + * value from the first Animated value. + */ + export function subtract( + a: Animated, + b: Animated, + ): AnimatedSubtraction; + + class AnimatedSubtraction< + OutputT extends number | string, + > extends AnimatedInterpolation {} + + /** + * Creates a new Animated value composed by dividing the first Animated + * value by the second Animated value. + */ + export function divide( + a: Animated, + b: Animated, + ): AnimatedDivision; + + class AnimatedDivision< + OutputT extends number | string, + > extends AnimatedInterpolation {} + + /** + * Creates a new Animated value composed from two Animated values multiplied + * together. + */ + export function multiply( + a: Animated, + b: Animated, + ): AnimatedMultiplication; + + class AnimatedMultiplication< + OutputT extends number | string, + > extends AnimatedInterpolation {} + + /** + * Creates a new Animated value that is the (non-negative) modulo of the + * provided Animated value + */ + export function modulo( + a: Animated, + modulus: number, + ): AnimatedModulo; + + class AnimatedModulo< + OutputT extends number | string, + > extends AnimatedInterpolation {} + + /** + * Create a new Animated value that is limited between 2 values. It uses the + * difference between the last value so even if the value is far from the bounds + * it will start changing when the value starts getting closer again. + * (`value = clamp(value + diff, min, max)`). + * + * This is useful with scroll events, for example, to show the navbar when + * scrolling up and to hide it when scrolling down. + */ + export function diffClamp( + a: Animated, + min: number, + max: number, + ): AnimatedDiffClamp; + + class AnimatedDiffClamp< + OutputT extends number | string, + > extends AnimatedInterpolation {} + + /** + * Starts an animation after the given delay. + */ + export function delay(time: number): CompositeAnimation; + + /** + * Starts an array of animations in order, waiting for each to complete + * before starting the next. If the current running animation is stopped, no + * following animations will be started. + */ + export function sequence( + animations: Array, + ): CompositeAnimation; + + /** + * Array of animations may run in parallel (overlap), but are started in + * sequence with successive delays. Nice for doing trailing effects. + */ + + export function stagger( + time: number, + animations: Array, + ): CompositeAnimation; + + /** + * Loops a given animation continuously, so that each time it reaches the end, + * it resets and begins again from the start. Can specify number of times to + * loop using the key 'iterations' in the config. Will loop without blocking + * the UI thread if the child animation is set to 'useNativeDriver'. + */ + + export function loop( + animation: CompositeAnimation, + config?: LoopAnimationConfig, + ): CompositeAnimation; + + /** + * Spring animation based on Rebound and Origami. Tracks velocity state to + * create fluid motions as the `toValue` updates, and can be chained together. + */ + export function spring( + value: AnimatedValue | AnimatedValueXY, + config: SpringAnimationConfig, + ): CompositeAnimation; + + type ParallelConfig = { + stopTogether?: boolean | undefined; // If one is stopped, stop all. default: true + }; + + /** + * Starts an array of animations all at the same time. By default, if one + * of the animations is stopped, they will all be stopped. You can override + * this with the `stopTogether` flag. + */ + export function parallel( + animations: Array, + config?: ParallelConfig, + ): CompositeAnimation; + + type Mapping = {[key: string]: Mapping} | AnimatedValue; + interface EventConfig { + listener?: ((event: NativeSyntheticEvent) => void) | undefined; + useNativeDriver: boolean; + } + + /** + * Takes an array of mappings and extracts values from each arg accordingly, + * then calls `setValue` on the mapped outputs. e.g. + * + *```javascript + * onScroll={Animated.event( + * [{nativeEvent: {contentOffset: {x: this._scrollX}}}] + * {listener}, // Optional async listener + * ) + * ... + * onPanResponderMove: Animated.event([ + * null, // raw event arg ignored + * {dx: this._panX}, // gestureState arg + * ]), + *``` + */ + export function event( + argMapping: Array, + config?: EventConfig, + ): (...args: any[]) => void; + + export type ComponentProps = T extends + | React.ComponentType + | React.Component + ? P + : never; + + export type LegacyRef = {getNode(): C}; + + type Nullable = undefined | null; + type Primitive = string | number | boolean | symbol; + type Builtin = Function | Date | Error | RegExp; + + interface WithAnimatedArray

extends Array> {} + type WithAnimatedObject = { + [K in keyof T]: WithAnimatedValue; + }; + + export type WithAnimatedValue = T extends Builtin | Nullable + ? T + : T extends Primitive + ? T | Value | AnimatedInterpolation // add `Value` and `AnimatedInterpolation` but also preserve original T + : T extends Array + ? WithAnimatedArray

+ : T extends {} + ? WithAnimatedObject + : T; // in case it's something we don't yet know about (for .e.g bigint) + + type NonAnimatedProps = 'key' | 'ref'; + + type TAugmentRef = T extends React.Ref + ? React.Ref> + : never; + + export type AnimatedProps = { + [key in keyof T]: key extends NonAnimatedProps + ? key extends 'ref' + ? TAugmentRef + : T[key] + : WithAnimatedValue; + }; + + export interface AnimatedComponent> + extends React.FC>> {} + + export type AnimatedComponentOptions = { + collapsable?: boolean; + }; + + /** + * Make any React component Animatable. Used to create `Animated.View`, etc. + */ + export function createAnimatedComponent>( + component: T, + options?: AnimatedComponentOptions, + ): AnimatedComponent; + + /** + * Animated variants of the basic native views. Accepts Animated.Value for + * props and style. + */ + export const View: AnimatedComponent; + export const Image: AnimatedComponent; + export const Text: AnimatedComponent; + export const ScrollView: AnimatedComponent; + + /** + * FlatList and SectionList infer generic Type defined under their `data` and `section` props. + */ + export class FlatList extends React.Component< + AnimatedProps> + > {} + export class SectionList< + ItemT = any, + SectionT = DefaultSectionT, + > extends React.Component>> {} +} + +// We need to alias these views so we can reference them in the Animated +// namespace where their names are shadowed. +declare const _View: typeof View; +declare const _Image: typeof Image; +declare const _Text: typeof Text; +declare const _ScrollView: typeof ScrollView; diff --git a/Libraries/Animated/Animated.js b/Libraries/Animated/Animated.js index 70beabf56a98a9..ec17ef764543ee 100644 --- a/Libraries/Animated/Animated.js +++ b/Libraries/Animated/Animated.js @@ -8,7 +8,8 @@ * @format */ -import Platform from '../Utilities/Platform'; +export type {CompositeAnimation, Numeric} from './AnimatedImplementation'; + import typeof AnimatedFlatList from './components/AnimatedFlatList'; import typeof AnimatedImage from './components/AnimatedImage'; import typeof AnimatedScrollView from './components/AnimatedScrollView'; @@ -16,31 +17,32 @@ import typeof AnimatedSectionList from './components/AnimatedSectionList'; import typeof AnimatedText from './components/AnimatedText'; import typeof AnimatedView from './components/AnimatedView'; -const AnimatedMock = require('./AnimatedMock'); -const AnimatedImplementation = require('./AnimatedImplementation'); +import Platform from '../Utilities/Platform'; +import AnimatedImplementation from './AnimatedImplementation'; +import AnimatedMock from './AnimatedMock'; const Animated = ((Platform.isTesting ? AnimatedMock - : AnimatedImplementation): typeof AnimatedMock); + : AnimatedImplementation): typeof AnimatedImplementation); -module.exports = { +export default { get FlatList(): AnimatedFlatList { - return require('./components/AnimatedFlatList'); + return require('./components/AnimatedFlatList').default; }, get Image(): AnimatedImage { - return require('./components/AnimatedImage'); + return require('./components/AnimatedImage').default; }, get ScrollView(): AnimatedScrollView { - return require('./components/AnimatedScrollView'); + return require('./components/AnimatedScrollView').default; }, get SectionList(): AnimatedSectionList { - return require('./components/AnimatedSectionList'); + return require('./components/AnimatedSectionList').default; }, get Text(): AnimatedText { - return require('./components/AnimatedText'); + return require('./components/AnimatedText').default; }, get View(): AnimatedView { - return require('./components/AnimatedView'); + return require('./components/AnimatedView').default; }, ...Animated, }; diff --git a/Libraries/Animated/AnimatedEvent.js b/Libraries/Animated/AnimatedEvent.js index 9aa49926152a86..7279c2af4deaa2 100644 --- a/Libraries/Animated/AnimatedEvent.js +++ b/Libraries/Animated/AnimatedEvent.js @@ -10,17 +10,14 @@ 'use strict'; -const AnimatedValue = require('./nodes/AnimatedValue'); -const AnimatedValueXY = require('./nodes/AnimatedValueXY'); -const NativeAnimatedHelper = require('./NativeAnimatedHelper'); -const ReactNative = require('../Renderer/shims/ReactNative'); - -const invariant = require('invariant'); - -const {shouldUseNativeDriver} = require('./NativeAnimatedHelper'); - import type {PlatformConfig} from './AnimatedPlatformConfig'; +import {findNodeHandle} from '../ReactNative/RendererProxy'; +import NativeAnimatedHelper from './NativeAnimatedHelper'; +import AnimatedValue from './nodes/AnimatedValue'; +import AnimatedValueXY from './nodes/AnimatedValueXY'; +import invariant from 'invariant'; + export type Mapping = | {[key: string]: Mapping, ...} | AnimatedValue @@ -31,7 +28,7 @@ export type EventConfig = { platformConfig?: PlatformConfig, }; -function attachNativeEvent( +export function attachNativeEvent( viewRef: any, eventName: string, argMapping: $ReadOnlyArray, @@ -41,7 +38,7 @@ function attachNativeEvent( // key path inside the `nativeEvent` object. Ex.: ['contentOffset', 'x']. const eventMappings = []; - const traverse = (value, path) => { + const traverse = (value: mixed, path: Array) => { if (value instanceof AnimatedValue) { value.__makeNative(platformConfig); @@ -67,7 +64,7 @@ function attachNativeEvent( // Assume that the event containing `nativeEvent` is always the first argument. traverse(argMapping[0].nativeEvent, []); - const viewTag = ReactNative.findNodeHandle(viewRef); + const viewTag = findNodeHandle(viewRef); if (viewTag != null) { eventMappings.forEach(mapping => { NativeAnimatedHelper.API.addAnimatedEventToView( @@ -94,8 +91,8 @@ function attachNativeEvent( }; } -function validateMapping(argMapping, args) { - const validate = (recMapping, recEvt, key) => { +function validateMapping(argMapping: $ReadOnlyArray, args: any) { + const validate = (recMapping: ?Mapping, recEvt: any, key: string) => { if (recMapping instanceof AnimatedValue) { invariant( typeof recEvt === 'number', @@ -146,7 +143,7 @@ function validateMapping(argMapping, args) { }); } -class AnimatedEvent { +export class AnimatedEvent { _argMapping: $ReadOnlyArray; _listeners: Array = []; _attachedEvent: ?{detach: () => void, ...}; @@ -165,7 +162,7 @@ class AnimatedEvent { this.__addListener(config.listener); } this._attachedEvent = null; - this.__isNative = shouldUseNativeDriver(config); + this.__isNative = NativeAnimatedHelper.shouldUseNativeDriver(config); this.__platformConfig = config.platformConfig; } @@ -177,7 +174,7 @@ class AnimatedEvent { this._listeners = this._listeners.filter(listener => listener !== callback); } - __attach(viewRef: any, eventName: string) { + __attach(viewRef: any, eventName: string): void { invariant( this.__isNative, 'Only native driven events need to be attached.', @@ -191,7 +188,7 @@ class AnimatedEvent { ); } - __detach(viewTag: any, eventName: string) { + __detach(viewTag: any, eventName: string): void { invariant( this.__isNative, 'Only native driven events need to be detached.', @@ -223,7 +220,10 @@ class AnimatedEvent { validatedMapping = true; } - const traverse = (recMapping, recEvt) => { + const traverse = ( + recMapping: ?(Mapping | AnimatedValue), + recEvt: any, + ) => { if (recMapping instanceof AnimatedValue) { if (typeof recEvt === 'number') { recMapping.setValue(recEvt); @@ -254,5 +254,3 @@ class AnimatedEvent { this._listeners.forEach(listener => listener(...args)); }; } - -module.exports = {AnimatedEvent, attachNativeEvent}; diff --git a/Libraries/Animated/AnimatedImplementation.js b/Libraries/Animated/AnimatedImplementation.js index e93c0dda4ccfc5..7e25c65f2a461e 100644 --- a/Libraries/Animated/AnimatedImplementation.js +++ b/Libraries/Animated/AnimatedImplementation.js @@ -10,35 +10,33 @@ 'use strict'; -const {AnimatedEvent, attachNativeEvent} = require('./AnimatedEvent'); -const AnimatedAddition = require('./nodes/AnimatedAddition'); -const AnimatedDiffClamp = require('./nodes/AnimatedDiffClamp'); -const AnimatedDivision = require('./nodes/AnimatedDivision'); -const AnimatedInterpolation = require('./nodes/AnimatedInterpolation'); -const AnimatedModulo = require('./nodes/AnimatedModulo'); -const AnimatedMultiplication = require('./nodes/AnimatedMultiplication'); -const AnimatedNode = require('./nodes/AnimatedNode'); -const AnimatedSubtraction = require('./nodes/AnimatedSubtraction'); -const AnimatedTracking = require('./nodes/AnimatedTracking'); -const AnimatedValue = require('./nodes/AnimatedValue'); -const AnimatedValueXY = require('./nodes/AnimatedValueXY'); -const DecayAnimation = require('./animations/DecayAnimation'); -const SpringAnimation = require('./animations/SpringAnimation'); -const TimingAnimation = require('./animations/TimingAnimation'); - -const createAnimatedComponent = require('./createAnimatedComponent'); - +import type {EventConfig, Mapping} from './AnimatedEvent'; import type { AnimationConfig, EndCallback, EndResult, } from './animations/Animation'; -import type {TimingAnimationConfig} from './animations/TimingAnimation'; import type {DecayAnimationConfig} from './animations/DecayAnimation'; import type {SpringAnimationConfig} from './animations/SpringAnimation'; -import type {Mapping, EventConfig} from './AnimatedEvent'; +import type {TimingAnimationConfig} from './animations/TimingAnimation'; +import {AnimatedEvent, attachNativeEvent} from './AnimatedEvent'; +import DecayAnimation from './animations/DecayAnimation'; +import SpringAnimation from './animations/SpringAnimation'; +import TimingAnimation from './animations/TimingAnimation'; +import createAnimatedComponent from './createAnimatedComponent'; +import AnimatedAddition from './nodes/AnimatedAddition'; import AnimatedColor from './nodes/AnimatedColor'; +import AnimatedDiffClamp from './nodes/AnimatedDiffClamp'; +import AnimatedDivision from './nodes/AnimatedDivision'; +import AnimatedInterpolation from './nodes/AnimatedInterpolation'; +import AnimatedModulo from './nodes/AnimatedModulo'; +import AnimatedMultiplication from './nodes/AnimatedMultiplication'; +import AnimatedNode from './nodes/AnimatedNode'; +import AnimatedSubtraction from './nodes/AnimatedSubtraction'; +import AnimatedTracking from './nodes/AnimatedTracking'; +import AnimatedValue from './nodes/AnimatedValue'; +import AnimatedValueXY from './nodes/AnimatedValueXY'; export type CompositeAnimation = { start: (callback?: ?EndCallback) => void, @@ -91,10 +89,10 @@ const diffClamp = function ( const _combineCallbacks = function ( callback: ?EndCallback, - config: {...AnimationConfig, ...}, + config: $ReadOnly<{...AnimationConfig, ...}>, ) { if (callback && config.onComplete) { - return (...args) => { + return (...args: Array) => { config.onComplete && config.onComplete(...args); callback && callback(...args); }; @@ -308,7 +306,7 @@ const sequence = function ( let current = 0; return { start: function (callback?: ?EndCallback) { - const onComplete = function (result) { + const onComplete = function (result: EndResult) { if (!result.finished) { callback && callback(result); return; @@ -369,7 +367,7 @@ const parallel = function ( ): CompositeAnimation { let doneCount = 0; // Make sure we only call stop() at most once for each animation - const hasEnded = {}; + const hasEnded: {[number]: boolean} = {}; const stopTogether = !(config && config.stopTogether === false); const result = { @@ -380,7 +378,7 @@ const parallel = function ( } animations.forEach((animation, idx) => { - const cb = function (endResult) { + const cb = function (endResult: EndResult | {finished: boolean}) { hasEnded[idx] = true; doneCount++; if (doneCount === animations.length) { @@ -417,7 +415,7 @@ const parallel = function ( }); }, - _startNativeLoop: function () { + _startNativeLoop: function (): empty { throw new Error( 'Loops run using the native driver cannot contain Animated.parallel animations', ); @@ -460,6 +458,7 @@ type LoopAnimationConfig = { const loop = function ( animation: CompositeAnimation, + // $FlowFixMe[prop-missing] {iterations = -1, resetBeforeIteration = true}: LoopAnimationConfig = {}, ): CompositeAnimation { let isFinished = false; @@ -551,6 +550,19 @@ const event = function ( } }; +// All types of animated nodes that represent scalar numbers and can be interpolated (etc) +type AnimatedNumeric = + | AnimatedAddition + | AnimatedDiffClamp + | AnimatedDivision + | AnimatedInterpolation + | AnimatedModulo + | AnimatedMultiplication + | AnimatedSubtraction + | AnimatedValue; + +export type {AnimatedNumeric as Numeric}; + /** * The `Animated` library is designed to make animations fluid, powerful, and * easy to build and maintain. `Animated` focuses on declarative relationships @@ -561,7 +573,7 @@ const event = function ( * * See https://reactnative.dev/docs/animated */ -module.exports = { +export default { /** * Standard value class for driving animations. Typically initialized with * `new Animated.Value(0);` diff --git a/Libraries/Animated/AnimatedMock.js b/Libraries/Animated/AnimatedMock.js index ee9241514a70ba..790a41658e1678 100644 --- a/Libraries/Animated/AnimatedMock.js +++ b/Libraries/Animated/AnimatedMock.js @@ -10,21 +10,21 @@ 'use strict'; -const {AnimatedEvent, attachNativeEvent} = require('./AnimatedEvent'); -const AnimatedImplementation = require('./AnimatedImplementation'); -const AnimatedInterpolation = require('./nodes/AnimatedInterpolation'); -const AnimatedNode = require('./nodes/AnimatedNode'); -const AnimatedValue = require('./nodes/AnimatedValue'); -const AnimatedValueXY = require('./nodes/AnimatedValueXY'); - -const createAnimatedComponent = require('./createAnimatedComponent'); - +import type {Numeric as AnimatedNumeric} from './AnimatedImplementation'; +import type {EndResult} from './animations/Animation'; import type {EndCallback} from './animations/Animation'; -import type {TimingAnimationConfig} from './animations/TimingAnimation'; import type {DecayAnimationConfig} from './animations/DecayAnimation'; import type {SpringAnimationConfig} from './animations/SpringAnimation'; +import type {TimingAnimationConfig} from './animations/TimingAnimation'; +import {AnimatedEvent, attachNativeEvent} from './AnimatedEvent'; +import AnimatedImplementation from './AnimatedImplementation'; +import createAnimatedComponent from './createAnimatedComponent'; import AnimatedColor from './nodes/AnimatedColor'; +import AnimatedInterpolation from './nodes/AnimatedInterpolation'; +import AnimatedNode from './nodes/AnimatedNode'; +import AnimatedValue from './nodes/AnimatedValue'; +import AnimatedValueXY from './nodes/AnimatedValueXY'; /** * Animations are a source of flakiness in snapshot testing. This mock replaces @@ -43,7 +43,7 @@ function mockAnimationStart( const guardedCallback = callback == null ? callback - : (...args) => { + : (...args: Array) => { if (inAnimationCallback) { console.warn( 'Ignoring recursive animation callback when running mock animations', @@ -164,12 +164,15 @@ type LoopAnimationConfig = { const loop = function ( animation: CompositeAnimation, + // $FlowFixMe[prop-missing] {iterations = -1}: LoopAnimationConfig = {}, ): CompositeAnimation { return emptyAnimation; }; -module.exports = { +export type {AnimatedNumeric as Numeric}; + +export default { Value: AnimatedValue, ValueXY: AnimatedValueXY, Color: AnimatedColor, diff --git a/Libraries/Animated/AnimatedWeb.js b/Libraries/Animated/AnimatedWeb.js index e1c016b753241b..e23a04587a7061 100644 --- a/Libraries/Animated/AnimatedWeb.js +++ b/Libraries/Animated/AnimatedWeb.js @@ -10,9 +10,9 @@ 'use strict'; -const AnimatedImplementation = require('./AnimatedImplementation'); +import AnimatedImplementation from './AnimatedImplementation'; -module.exports = { +export default { ...AnimatedImplementation, /* $FlowFixMe[incompatible-call] createAnimatedComponent expects to receive * types. Plain intrinsic components can't be typed like this */ diff --git a/Libraries/Animated/Easing.d.ts b/Libraries/Animated/Easing.d.ts new file mode 100644 index 00000000000000..bb496f0cd77643 --- /dev/null +++ b/Libraries/Animated/Easing.d.ts @@ -0,0 +1,37 @@ +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @format + */ + +/** + * This class implements common easing functions. The math is pretty obscure, + * but this cool website has nice visual illustrations of what they represent: + * http://xaedes.de/dev/transitions/ + */ +export type EasingFunction = (value: number) => number; +export interface EasingStatic { + step0: EasingFunction; + step1: EasingFunction; + linear: EasingFunction; + ease: EasingFunction; + quad: EasingFunction; + cubic: EasingFunction; + poly(n: number): EasingFunction; + sin: EasingFunction; + circle: EasingFunction; + exp: EasingFunction; + elastic(bounciness: number): EasingFunction; + back(s: number): EasingFunction; + bounce: EasingFunction; + bezier(x1: number, y1: number, x2: number, y2: number): EasingFunction; + in(easing: EasingFunction): EasingFunction; + out(easing: EasingFunction): EasingFunction; + inOut(easing: EasingFunction): EasingFunction; +} + +export type Easing = EasingStatic; +export const Easing: EasingStatic; diff --git a/Libraries/Animated/Easing.js b/Libraries/Animated/Easing.js index f8b5bac2f30404..32819708a11d6b 100644 --- a/Libraries/Animated/Easing.js +++ b/Libraries/Animated/Easing.js @@ -214,7 +214,7 @@ const Easing = { x2: number, y2: number, ): (t: number) => number { - const _bezier = require('./bezier'); + const _bezier = require('./bezier').default; return _bezier(x1, y1, x2, y2); }, @@ -247,4 +247,4 @@ const Easing = { }, }; -module.exports = Easing; +export default Easing; diff --git a/Libraries/Animated/NativeAnimatedHelper.js b/Libraries/Animated/NativeAnimatedHelper.js index 3ceb741daef06c..c71e88101377c4 100644 --- a/Libraries/Animated/NativeAnimatedHelper.js +++ b/Libraries/Animated/NativeAnimatedHelper.js @@ -8,18 +8,22 @@ * @format */ -import NativeAnimatedNonTurboModule from './NativeAnimatedModule'; -import NativeAnimatedTurboModule from './NativeAnimatedTurboModule'; -import NativeEventEmitter from '../EventEmitter/NativeEventEmitter'; -import Platform from '../Utilities/Platform'; +import type {EventSubscription} from '../vendor/emitter/EventEmitter'; import type {EventConfig} from './AnimatedEvent'; +import type {AnimationConfig, EndCallback} from './animations/Animation'; import type { - EventMapping, AnimatedNodeConfig, AnimatingNodeConfig, + EventMapping, } from './NativeAnimatedModule'; -import type {AnimationConfig, EndCallback} from './animations/Animation'; import type {InterpolationConfigType} from './nodes/AnimatedInterpolation'; + +import NativeEventEmitter from '../EventEmitter/NativeEventEmitter'; +import RCTDeviceEventEmitter from '../EventEmitter/RCTDeviceEventEmitter'; +import ReactNativeFeatureFlags from '../ReactNative/ReactNativeFeatureFlags'; +import Platform from '../Utilities/Platform'; +import NativeAnimatedNonTurboModule from './NativeAnimatedModule'; +import NativeAnimatedTurboModule from './NativeAnimatedTurboModule'; import invariant from 'invariant'; // TODO T69437152 @petetheheat - Delete this fork when Fabric ships to 100%. @@ -33,27 +37,90 @@ let __nativeAnimationIdCount = 1; /* used for started animations */ let nativeEventEmitter; -let waitingForQueuedOperations = new Set(); +let waitingForQueuedOperations = new Set(); let queueOperations = false; let queue: Array<() => void> = []; +// $FlowFixMe +let singleOpQueue: Array = []; + +const useSingleOpBatching = + Platform.OS === 'android' && + !!NativeAnimatedModule?.queueAndExecuteBatchedOperations && + ReactNativeFeatureFlags.animatedShouldUseSingleOp(); +let flushQueueTimeout = null; + +const eventListenerGetValueCallbacks: { + [$FlowFixMe | number]: ((value: number) => void) | void, +} = {}; +const eventListenerAnimationFinishedCallbacks: { + [$FlowFixMe | number]: EndCallback | void, +} = {}; +let globalEventEmitterGetValueListener: ?EventSubscription = null; +let globalEventEmitterAnimationFinishedListener: ?EventSubscription = null; + +const nativeOps: ?typeof NativeAnimatedModule = useSingleOpBatching + ? ((function () { + const apis = [ + 'createAnimatedNode', // 1 + 'updateAnimatedNodeConfig', // 2 + 'getValue', // 3 + 'startListeningToAnimatedNodeValue', // 4 + 'stopListeningToAnimatedNodeValue', // 5 + 'connectAnimatedNodes', // 6 + 'disconnectAnimatedNodes', // 7 + 'startAnimatingNode', // 8 + 'stopAnimation', // 9 + 'setAnimatedNodeValue', // 10 + 'setAnimatedNodeOffset', // 11 + 'flattenAnimatedNodeOffset', // 12 + 'extractAnimatedNodeOffset', // 13 + 'connectAnimatedNodeToView', // 14 + 'disconnectAnimatedNodeFromView', // 15 + 'restoreDefaultValues', // 16 + 'dropAnimatedNode', // 17 + 'addAnimatedEventToView', // 18 + 'removeAnimatedEventFromView', // 19 + 'addListener', // 20 + 'removeListener', // 21 + ]; + return apis.reduce<{[string]: number}>((acc, functionName, i) => { + // These indices need to be kept in sync with the indices in native (see NativeAnimatedModule in Java, or the equivalent for any other native platform). + // $FlowFixMe[prop-missing] + acc[functionName] = i + 1; + return acc; + }, {}); + })(): $FlowFixMe) + : NativeAnimatedModule; /** - * Simple wrappers around NativeAnimatedModule to provide flow and autocomplete support for - * the native module methods + * Wrappers around NativeAnimatedModule to provide flow and autocomplete support for + * the native module methods, and automatic queue management on Android */ const API = { getValue: function ( tag: number, saveValueCallback: (value: number) => void, ): void { - invariant(NativeAnimatedModule, 'Native animated module is not available'); - API.queueOperation(() => { - NativeAnimatedModule.getValue(tag, saveValueCallback); - }); + invariant(nativeOps, 'Native animated module is not available'); + if (useSingleOpBatching) { + if (saveValueCallback) { + eventListenerGetValueCallbacks[tag] = saveValueCallback; + } + // $FlowFixMe + API.queueOperation(nativeOps.getValue, tag); + } else { + API.queueOperation(nativeOps.getValue, tag, saveValueCallback); + } }, setWaitingForIdentifier: function (id: string): void { waitingForQueuedOperations.add(id); queueOperations = true; + if ( + ReactNativeFeatureFlags.animatedShouldDebounceQueueFlush() && + flushQueueTimeout + ) { + clearTimeout(flushQueueTimeout); + } }, unsetWaitingForIdentifier: function (id: string): void { waitingForQueuedOperations.delete(id); @@ -64,70 +131,103 @@ const API = { } }, disableQueue: function (): void { + invariant(nativeOps, 'Native animated module is not available'); + + if (ReactNativeFeatureFlags.animatedShouldDebounceQueueFlush()) { + const prevTimeout = flushQueueTimeout; + clearImmediate(prevTimeout); + flushQueueTimeout = setImmediate(API.flushQueue); + } else { + API.flushQueue(); + } + }, + flushQueue: function (): void { invariant(NativeAnimatedModule, 'Native animated module is not available'); + flushQueueTimeout = null; - if (Platform.OS === 'android') { - NativeAnimatedModule.startOperationBatch(); + // Early returns before calling any APIs + if (useSingleOpBatching && singleOpQueue.length === 0) { + return; } - for (let q = 0, l = queue.length; q < l; q++) { - queue[q](); + if (!useSingleOpBatching && queue.length === 0) { + return; } - queue.length = 0; - if (Platform.OS === 'android') { - NativeAnimatedModule.finishOperationBatch(); + + if (useSingleOpBatching) { + // Set up event listener for callbacks if it's not set up + if ( + !globalEventEmitterGetValueListener || + !globalEventEmitterAnimationFinishedListener + ) { + setupGlobalEventEmitterListeners(); + } + // Single op batching doesn't use callback functions, instead we + // use RCTDeviceEventEmitter. This reduces overhead of sending lots of + // JSI functions across to native code; but also, TM infrastructure currently + // does not support packing a function into native arrays. + NativeAnimatedModule.queueAndExecuteBatchedOperations?.(singleOpQueue); + singleOpQueue.length = 0; + } else { + Platform.OS === 'android' && NativeAnimatedModule.startOperationBatch?.(); + for (let q = 0, l = queue.length; q < l; q++) { + queue[q](); + } + queue.length = 0; + Platform.OS === 'android' && + NativeAnimatedModule.finishOperationBatch?.(); } }, - queueOperation: (fn: () => void): void => { - if (queueOperations) { - queue.push(fn); + queueOperation: , Fn: (...Args) => void>( + fn: Fn, + ...args: Args + ): void => { + if (useSingleOpBatching) { + // Get the command ID from the queued function, and push that ID and any arguments needed to execute the operation + // $FlowFixMe: surprise, fn is actually a number + singleOpQueue.push(fn, ...args); + return; + } + + // If queueing is explicitly on, *or* the queue has not yet + // been flushed, use the queue. This is to prevent operations + // from being executed out of order. + if (queueOperations || queue.length !== 0) { + queue.push(() => fn(...args)); } else { - fn(); + fn(...args); } }, createAnimatedNode: function (tag: number, config: AnimatedNodeConfig): void { - invariant(NativeAnimatedModule, 'Native animated module is not available'); - API.queueOperation(() => - NativeAnimatedModule.createAnimatedNode(tag, config), - ); + invariant(nativeOps, 'Native animated module is not available'); + API.queueOperation(nativeOps.createAnimatedNode, tag, config); }, updateAnimatedNodeConfig: function ( tag: number, config: AnimatedNodeConfig, ): void { - invariant(NativeAnimatedModule, 'Native animated module is not available'); - if (typeof NativeAnimatedModule.updateAnimatedNodeConfig === 'function') { - API.queueOperation(() => - // $FlowIgnore[not-a-function] - checked above - NativeAnimatedModule.updateAnimatedNodeConfig(tag, config), - ); + invariant(nativeOps, 'Native animated module is not available'); + if (nativeOps.updateAnimatedNodeConfig) { + API.queueOperation(nativeOps.updateAnimatedNodeConfig, tag, config); } }, startListeningToAnimatedNodeValue: function (tag: number) { - invariant(NativeAnimatedModule, 'Native animated module is not available'); - API.queueOperation(() => - NativeAnimatedModule.startListeningToAnimatedNodeValue(tag), - ); + invariant(nativeOps, 'Native animated module is not available'); + API.queueOperation(nativeOps.startListeningToAnimatedNodeValue, tag); }, stopListeningToAnimatedNodeValue: function (tag: number) { - invariant(NativeAnimatedModule, 'Native animated module is not available'); - API.queueOperation(() => - NativeAnimatedModule.stopListeningToAnimatedNodeValue(tag), - ); + invariant(nativeOps, 'Native animated module is not available'); + API.queueOperation(nativeOps.stopListeningToAnimatedNodeValue, tag); }, connectAnimatedNodes: function (parentTag: number, childTag: number): void { - invariant(NativeAnimatedModule, 'Native animated module is not available'); - API.queueOperation(() => - NativeAnimatedModule.connectAnimatedNodes(parentTag, childTag), - ); + invariant(nativeOps, 'Native animated module is not available'); + API.queueOperation(nativeOps.connectAnimatedNodes, parentTag, childTag); }, disconnectAnimatedNodes: function ( parentTag: number, childTag: number, ): void { - invariant(NativeAnimatedModule, 'Native animated module is not available'); - API.queueOperation(() => - NativeAnimatedModule.disconnectAnimatedNodes(parentTag, childTag), - ); + invariant(nativeOps, 'Native animated module is not available'); + API.queueOperation(nativeOps.disconnectAnimatedNodes, parentTag, childTag); }, startAnimatingNode: function ( animationId: number, @@ -135,84 +235,85 @@ const API = { config: AnimatingNodeConfig, endCallback: EndCallback, ): void { - invariant(NativeAnimatedModule, 'Native animated module is not available'); - API.queueOperation(() => - NativeAnimatedModule.startAnimatingNode( + invariant(nativeOps, 'Native animated module is not available'); + if (useSingleOpBatching) { + if (endCallback) { + eventListenerAnimationFinishedCallbacks[animationId] = endCallback; + } + // $FlowFixMe + API.queueOperation( + nativeOps.startAnimatingNode, + animationId, + nodeTag, + config, + ); + } else { + API.queueOperation( + nativeOps.startAnimatingNode, animationId, nodeTag, config, endCallback, - ), - ); + ); + } }, stopAnimation: function (animationId: number) { - invariant(NativeAnimatedModule, 'Native animated module is not available'); - API.queueOperation(() => NativeAnimatedModule.stopAnimation(animationId)); + invariant(nativeOps, 'Native animated module is not available'); + API.queueOperation(nativeOps.stopAnimation, animationId); }, setAnimatedNodeValue: function (nodeTag: number, value: number): void { - invariant(NativeAnimatedModule, 'Native animated module is not available'); - API.queueOperation(() => - NativeAnimatedModule.setAnimatedNodeValue(nodeTag, value), - ); + invariant(nativeOps, 'Native animated module is not available'); + API.queueOperation(nativeOps.setAnimatedNodeValue, nodeTag, value); }, setAnimatedNodeOffset: function (nodeTag: number, offset: number): void { - invariant(NativeAnimatedModule, 'Native animated module is not available'); - API.queueOperation(() => - NativeAnimatedModule.setAnimatedNodeOffset(nodeTag, offset), - ); + invariant(nativeOps, 'Native animated module is not available'); + API.queueOperation(nativeOps.setAnimatedNodeOffset, nodeTag, offset); }, flattenAnimatedNodeOffset: function (nodeTag: number): void { - invariant(NativeAnimatedModule, 'Native animated module is not available'); - API.queueOperation(() => - NativeAnimatedModule.flattenAnimatedNodeOffset(nodeTag), - ); + invariant(nativeOps, 'Native animated module is not available'); + API.queueOperation(nativeOps.flattenAnimatedNodeOffset, nodeTag); }, extractAnimatedNodeOffset: function (nodeTag: number): void { - invariant(NativeAnimatedModule, 'Native animated module is not available'); - API.queueOperation(() => - NativeAnimatedModule.extractAnimatedNodeOffset(nodeTag), - ); + invariant(nativeOps, 'Native animated module is not available'); + API.queueOperation(nativeOps.extractAnimatedNodeOffset, nodeTag); }, connectAnimatedNodeToView: function (nodeTag: number, viewTag: number): void { - invariant(NativeAnimatedModule, 'Native animated module is not available'); - API.queueOperation(() => - NativeAnimatedModule.connectAnimatedNodeToView(nodeTag, viewTag), - ); + invariant(nativeOps, 'Native animated module is not available'); + API.queueOperation(nativeOps.connectAnimatedNodeToView, nodeTag, viewTag); }, disconnectAnimatedNodeFromView: function ( nodeTag: number, viewTag: number, ): void { - invariant(NativeAnimatedModule, 'Native animated module is not available'); - API.queueOperation(() => - NativeAnimatedModule.disconnectAnimatedNodeFromView(nodeTag, viewTag), + invariant(nativeOps, 'Native animated module is not available'); + API.queueOperation( + nativeOps.disconnectAnimatedNodeFromView, + nodeTag, + viewTag, ); }, restoreDefaultValues: function (nodeTag: number): void { - invariant(NativeAnimatedModule, 'Native animated module is not available'); + invariant(nativeOps, 'Native animated module is not available'); // Backwards compat with older native runtimes, can be removed later. - if (NativeAnimatedModule.restoreDefaultValues != null) { - API.queueOperation(() => - NativeAnimatedModule.restoreDefaultValues(nodeTag), - ); + if (nativeOps.restoreDefaultValues != null) { + API.queueOperation(nativeOps.restoreDefaultValues, nodeTag); } }, dropAnimatedNode: function (tag: number): void { - invariant(NativeAnimatedModule, 'Native animated module is not available'); - API.queueOperation(() => NativeAnimatedModule.dropAnimatedNode(tag)); + invariant(nativeOps, 'Native animated module is not available'); + API.queueOperation(nativeOps.dropAnimatedNode, tag); }, addAnimatedEventToView: function ( viewTag: number, eventName: string, eventMapping: EventMapping, ) { - invariant(NativeAnimatedModule, 'Native animated module is not available'); - API.queueOperation(() => - NativeAnimatedModule.addAnimatedEventToView( - viewTag, - eventName, - eventMapping, - ), + invariant(nativeOps, 'Native animated module is not available'); + API.queueOperation( + nativeOps.addAnimatedEventToView, + viewTag, + eventName, + eventMapping, ); }, removeAnimatedEventFromView( @@ -220,36 +321,77 @@ const API = { eventName: string, animatedNodeTag: number, ) { - invariant(NativeAnimatedModule, 'Native animated module is not available'); - API.queueOperation(() => - NativeAnimatedModule.removeAnimatedEventFromView( - viewTag, - eventName, - animatedNodeTag, - ), + invariant(nativeOps, 'Native animated module is not available'); + API.queueOperation( + nativeOps.removeAnimatedEventFromView, + viewTag, + eventName, + animatedNodeTag, ); }, }; +function setupGlobalEventEmitterListeners() { + globalEventEmitterGetValueListener = RCTDeviceEventEmitter.addListener( + 'onNativeAnimatedModuleGetValue', + function (params) { + const {tag} = params; + const callback = eventListenerGetValueCallbacks[tag]; + if (!callback) { + return; + } + callback(params.value); + delete eventListenerGetValueCallbacks[tag]; + }, + ); + globalEventEmitterAnimationFinishedListener = + RCTDeviceEventEmitter.addListener( + 'onNativeAnimatedModuleAnimationFinished', + function (params) { + const {animationId} = params; + const callback = eventListenerAnimationFinishedCallbacks[animationId]; + if (!callback) { + return; + } + callback(params); + delete eventListenerAnimationFinishedCallbacks[animationId]; + }, + ); +} + /** * Styles allowed by the native animated implementation. * - * In general native animated implementation should support any numeric property that doesn't need - * to be updated through the shadow view hierarchy (all non-layout properties). + * In general native animated implementation should support any numeric or color property that + * doesn't need to be updated through the shadow view hierarchy (all non-layout properties). */ +const SUPPORTED_COLOR_STYLES = { + backgroundColor: true, + borderBottomColor: true, + borderColor: true, + borderEndColor: true, + borderLeftColor: true, + borderRightColor: true, + borderStartColor: true, + borderTopColor: true, + color: true, + tintColor: true, +}; + const SUPPORTED_STYLES = { - opacity: true, - transform: true, - borderRadius: true, + ...SUPPORTED_COLOR_STYLES, borderBottomEndRadius: true, borderBottomLeftRadius: true, borderBottomRightRadius: true, borderBottomStartRadius: true, + borderRadius: true, borderTopEndRadius: true, borderTopLeftRadius: true, borderTopRightRadius: true, borderTopStartRadius: true, elevation: true, + opacity: true, + transform: true, zIndex: true, /* ios styles */ shadowOpacity: true, @@ -283,17 +425,36 @@ const SUPPORTED_INTERPOLATION_PARAMS = { }; function addWhitelistedStyleProp(prop: string): void { + // $FlowFixMe[prop-missing] SUPPORTED_STYLES[prop] = true; } function addWhitelistedTransformProp(prop: string): void { + // $FlowFixMe[prop-missing] SUPPORTED_TRANSFORMS[prop] = true; } function addWhitelistedInterpolationParam(param: string): void { + // $FlowFixMe[prop-missing] SUPPORTED_INTERPOLATION_PARAMS[param] = true; } +function isSupportedColorStyleProp(prop: string): boolean { + return SUPPORTED_COLOR_STYLES.hasOwnProperty(prop); +} + +function isSupportedStyleProp(prop: string): boolean { + return SUPPORTED_STYLES.hasOwnProperty(prop); +} + +function isSupportedTransformProp(prop: string): boolean { + return SUPPORTED_TRANSFORMS.hasOwnProperty(prop); +} + +function isSupportedInterpolationParam(param: string): boolean { + return SUPPORTED_INTERPOLATION_PARAMS.hasOwnProperty(param); +} + function validateTransform( configs: Array< | { @@ -311,7 +472,7 @@ function validateTransform( >, ): void { configs.forEach(config => { - if (!SUPPORTED_TRANSFORMS.hasOwnProperty(config.property)) { + if (!isSupportedTransformProp(config.property)) { throw new Error( `Property '${config.property}' is not supported by native animated module`, ); @@ -321,7 +482,7 @@ function validateTransform( function validateStyles(styles: {[key: string]: ?number, ...}): void { for (const key in styles) { - if (!SUPPORTED_STYLES.hasOwnProperty(key)) { + if (!isSupportedStyleProp(key)) { throw new Error( `Style property '${key}' is not supported by native animated module`, ); @@ -329,9 +490,11 @@ function validateStyles(styles: {[key: string]: ?number, ...}): void { } } -function validateInterpolation(config: InterpolationConfigType): void { +function validateInterpolation( + config: InterpolationConfigType, +): void { for (const key in config) { - if (!SUPPORTED_INTERPOLATION_PARAMS.hasOwnProperty(key)) { + if (!isSupportedInterpolationParam(key)) { throw new Error( `Interpolation property '${key}' is not supported by native animated module`, ); @@ -354,7 +517,7 @@ function assertNativeAnimatedModule(): void { let _warnedMissingNativeAnimated = false; function shouldUseNativeDriver( - config: {...AnimationConfig, ...} | EventConfig, + config: $ReadOnly<{...AnimationConfig, ...}> | EventConfig, ): boolean { if (config.useNativeDriver == null) { console.warn( @@ -364,15 +527,17 @@ function shouldUseNativeDriver( } if (config.useNativeDriver === true && !NativeAnimatedModule) { - if (!_warnedMissingNativeAnimated) { - console.warn( - 'Animated: `useNativeDriver` is not supported because the native ' + - 'animated module is missing. Falling back to JS-based animation. To ' + - 'resolve this, add `RCTAnimation` module to this app, or remove ' + - '`useNativeDriver`. ' + - 'Make sure to run `bundle exec pod install` first. Read more about autolinking: https://github.com/react-native-community/cli/blob/master/docs/autolinking.md', - ); - _warnedMissingNativeAnimated = true; + if (process.env.NODE_ENV !== 'test') { + if (!_warnedMissingNativeAnimated) { + console.warn( + 'Animated: `useNativeDriver` is not supported because the native ' + + 'animated module is missing. Falling back to JS-based animation. To ' + + 'resolve this, add `RCTAnimation` module to this app, or remove ' + + '`useNativeDriver`. ' + + 'Make sure to run `bundle exec pod install` first. Read more about autolinking: https://github.com/react-native-community/cli/blob/master/docs/autolinking.md', + ); + _warnedMissingNativeAnimated = true; + } } return false; } @@ -395,8 +560,12 @@ function transformDataType(value: number | string): number | string { } } -module.exports = { +export default { API, + isSupportedColorStyleProp, + isSupportedStyleProp, + isSupportedTransformProp, + isSupportedInterpolationParam, addWhitelistedStyleProp, addWhitelistedTransformProp, addWhitelistedInterpolationParam, diff --git a/Libraries/Animated/NativeAnimatedModule.js b/Libraries/Animated/NativeAnimatedModule.js index 39ffb002f85888..9fc932e6b509cc 100644 --- a/Libraries/Animated/NativeAnimatedModule.js +++ b/Libraries/Animated/NativeAnimatedModule.js @@ -9,6 +9,7 @@ */ import type {TurboModule} from '../TurboModule/RCTExport'; + import * as TurboModuleRegistry from '../TurboModule/TurboModuleRegistry'; type EndResult = {finished: boolean, ...}; @@ -64,6 +65,9 @@ export interface Spec extends TurboModule { // Events +addListener: (eventName: string) => void; +removeListeners: (count: number) => void; + + // All of the above in a batched mode + +queueAndExecuteBatchedOperations?: (operationsAndArgs: Array) => void; } export default (TurboModuleRegistry.get('NativeAnimatedModule'): ?Spec); diff --git a/Libraries/Animated/NativeAnimatedTurboModule.js b/Libraries/Animated/NativeAnimatedTurboModule.js index 7c0fbe8f8e2c93..58664ca8742173 100644 --- a/Libraries/Animated/NativeAnimatedTurboModule.js +++ b/Libraries/Animated/NativeAnimatedTurboModule.js @@ -9,6 +9,7 @@ */ import type {TurboModule} from '../TurboModule/RCTExport'; + import * as TurboModuleRegistry from '../TurboModule/TurboModuleRegistry'; type EndResult = {finished: boolean, ...}; @@ -64,6 +65,9 @@ export interface Spec extends TurboModule { // Events +addListener: (eventName: string) => void; +removeListeners: (count: number) => void; + + // All of the above in a batched mode + +queueAndExecuteBatchedOperations?: (operationsAndArgs: Array) => void; } export default (TurboModuleRegistry.get( diff --git a/Libraries/Animated/SpringConfig.js b/Libraries/Animated/SpringConfig.js index c687f6b97126eb..2ed616eb87e671 100644 --- a/Libraries/Animated/SpringConfig.js +++ b/Libraries/Animated/SpringConfig.js @@ -24,7 +24,7 @@ function dampingFromOrigamiValue(oValue: number) { return (oValue - 8) * 3 + 25; } -function fromOrigamiTensionAndFriction( +export function fromOrigamiTensionAndFriction( tension: number, friction: number, ): SpringConfigType { @@ -34,7 +34,7 @@ function fromOrigamiTensionAndFriction( }; } -function fromBouncinessAndSpeed( +export function fromBouncinessAndSpeed( bounciness: number, speed: number, ): SpringConfigType { @@ -96,8 +96,3 @@ function fromBouncinessAndSpeed( damping: dampingFromOrigamiValue(bouncyFriction), }; } - -module.exports = { - fromOrigamiTensionAndFriction, - fromBouncinessAndSpeed, -}; diff --git a/Libraries/Animated/__tests__/Animated-test.js b/Libraries/Animated/__tests__/Animated-test.js index 8f62804c73b781..698dee83e9994a 100644 --- a/Libraries/Animated/__tests__/Animated-test.js +++ b/Libraries/Animated/__tests__/Animated-test.js @@ -5,12 +5,14 @@ * LICENSE file in the root directory of this source tree. * * @format - * @emails oncall+react_native + * @oncall react_native */ -import AnimatedProps from '../nodes/AnimatedProps'; -import TestRenderer from 'react-test-renderer'; import * as React from 'react'; +import TestRenderer from 'react-test-renderer'; + +let Animated = require('../Animated').default; +let AnimatedProps = require('../nodes/AnimatedProps').default; jest.mock('../../BatchedBridge/NativeModules', () => ({ NativeAnimatedModule: {}, @@ -21,8 +23,6 @@ jest.mock('../../BatchedBridge/NativeModules', () => ({ }, })); -let Animated = require('../Animated'); - describe('Animated tests', () => { beforeEach(() => { jest.resetModules(); @@ -31,6 +31,10 @@ describe('Animated tests', () => { describe('Animated', () => { it('works end to end', () => { const anim = new Animated.Value(0); + const translateAnim = anim.interpolate({ + inputRange: [0, 1], + outputRange: [100, 200], + }); const callback = jest.fn(); @@ -41,10 +45,10 @@ describe('Animated tests', () => { opacity: anim, transform: [ { - translateX: anim.interpolate({ - inputRange: [0, 1], - outputRange: [100, 200], - }), + translate: [translateAnim, translateAnim], + }, + { + translateX: translateAnim, }, {scale: anim}, ], @@ -61,7 +65,7 @@ describe('Animated tests', () => { style: { backgroundColor: 'red', opacity: 0, - transform: [{translateX: 100}, {scale: 0}], + transform: [{translate: [100, 100]}, {translateX: 100}, {scale: 0}], shadowOffset: { width: 0, height: 0, @@ -83,7 +87,7 @@ describe('Animated tests', () => { style: { backgroundColor: 'red', opacity: 0.5, - transform: [{translateX: 150}, {scale: 0.5}], + transform: [{translate: [150, 150]}, {translateX: 150}, {scale: 0.5}], shadowOffset: { width: 0.5, height: 0.5, @@ -692,7 +696,7 @@ describe('Animated tests', () => { beforeEach(() => { jest.mock('../../Interaction/InteractionManager'); - Animated = require('../Animated'); + Animated = require('../Animated').default; InteractionManager = require('../../Interaction/InteractionManager'); }); diff --git a/Libraries/Animated/__tests__/AnimatedMock-test.js b/Libraries/Animated/__tests__/AnimatedMock-test.js index cc510feefefb33..d08a5ecc38f72e 100644 --- a/Libraries/Animated/__tests__/AnimatedMock-test.js +++ b/Libraries/Animated/__tests__/AnimatedMock-test.js @@ -5,13 +5,13 @@ * LICENSE file in the root directory of this source tree. * * @format - * @emails oncall+react_native + * @oncall react_native */ 'use strict'; -const AnimatedMock = require('../AnimatedMock'); -const AnimatedImplementation = require('../AnimatedImplementation'); +import AnimatedImplementation from '../AnimatedImplementation'; +import AnimatedMock from '../AnimatedMock'; describe('Animated Mock', () => { it('matches implementation keys', () => { diff --git a/Libraries/Animated/__tests__/AnimatedNative-test.js b/Libraries/Animated/__tests__/AnimatedNative-test.js index 677527e22c9d15..2f7b10af052629 100644 --- a/Libraries/Animated/__tests__/AnimatedNative-test.js +++ b/Libraries/Animated/__tests__/AnimatedNative-test.js @@ -5,7 +5,7 @@ * LICENSE file in the root directory of this source tree. * * @format - * @emails oncall+react_native + * @oncall react_native */ jest @@ -20,14 +20,14 @@ jest })) .mock('../NativeAnimatedModule') .mock('../../EventEmitter/NativeEventEmitter') - // findNodeHandle is imported from ReactNative so mock that whole module. - .setMock('../../Renderer/shims/ReactNative', {findNodeHandle: () => 1}); + // findNodeHandle is imported from RendererProxy so mock that whole module. + .setMock('../../ReactNative/RendererProxy', {findNodeHandle: () => 1}); -import TestRenderer from 'react-test-renderer'; import * as React from 'react'; +import TestRenderer from 'react-test-renderer'; -const Animated = require('../Animated'); -const NativeAnimatedHelper = require('../NativeAnimatedHelper'); +const Animated = require('../Animated').default; +const NativeAnimatedHelper = require('../NativeAnimatedHelper').default; describe('Native Animated', () => { const NativeAnimatedModule = require('../NativeAnimatedModule').default; diff --git a/Libraries/Animated/__tests__/Easing-test.js b/Libraries/Animated/__tests__/Easing-test.js index 8efeed00037d74..1447c0c60edd0e 100644 --- a/Libraries/Animated/__tests__/Easing-test.js +++ b/Libraries/Animated/__tests__/Easing-test.js @@ -5,12 +5,12 @@ * LICENSE file in the root directory of this source tree. * * @format - * @emails oncall+react_native + * @oncall react_native */ 'use strict'; -const Easing = require('../Easing'); +import Easing from '../Easing'; describe('Easing', () => { it('should work with linear', () => { const easing = Easing.linear; diff --git a/Libraries/Animated/__tests__/Interpolation-test.js b/Libraries/Animated/__tests__/Interpolation-test.js index 64585ac683bd9a..2893cdd39399ba 100644 --- a/Libraries/Animated/__tests__/Interpolation-test.js +++ b/Libraries/Animated/__tests__/Interpolation-test.js @@ -5,13 +5,13 @@ * LICENSE file in the root directory of this source tree. * * @format - * @emails oncall+react_native + * @oncall react_native */ 'use strict'; -const AnimatedInterpolation = require('../nodes/AnimatedInterpolation'); -const Easing = require('../Easing'); +import Easing from '../Easing'; +import AnimatedInterpolation from '../nodes/AnimatedInterpolation'; describe('Interpolation', () => { it('should work with defaults', () => { diff --git a/Libraries/Animated/__tests__/TimingAnimation-test.js b/Libraries/Animated/__tests__/TimingAnimation-test.js index e82407876a2d9c..b05a2ff3c76efe 100644 --- a/Libraries/Animated/__tests__/TimingAnimation-test.js +++ b/Libraries/Animated/__tests__/TimingAnimation-test.js @@ -5,12 +5,12 @@ * LICENSE file in the root directory of this source tree. * * @format - * @emails oncall+react_native + * @oncall react_native */ 'use strict'; -const TimingAnimation = require('../animations/TimingAnimation'); +import TimingAnimation from '../animations/TimingAnimation'; describe('Timing Animation', () => { it('should return array of 61 items', () => { diff --git a/Libraries/Animated/__tests__/bezier-test.js b/Libraries/Animated/__tests__/bezier-test.js index 1a02d7ad62ba10..da5303f9c5e8da 100644 --- a/Libraries/Animated/__tests__/bezier-test.js +++ b/Libraries/Animated/__tests__/bezier-test.js @@ -4,9 +4,9 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @emails oncall+react_native * @flow * @format + * @oncall react_native */ /** @@ -17,23 +17,28 @@ 'use strict'; -const bezier = require('../bezier'); +import bezier from '../bezier'; -const identity = function (x) { +const identity = function (x: number) { return x; }; -function assertClose(a, b, precision = 3) { +function assertClose(a: number, b: number, precision: number = 3) { expect(a).toBeCloseTo(b, precision); } -function makeAssertCloseWithPrecision(precision) { - return function (a, b) { +function makeAssertCloseWithPrecision(precision: number) { + return function (a: number, b: number) { assertClose(a, b, precision); }; } -function allEquals(be1, be2, samples, assertion) { +function allEquals( + be1: (x: number) => number, + be2: (x: number) => number, + samples: number, + assertion: $FlowFixMe, +) { if (!assertion) { assertion = assertClose; } @@ -43,8 +48,8 @@ function allEquals(be1, be2, samples, assertion) { } } -function repeat(n) { - return function (f) { +function repeat(n: number) { + return function (f: () => void) { for (let i = 0; i < n; ++i) { f(); } @@ -99,7 +104,7 @@ describe('bezier', function () { d = Math.random(); const easing = bezier(a, b, c, d); const projected = bezier(b, a, d, c); - const composed = function (x) { + const composed = function (x: number) { return projected(easing(x)); }; allEquals(identity, composed, 100, makeAssertCloseWithPrecision(2)); @@ -135,7 +140,7 @@ describe('bezier', function () { c = 1 - a, d = 1 - b; const easing = bezier(a, b, c, d); - const sym = function (x) { + const sym = function (x: number) { return 1 - easing(1 - x); }; allEquals(easing, sym, 100, makeAssertCloseWithPrecision(2)); diff --git a/Libraries/Animated/__tests__/createAnimatedComponentInjection-test.js b/Libraries/Animated/__tests__/createAnimatedComponentInjection-test.js index 9d8fa9b1869d99..15936f7b675a3b 100644 --- a/Libraries/Animated/__tests__/createAnimatedComponentInjection-test.js +++ b/Libraries/Animated/__tests__/createAnimatedComponentInjection-test.js @@ -4,16 +4,17 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @emails oncall+react_native * @flow strict-local * @format + * @oncall react_native */ 'use strict'; -const createAnimatedComponent = require('../createAnimatedComponent'); +import * as React from 'react'; + +const createAnimatedComponent = require('../createAnimatedComponent').default; const createAnimatedComponentInjection = require('../createAnimatedComponentInjection'); -const React = require('react'); function injected( Component: React.AbstractComponent, diff --git a/Libraries/Animated/animations/Animation.js b/Libraries/Animated/animations/Animation.js index f22c5e9e4adaa5..f3d2ac6d3ac234 100644 --- a/Libraries/Animated/animations/Animation.js +++ b/Libraries/Animated/animations/Animation.js @@ -10,10 +10,11 @@ 'use strict'; -const NativeAnimatedHelper = require('../NativeAnimatedHelper'); import type {PlatformConfig} from '../AnimatedPlatformConfig'; import type AnimatedValue from '../nodes/AnimatedValue'; +import NativeAnimatedHelper from '../NativeAnimatedHelper'; + export type EndResult = {finished: boolean, ...}; export type EndCallback = (result: EndResult) => void; @@ -30,7 +31,7 @@ let startNativeAnimationNextId = 1; // Important note: start() and stop() will only be called at most once. // Once an animation has been stopped or finished its course, it will // not be reused. -class Animation { +export default class Animation { __active: boolean; __isInteraction: boolean; __nativeId: number; @@ -85,5 +86,3 @@ class Animation { } } } - -module.exports = Animation; diff --git a/Libraries/Animated/animations/DecayAnimation.js b/Libraries/Animated/animations/DecayAnimation.js index c53ff08ac0fea4..f0042c5881dead 100644 --- a/Libraries/Animated/animations/DecayAnimation.js +++ b/Libraries/Animated/animations/DecayAnimation.js @@ -10,14 +10,13 @@ 'use strict'; -const Animation = require('./Animation'); - -const {shouldUseNativeDriver} = require('../NativeAnimatedHelper'); - import type {PlatformConfig} from '../AnimatedPlatformConfig'; import type AnimatedValue from '../nodes/AnimatedValue'; import type {AnimationConfig, EndCallback} from './Animation'; +import NativeAnimatedHelper from '../NativeAnimatedHelper'; +import Animation from './Animation'; + export type DecayAnimationConfig = { ...AnimationConfig, velocity: @@ -36,7 +35,7 @@ export type DecayAnimationConfigSingle = { deceleration?: number, }; -class DecayAnimation extends Animation { +export default class DecayAnimation extends Animation { _startTime: number; _lastValue: number; _fromValue: number; @@ -51,7 +50,7 @@ class DecayAnimation extends Animation { super(); this._deceleration = config.deceleration ?? 0.998; this._velocity = config.velocity; - this._useNativeDriver = shouldUseNativeDriver(config); + this._useNativeDriver = NativeAnimatedHelper.shouldUseNativeDriver(config); this._platformConfig = config.platformConfig; this.__isInteraction = config.isInteraction ?? !this._useNativeDriver; this.__iterations = config.iterations ?? 1; @@ -123,5 +122,3 @@ class DecayAnimation extends Animation { this.__debouncedOnEnd({finished: false}); } } - -module.exports = DecayAnimation; diff --git a/Libraries/Animated/animations/SpringAnimation.js b/Libraries/Animated/animations/SpringAnimation.js index 471fe50216cd50..69101dab030e8f 100644 --- a/Libraries/Animated/animations/SpringAnimation.js +++ b/Libraries/Animated/animations/SpringAnimation.js @@ -10,20 +10,17 @@ 'use strict'; -const AnimatedValue = require('../nodes/AnimatedValue'); -const AnimatedValueXY = require('../nodes/AnimatedValueXY'); -const AnimatedInterpolation = require('../nodes/AnimatedInterpolation'); -const Animation = require('./Animation'); -const SpringConfig = require('../SpringConfig'); - -const invariant = require('invariant'); - -const {shouldUseNativeDriver} = require('../NativeAnimatedHelper'); - import type {PlatformConfig} from '../AnimatedPlatformConfig'; +import type AnimatedInterpolation from '../nodes/AnimatedInterpolation'; +import type AnimatedValue from '../nodes/AnimatedValue'; +import type AnimatedValueXY from '../nodes/AnimatedValueXY'; import type {AnimationConfig, EndCallback} from './Animation'; +import NativeAnimatedHelper from '../NativeAnimatedHelper'; import AnimatedColor from '../nodes/AnimatedColor'; +import * as SpringConfig from '../SpringConfig'; +import Animation from './Animation'; +import invariant from 'invariant'; export type SpringAnimationConfig = { ...AnimationConfig, @@ -44,7 +41,7 @@ export type SpringAnimationConfig = { ... } | AnimatedColor - | AnimatedInterpolation, + | AnimatedInterpolation, overshootClamping?: boolean, restDisplacementThreshold?: number, restSpeedThreshold?: number, @@ -67,7 +64,7 @@ export type SpringAnimationConfig = { export type SpringAnimationConfigSingle = { ...AnimationConfig, - toValue: number | AnimatedValue | AnimatedInterpolation, + toValue: number, overshootClamping?: boolean, restDisplacementThreshold?: number, restSpeedThreshold?: number, @@ -82,7 +79,7 @@ export type SpringAnimationConfigSingle = { delay?: number, }; -class SpringAnimation extends Animation { +export default class SpringAnimation extends Animation { _overshootClamping: boolean; _restDisplacementThreshold: number; _restSpeedThreshold: number; @@ -90,7 +87,7 @@ class SpringAnimation extends Animation { _startPosition: number; _lastPosition: number; _fromValue: number; - _toValue: any; + _toValue: number; _stiffness: number; _damping: number; _mass: number; @@ -115,7 +112,7 @@ class SpringAnimation extends Animation { this._lastVelocity = config.velocity ?? 0; this._toValue = config.toValue; this._delay = config.delay ?? 0; - this._useNativeDriver = shouldUseNativeDriver(config); + this._useNativeDriver = NativeAnimatedHelper.shouldUseNativeDriver(config); this._platformConfig = config.platformConfig; this.__isInteraction = config.isInteraction ?? !this._useNativeDriver; this.__iterations = config.iterations ?? 1; @@ -371,5 +368,3 @@ class SpringAnimation extends Animation { this.__debouncedOnEnd({finished: false}); } } - -module.exports = SpringAnimation; diff --git a/Libraries/Animated/animations/TimingAnimation.js b/Libraries/Animated/animations/TimingAnimation.js index 748bb47cc6f313..5c0c3ce38144de 100644 --- a/Libraries/Animated/animations/TimingAnimation.js +++ b/Libraries/Animated/animations/TimingAnimation.js @@ -10,20 +10,18 @@ 'use strict'; -const AnimatedValue = require('../nodes/AnimatedValue'); -const AnimatedValueXY = require('../nodes/AnimatedValueXY'); -const AnimatedInterpolation = require('../nodes/AnimatedInterpolation'); -const Animation = require('./Animation'); - -const {shouldUseNativeDriver} = require('../NativeAnimatedHelper'); - import type {PlatformConfig} from '../AnimatedPlatformConfig'; -import type {AnimationConfig, EndCallback} from './Animation'; import type {RgbaValue} from '../nodes/AnimatedColor'; +import type AnimatedInterpolation from '../nodes/AnimatedInterpolation'; +import type AnimatedValue from '../nodes/AnimatedValue'; +import type AnimatedValueXY from '../nodes/AnimatedValueXY'; +import type {AnimationConfig, EndCallback} from './Animation'; +import NativeAnimatedHelper from '../NativeAnimatedHelper'; import AnimatedColor from '../nodes/AnimatedColor'; +import Animation from './Animation'; -export type TimingAnimationConfig = { +export type TimingAnimationConfig = $ReadOnly<{ ...AnimationConfig, toValue: | number @@ -36,33 +34,33 @@ export type TimingAnimationConfig = { | AnimatedValueXY | RgbaValue | AnimatedColor - | AnimatedInterpolation, + | AnimatedInterpolation, easing?: (value: number) => number, duration?: number, delay?: number, -}; +}>; -export type TimingAnimationConfigSingle = { +export type TimingAnimationConfigSingle = $ReadOnly<{ ...AnimationConfig, - toValue: number | AnimatedValue | AnimatedInterpolation, + toValue: number, easing?: (value: number) => number, duration?: number, delay?: number, -}; +}>; let _easeInOut; function easeInOut() { if (!_easeInOut) { - const Easing = require('../Easing'); + const Easing = require('../Easing').default; _easeInOut = Easing.inOut(Easing.ease); } return _easeInOut; } -class TimingAnimation extends Animation { +export default class TimingAnimation extends Animation { _startTime: number; _fromValue: number; - _toValue: any; + _toValue: number; _duration: number; _delay: number; _easing: (value: number) => number; @@ -79,7 +77,7 @@ class TimingAnimation extends Animation { this._duration = config.duration ?? 500; this._delay = config.delay ?? 0; this.__iterations = config.iterations ?? 1; - this._useNativeDriver = shouldUseNativeDriver(config); + this._useNativeDriver = NativeAnimatedHelper.shouldUseNativeDriver(config); this._platformConfig = config.platformConfig; this.__isInteraction = config.isInteraction ?? !this._useNativeDriver; } @@ -172,5 +170,3 @@ class TimingAnimation extends Animation { this.__debouncedOnEnd({finished: false}); } } - -module.exports = TimingAnimation; diff --git a/Libraries/Animated/bezier.js b/Libraries/Animated/bezier.js index da60afa0ec32e5..f18cef48e2daea 100644 --- a/Libraries/Animated/bezier.js +++ b/Libraries/Animated/bezier.js @@ -92,7 +92,7 @@ function newtonRaphsonIterate( return aGuessT; } -module.exports = function bezier( +export default function bezier( mX1: number, mY1: number, mX2: number, @@ -161,4 +161,4 @@ module.exports = function bezier( } return calcBezier(getTForX(x), mY1, mY2); }; -}; +} diff --git a/Libraries/Animated/components/AnimatedFlatList.js b/Libraries/Animated/components/AnimatedFlatList.js index ebe160f12e7545..afe8bd88061cec 100644 --- a/Libraries/Animated/components/AnimatedFlatList.js +++ b/Libraries/Animated/components/AnimatedFlatList.js @@ -8,13 +8,12 @@ * @format */ -import * as React from 'react'; - -const FlatList = require('../../Lists/FlatList'); -const createAnimatedComponent = require('../createAnimatedComponent'); - import type {AnimatedComponentType} from '../createAnimatedComponent'; +import FlatList from '../../Lists/FlatList'; +import createAnimatedComponent from '../createAnimatedComponent'; +import * as React from 'react'; + /** * @see https://github.com/facebook/react-native/commit/b8c8562 */ @@ -22,7 +21,7 @@ const FlatListWithEventThrottle = React.forwardRef((props, ref) => ( )); -module.exports = (createAnimatedComponent( +export default (createAnimatedComponent( FlatListWithEventThrottle, ): AnimatedComponentType< React.ElementConfig, diff --git a/Libraries/Animated/components/AnimatedImage.js b/Libraries/Animated/components/AnimatedImage.js index b0e7b9042020c2..c178480fe73a41 100644 --- a/Libraries/Animated/components/AnimatedImage.js +++ b/Libraries/Animated/components/AnimatedImage.js @@ -8,14 +8,13 @@ * @format */ -import * as React from 'react'; - -const Image = require('../../Image/Image'); -const createAnimatedComponent = require('../createAnimatedComponent'); - import type {AnimatedComponentType} from '../createAnimatedComponent'; -module.exports = (createAnimatedComponent( +import Image from '../../Image/Image'; +import createAnimatedComponent from '../createAnimatedComponent'; +import * as React from 'react'; + +export default (createAnimatedComponent( (Image: $FlowFixMe), ): AnimatedComponentType< React.ElementConfig, diff --git a/Libraries/Animated/components/AnimatedScrollView.js b/Libraries/Animated/components/AnimatedScrollView.js index 887948366ac849..a3ba2d272caed9 100644 --- a/Libraries/Animated/components/AnimatedScrollView.js +++ b/Libraries/Animated/components/AnimatedScrollView.js @@ -8,23 +8,119 @@ * @format */ +import type {____ViewStyle_Internal} from '../../StyleSheet/StyleSheetTypes'; +import type {AnimatedComponentType} from '../createAnimatedComponent'; + +import RefreshControl from '../../Components/RefreshControl/RefreshControl'; +import ScrollView from '../../Components/ScrollView/ScrollView'; +import flattenStyle from '../../StyleSheet/flattenStyle'; +import splitLayoutProps from '../../StyleSheet/splitLayoutProps'; +import StyleSheet from '../../StyleSheet/StyleSheet'; +import Platform from '../../Utilities/Platform'; +import useMergeRefs from '../../Utilities/useMergeRefs'; +import createAnimatedComponent from '../createAnimatedComponent'; +import useAnimatedProps from '../useAnimatedProps'; import * as React from 'react'; +import {useMemo} from 'react'; -const ScrollView = require('../../Components/ScrollView/ScrollView'); -const createAnimatedComponent = require('../createAnimatedComponent'); - -import type {AnimatedComponentType} from '../createAnimatedComponent'; +type Props = React.ElementConfig; +type Instance = React.ElementRef; /** * @see https://github.com/facebook/react-native/commit/b8c8562 */ -const ScrollViewWithEventThrottle = React.forwardRef((props, ref) => ( - -)); - -module.exports = (createAnimatedComponent( - ScrollViewWithEventThrottle, -): AnimatedComponentType< - React.ElementConfig, - React.ElementRef, ->); +const AnimatedScrollView: AnimatedComponentType = + React.forwardRef((props, forwardedRef) => { + // (Android only) When a ScrollView has a RefreshControl and + // any `style` property set with an Animated.Value, the CSS + // gets incorrectly applied twice. This is because ScrollView + // swaps the parent/child relationship of itself and the + // RefreshControl component (see ScrollView.js for more details). + if ( + Platform.OS === 'android' && + props.refreshControl != null && + props.style != null + ) { + return ( + + ); + } else { + return ( + + ); + } + }); + +const AnimatedScrollViewWithInvertedRefreshControl = React.forwardRef( + ( + props: { + ...React.ElementConfig, + // $FlowFixMe[unclear-type] Same Flow type as `refreshControl` in ScrollView + refreshControl: React.Element, + }, + forwardedRef, + ) => { + // Split `props` into the animate-able props for the parent (RefreshControl) + // and child (ScrollView). + const {intermediatePropsForRefreshControl, intermediatePropsForScrollView} = + useMemo(() => { + const {outer, inner} = splitLayoutProps(flattenStyle(props.style)); + return { + intermediatePropsForRefreshControl: {style: outer}, + intermediatePropsForScrollView: {...props, style: inner}, + }; + }, [props]); + + // Handle animated props on `refreshControl`. + const [refreshControlAnimatedProps, refreshControlRef] = useAnimatedProps< + {style: ?____ViewStyle_Internal}, + $FlowFixMe, + >(intermediatePropsForRefreshControl); + // NOTE: Assumes that refreshControl.ref` and `refreshControl.style` can be + // safely clobbered. + const refreshControl: React.Element = + React.cloneElement(props.refreshControl, { + ...refreshControlAnimatedProps, + ref: refreshControlRef, + }); + + // Handle animated props on `NativeDirectionalScrollView`. + const [scrollViewAnimatedProps, scrollViewRef] = useAnimatedProps< + Props, + Instance, + >(intermediatePropsForScrollView); + const ref = useMergeRefs(scrollViewRef, forwardedRef); + + return ( + // $FlowFixMe[incompatible-use] Investigate useAnimatedProps return value + + ); + }, +); + +const AnimatedScrollViewWithoutInvertedRefreshControl = + createAnimatedComponent(ScrollView); + +export default AnimatedScrollView; diff --git a/Libraries/Animated/components/AnimatedSectionList.js b/Libraries/Animated/components/AnimatedSectionList.js index 2c467a66998282..955691f6e2b278 100644 --- a/Libraries/Animated/components/AnimatedSectionList.js +++ b/Libraries/Animated/components/AnimatedSectionList.js @@ -8,12 +8,11 @@ * @format */ -import * as React from 'react'; +import type {AnimatedComponentType} from '../createAnimatedComponent'; import SectionList from '../../Lists/SectionList'; -const createAnimatedComponent = require('../createAnimatedComponent'); - -import type {AnimatedComponentType} from '../createAnimatedComponent'; +import createAnimatedComponent from '../createAnimatedComponent'; +import * as React from 'react'; /** * @see https://github.com/facebook/react-native/commit/b8c8562 @@ -22,7 +21,7 @@ const SectionListWithEventThrottle = React.forwardRef((props, ref) => ( )); -module.exports = (createAnimatedComponent( +export default (createAnimatedComponent( SectionListWithEventThrottle, ): AnimatedComponentType< React.ElementConfig, diff --git a/Libraries/Animated/components/AnimatedText.js b/Libraries/Animated/components/AnimatedText.js index 0cd6cd5245d301..02679f1a8013a9 100644 --- a/Libraries/Animated/components/AnimatedText.js +++ b/Libraries/Animated/components/AnimatedText.js @@ -8,14 +8,13 @@ * @format */ -import * as React from 'react'; - -const Text = require('../../Text/Text'); -const createAnimatedComponent = require('../createAnimatedComponent'); - import type {AnimatedComponentType} from '../createAnimatedComponent'; -module.exports = (createAnimatedComponent( +import Text from '../../Text/Text'; +import createAnimatedComponent from '../createAnimatedComponent'; +import * as React from 'react'; + +export default (createAnimatedComponent( (Text: $FlowFixMe), ): AnimatedComponentType< React.ElementConfig, diff --git a/Libraries/Animated/components/AnimatedView.js b/Libraries/Animated/components/AnimatedView.js index 75358b003d5dfc..5eca94417e67da 100644 --- a/Libraries/Animated/components/AnimatedView.js +++ b/Libraries/Animated/components/AnimatedView.js @@ -8,14 +8,13 @@ * @format */ -import * as React from 'react'; - -const View = require('../../Components/View/View'); -const createAnimatedComponent = require('../createAnimatedComponent'); - import type {AnimatedComponentType} from '../createAnimatedComponent'; -module.exports = (createAnimatedComponent(View): AnimatedComponentType< +import View from '../../Components/View/View'; +import createAnimatedComponent from '../createAnimatedComponent'; +import * as React from 'react'; + +export default (createAnimatedComponent(View): AnimatedComponentType< React.ElementConfig, React.ElementRef, >); diff --git a/Libraries/Animated/createAnimatedComponent.js b/Libraries/Animated/createAnimatedComponent.js index 3272281e6334f3..fb64ba05ffd375 100644 --- a/Libraries/Animated/createAnimatedComponent.js +++ b/Libraries/Animated/createAnimatedComponent.js @@ -10,22 +10,20 @@ 'use strict'; +import View from '../Components/View/View'; +import setAndForwardRef from '../Utilities/setAndForwardRef'; +import {AnimatedEvent} from './AnimatedEvent'; import * as createAnimatedComponentInjection from './createAnimatedComponentInjection'; - -const View = require('../Components/View/View'); -const {AnimatedEvent} = require('./AnimatedEvent'); -const AnimatedProps = require('./nodes/AnimatedProps'); -const React = require('react'); -const NativeAnimatedHelper = require('./NativeAnimatedHelper'); - -const invariant = require('invariant'); -const setAndForwardRef = require('../Utilities/setAndForwardRef'); +import NativeAnimatedHelper from './NativeAnimatedHelper'; +import AnimatedProps from './nodes/AnimatedProps'; +import invariant from 'invariant'; +import * as React from 'react'; let animatedComponentNextId = 1; export type AnimatedComponentType< - Props: {+[string]: mixed, ...}, - Instance, + -Props: {+[string]: mixed, ...}, + +Instance = mixed, > = React.AbstractComponent< $ObjMap< Props & @@ -139,7 +137,7 @@ function createAnimatedComponent( // components. If you want to animate a composite component, you need to // re-render it. In this case, we have a fallback that uses forceUpdate. // This fallback is also called in Fabric. - _animatedPropsCallback = () => { + _animatedPropsCallback = (): void => { if (this._component == null) { // AnimatedProps is created in will-mount because it's used in render. // But this callback may be invoked before mount in async mode, @@ -191,7 +189,7 @@ function createAnimatedComponent( } } - _setComponentRef = setAndForwardRef({ + _setComponentRef: (ref: React.ElementRef) => void = setAndForwardRef({ getForwardedRef: () => this.props.forwardedRef, setLocalRef: ref => { this._prevComponent = this._component; @@ -199,8 +197,10 @@ function createAnimatedComponent( }, }); - render() { - const {style = {}, ...props} = this._propsAnimated.__getValue() || {}; + render(): React.Node { + const animatedProps = this._propsAnimated.__getValue() || {}; + + const {style = {}, ...props} = animatedProps; const {style: passthruStyle = {}, ...passthruProps} = this.props.passthroughAnimatedPropExplicitValues || {}; const mergedStyle = {...style, ...passthruStyle}; @@ -270,5 +270,5 @@ function createAnimatedComponent( } // $FlowIgnore[incompatible-cast] - Will be compatible after refactors. -module.exports = (createAnimatedComponentInjection.recordAndRetrieve() ?? +export default (createAnimatedComponentInjection.recordAndRetrieve() ?? createAnimatedComponent: typeof createAnimatedComponent); diff --git a/Libraries/Animated/createAnimatedComponent_EXPERIMENTAL.js b/Libraries/Animated/createAnimatedComponent_EXPERIMENTAL.js index b2cd04ac56e44b..eb7c78cecc815c 100644 --- a/Libraries/Animated/createAnimatedComponent_EXPERIMENTAL.js +++ b/Libraries/Animated/createAnimatedComponent_EXPERIMENTAL.js @@ -8,9 +8,9 @@ * @format */ -import useAnimatedProps from './useAnimatedProps'; -import useMergeRefs from '../Utilities/useMergeRefs'; import StyleSheet from '../StyleSheet/StyleSheet'; +import useMergeRefs from '../Utilities/useMergeRefs'; +import useAnimatedProps from './useAnimatedProps'; import * as React from 'react'; /** diff --git a/Libraries/Animated/nodes/AnimatedAddition.js b/Libraries/Animated/nodes/AnimatedAddition.js index 409db6e4d6b7b3..7a48965f5dd545 100644 --- a/Libraries/Animated/nodes/AnimatedAddition.js +++ b/Libraries/Animated/nodes/AnimatedAddition.js @@ -10,15 +10,15 @@ 'use strict'; -const AnimatedInterpolation = require('./AnimatedInterpolation'); -const AnimatedNode = require('./AnimatedNode'); -const AnimatedValue = require('./AnimatedValue'); -const AnimatedWithChildren = require('./AnimatedWithChildren'); - import type {PlatformConfig} from '../AnimatedPlatformConfig'; import type {InterpolationConfigType} from './AnimatedInterpolation'; +import type AnimatedNode from './AnimatedNode'; + +import AnimatedInterpolation from './AnimatedInterpolation'; +import AnimatedValue from './AnimatedValue'; +import AnimatedWithChildren from './AnimatedWithChildren'; -class AnimatedAddition extends AnimatedWithChildren { +export default class AnimatedAddition extends AnimatedWithChildren { _a: AnimatedNode; _b: AnimatedNode; @@ -38,7 +38,9 @@ class AnimatedAddition extends AnimatedWithChildren { return this._a.__getValue() + this._b.__getValue(); } - interpolate(config: InterpolationConfigType): AnimatedInterpolation { + interpolate( + config: InterpolationConfigType, + ): AnimatedInterpolation { return new AnimatedInterpolation(this, config); } @@ -60,5 +62,3 @@ class AnimatedAddition extends AnimatedWithChildren { }; } } - -module.exports = AnimatedAddition; diff --git a/Libraries/Animated/nodes/AnimatedColor.js b/Libraries/Animated/nodes/AnimatedColor.js index 603b329fa7c850..d6fba11337f76b 100644 --- a/Libraries/Animated/nodes/AnimatedColor.js +++ b/Libraries/Animated/nodes/AnimatedColor.js @@ -10,17 +10,23 @@ 'use strict'; -import AnimatedValue from './AnimatedValue'; -import AnimatedWithChildren from './AnimatedWithChildren'; +import type {NativeColorValue} from '../../StyleSheet/PlatformColorValueTypes'; +import type {ProcessedColorValue} from '../../StyleSheet/processColor'; +import type {ColorValue} from '../../StyleSheet/StyleSheet'; +import type {PlatformConfig} from '../AnimatedPlatformConfig'; + import normalizeColor from '../../StyleSheet/normalizeColor'; import {processColorObject} from '../../StyleSheet/PlatformColorValueTypes'; import NativeAnimatedHelper from '../NativeAnimatedHelper'; +import AnimatedValue from './AnimatedValue'; +import AnimatedWithChildren from './AnimatedWithChildren'; -import type {PlatformConfig} from '../AnimatedPlatformConfig'; -import type {ColorValue} from '../../StyleSheet/StyleSheet'; -import type {NativeColorValue} from '../../StyleSheet/PlatformColorValueTypes'; +export type AnimatedColorConfig = $ReadOnly<{ + useNativeDriver: boolean, +}>; + +type ColorListenerCallback = (value: ColorValue) => mixed; -type ColorListenerCallback = (value: string) => mixed; export type RgbaValue = { +r: number, +g: number, @@ -28,6 +34,7 @@ export type RgbaValue = { +a: number, ... }; + type RgbaAnimatedValue = { +r: AnimatedValue, +g: AnimatedValue, @@ -36,30 +43,43 @@ type RgbaAnimatedValue = { ... }; +const NativeAnimatedAPI = NativeAnimatedHelper.API; + const defaultColor: RgbaValue = {r: 0, g: 0, b: 0, a: 1.0}; let _uniqueId = 1; /* eslint no-bitwise: 0 */ -function processColor(color?: ?ColorValue): ?(RgbaValue | NativeColorValue) { +function processColor( + color?: ?(ColorValue | RgbaValue), +): ?(RgbaValue | NativeColorValue) { if (color === undefined || color === null) { return null; } - let normalizedColor = normalizeColor(color); + if (isRgbaValue(color)) { + // $FlowIgnore[incompatible-cast] - Type is verified above + return (color: RgbaValue); + } + + let normalizedColor: ?ProcessedColorValue = normalizeColor( + // $FlowIgnore[incompatible-cast] - Type is verified above + (color: ColorValue), + ); if (normalizedColor === undefined || normalizedColor === null) { return null; } if (typeof normalizedColor === 'object') { - const processedColorObj = processColorObject(normalizedColor); + const processedColorObj: ?NativeColorValue = + processColorObject(normalizedColor); if (processedColorObj != null) { return processedColorObj; } } else if (typeof normalizedColor === 'number') { - const r = (normalizedColor & 0xff000000) >>> 24; - const g = (normalizedColor & 0x00ff0000) >>> 16; - const b = (normalizedColor & 0x0000ff00) >>> 8; - const a = (normalizedColor & 0x000000ff) / 255; + const r: number = (normalizedColor & 0xff000000) >>> 24; + const g: number = (normalizedColor & 0x00ff0000) >>> 16; + const b: number = (normalizedColor & 0x0000ff00) >>> 8; + const a: number = (normalizedColor & 0x000000ff) / 255; return {r, g, b, a}; } @@ -92,7 +112,7 @@ export default class AnimatedColor extends AnimatedWithChildren { g: AnimatedValue; b: AnimatedValue; a: AnimatedValue; - nativeColor: Object; + nativeColor: ?NativeColorValue; _listeners: { [key: string]: { r: string, @@ -102,21 +122,15 @@ export default class AnimatedColor extends AnimatedWithChildren { ... }, ... - }; + } = {}; - constructor(valueIn?: ?(RgbaValue | RgbaAnimatedValue | ColorValue)) { + constructor( + valueIn?: ?(RgbaValue | RgbaAnimatedValue | ColorValue), + config?: ?AnimatedColorConfig, + ) { super(); let value: RgbaValue | RgbaAnimatedValue | ColorValue = valueIn ?? defaultColor; - this.setValue(value); - this._listeners = {}; - } - - /** - * Directly set the value. This will stop any animations running on the value - * and update all the bound properties. - */ - setValue(value: RgbaValue | RgbaAnimatedValue | ColorValue): void { if (isRgbaAnimatedValue(value)) { // $FlowIgnore[incompatible-cast] - Type is verified above const rgbaAnimatedValue: RgbaAnimatedValue = (value: RgbaAnimatedValue); @@ -125,62 +139,70 @@ export default class AnimatedColor extends AnimatedWithChildren { this.b = rgbaAnimatedValue.b; this.a = rgbaAnimatedValue.a; } else { - // Handle potential parsable string color or platform color object - if (!isRgbaValue(value)) { - // $FlowIgnore[incompatible-cast] - Type is verified via conditionals - value = processColor((value: ColorValue)) ?? defaultColor; + const processedColor: RgbaValue | NativeColorValue = + // $FlowIgnore[incompatible-cast] - Type is verified above + processColor((value: ColorValue | RgbaValue)) ?? defaultColor; + let initColor: RgbaValue = defaultColor; + if (isRgbaValue(processedColor)) { + // $FlowIgnore[incompatible-cast] - Type is verified above + initColor = (processedColor: RgbaValue); + } else { + // $FlowIgnore[incompatible-cast] - Type is verified above + this.nativeColor = (processedColor: NativeColorValue); } - if (!isRgbaValue(value)) { - // We are using a platform color - this.nativeColor = value; - value = defaultColor; - } + this.r = new AnimatedValue(initColor.r); + this.g = new AnimatedValue(initColor.g); + this.b = new AnimatedValue(initColor.b); + this.a = new AnimatedValue(initColor.a); + } + if (this.nativeColor || (config && config.useNativeDriver)) { + this.__makeNative(); + } + } - if (isRgbaValue(value)) { - // $FlowIgnore[incompatible-cast] - Type is verified via conditionals - const rgbaValue: RgbaValue = (value: RgbaValue); - - if (this.r) { - this.r.setValue(rgbaValue.r); - } else { - this.r = new AnimatedValue(rgbaValue.r); - } - - if (this.g) { - this.g.setValue(rgbaValue.g); - } else { - this.g = new AnimatedValue(rgbaValue.g); - } - - if (this.b) { - this.b.setValue(rgbaValue.b); - } else { - this.b = new AnimatedValue(rgbaValue.b); - } - - if (this.a) { - this.a.setValue(rgbaValue.a); - } else { - this.a = new AnimatedValue(rgbaValue.a); - } - } + /** + * Directly set the value. This will stop any animations running on the value + * and update all the bound properties. + */ + setValue(value: RgbaValue | ColorValue): void { + let shouldUpdateNodeConfig = false; + if (this.__isNative) { + const nativeTag = this.__getNativeTag(); + NativeAnimatedAPI.setWaitingForIdentifier(nativeTag.toString()); + } - if (this.nativeColor) { - if (!this.__isNative) { - this.__makeNative(); - } + const processedColor: RgbaValue | NativeColorValue = + processColor(value) ?? defaultColor; + if (isRgbaValue(processedColor)) { + // $FlowIgnore[incompatible-type] - Type is verified above + const rgbaValue: RgbaValue = processedColor; + this.r.setValue(rgbaValue.r); + this.g.setValue(rgbaValue.g); + this.b.setValue(rgbaValue.b); + this.a.setValue(rgbaValue.a); + if (this.nativeColor != null) { + this.nativeColor = null; + shouldUpdateNodeConfig = true; + } + } else { + // $FlowIgnore[incompatible-type] - Type is verified above + const nativeColor: NativeColorValue = processedColor; + if (this.nativeColor !== nativeColor) { + this.nativeColor = nativeColor; + shouldUpdateNodeConfig = true; + } + } - const nativeTag = this.__getNativeTag(); - NativeAnimatedHelper.API.setWaitingForIdentifier(nativeTag.toString()); - NativeAnimatedHelper.API.updateAnimatedNodeConfig( + if (this.__isNative) { + const nativeTag = this.__getNativeTag(); + if (shouldUpdateNodeConfig) { + NativeAnimatedAPI.updateAnimatedNodeConfig( nativeTag, this.__getNativeConfig(), ); - NativeAnimatedHelper.API.unsetWaitingForIdentifier( - nativeTag.toString(), - ); } + NativeAnimatedAPI.unsetWaitingForIdentifier(nativeTag.toString()); } } @@ -227,7 +249,7 @@ export default class AnimatedColor extends AnimatedWithChildren { */ addListener(callback: ColorListenerCallback): string { const id = String(_uniqueId++); - const jointCallback = ({value: number}) => { + const jointCallback = ({value: number}: any) => { callback(this.__getValue()); }; this._listeners[id] = { @@ -267,7 +289,7 @@ export default class AnimatedColor extends AnimatedWithChildren { * final value after stopping the animation, which is useful for updating * state to match the animation position with layout. */ - stopAnimation(callback?: (value: string) => void): void { + stopAnimation(callback?: ColorListenerCallback): void { this.r.stopAnimation(); this.g.stopAnimation(); this.b.stopAnimation(); @@ -278,7 +300,7 @@ export default class AnimatedColor extends AnimatedWithChildren { /** * Stops any animation and resets the value to its original. */ - resetAnimation(callback?: (value: string) => void): void { + resetAnimation(callback?: ColorListenerCallback): void { this.r.resetAnimation(); this.g.resetAnimation(); this.b.resetAnimation(); @@ -286,8 +308,12 @@ export default class AnimatedColor extends AnimatedWithChildren { callback && callback(this.__getValue()); } - __getValue(): string { - return `rgba(${this.r.__getValue()}, ${this.g.__getValue()}, ${this.b.__getValue()}, ${this.a.__getValue()})`; + __getValue(): ColorValue { + if (this.nativeColor != null) { + return this.nativeColor; + } else { + return `rgba(${this.r.__getValue()}, ${this.g.__getValue()}, ${this.b.__getValue()}, ${this.a.__getValue()})`; + } } __attach(): void { diff --git a/Libraries/Animated/nodes/AnimatedDiffClamp.js b/Libraries/Animated/nodes/AnimatedDiffClamp.js index 629e04cc68113f..d2ac11ae764a11 100644 --- a/Libraries/Animated/nodes/AnimatedDiffClamp.js +++ b/Libraries/Animated/nodes/AnimatedDiffClamp.js @@ -10,14 +10,14 @@ 'use strict'; -const AnimatedInterpolation = require('./AnimatedInterpolation'); -const AnimatedNode = require('./AnimatedNode'); -const AnimatedWithChildren = require('./AnimatedWithChildren'); - -import type {InterpolationConfigType} from './AnimatedInterpolation'; import type {PlatformConfig} from '../AnimatedPlatformConfig'; +import type {InterpolationConfigType} from './AnimatedInterpolation'; +import type AnimatedNode from './AnimatedNode'; -class AnimatedDiffClamp extends AnimatedWithChildren { +import AnimatedInterpolation from './AnimatedInterpolation'; +import AnimatedWithChildren from './AnimatedWithChildren'; + +export default class AnimatedDiffClamp extends AnimatedWithChildren { _a: AnimatedNode; _min: number; _max: number; @@ -38,7 +38,9 @@ class AnimatedDiffClamp extends AnimatedWithChildren { super.__makeNative(platformConfig); } - interpolate(config: InterpolationConfigType): AnimatedInterpolation { + interpolate( + config: InterpolationConfigType, + ): AnimatedInterpolation { return new AnimatedInterpolation(this, config); } @@ -68,5 +70,3 @@ class AnimatedDiffClamp extends AnimatedWithChildren { }; } } - -module.exports = AnimatedDiffClamp; diff --git a/Libraries/Animated/nodes/AnimatedDivision.js b/Libraries/Animated/nodes/AnimatedDivision.js index 1dcd4622ac135d..158a0f3d7805f2 100644 --- a/Libraries/Animated/nodes/AnimatedDivision.js +++ b/Libraries/Animated/nodes/AnimatedDivision.js @@ -10,15 +10,15 @@ 'use strict'; -const AnimatedInterpolation = require('./AnimatedInterpolation'); -const AnimatedNode = require('./AnimatedNode'); -const AnimatedValue = require('./AnimatedValue'); -const AnimatedWithChildren = require('./AnimatedWithChildren'); - -import type {InterpolationConfigType} from './AnimatedInterpolation'; import type {PlatformConfig} from '../AnimatedPlatformConfig'; +import type {InterpolationConfigType} from './AnimatedInterpolation'; -class AnimatedDivision extends AnimatedWithChildren { +import AnimatedInterpolation from './AnimatedInterpolation'; +import AnimatedNode from './AnimatedNode'; +import AnimatedValue from './AnimatedValue'; +import AnimatedWithChildren from './AnimatedWithChildren'; + +export default class AnimatedDivision extends AnimatedWithChildren { _a: AnimatedNode; _b: AnimatedNode; _warnedAboutDivideByZero: boolean = false; @@ -54,7 +54,9 @@ class AnimatedDivision extends AnimatedWithChildren { return a / b; } - interpolate(config: InterpolationConfigType): AnimatedInterpolation { + interpolate( + config: InterpolationConfigType, + ): AnimatedInterpolation { return new AnimatedInterpolation(this, config); } @@ -76,5 +78,3 @@ class AnimatedDivision extends AnimatedWithChildren { }; } } - -module.exports = AnimatedDivision; diff --git a/Libraries/Animated/nodes/AnimatedInterpolation.js b/Libraries/Animated/nodes/AnimatedInterpolation.js index d6f5deed041f5a..be85be6e89d742 100644 --- a/Libraries/Animated/nodes/AnimatedInterpolation.js +++ b/Libraries/Animated/nodes/AnimatedInterpolation.js @@ -12,20 +12,19 @@ 'use strict'; -const AnimatedNode = require('./AnimatedNode'); -const AnimatedWithChildren = require('./AnimatedWithChildren'); -const NativeAnimatedHelper = require('../NativeAnimatedHelper'); - -const invariant = require('invariant'); -const normalizeColor = require('../../StyleSheet/normalizeColor'); - import type {PlatformConfig} from '../AnimatedPlatformConfig'; +import type AnimatedNode from './AnimatedNode'; + +import normalizeColor from '../../StyleSheet/normalizeColor'; +import NativeAnimatedHelper from '../NativeAnimatedHelper'; +import AnimatedWithChildren from './AnimatedWithChildren'; +import invariant from 'invariant'; type ExtrapolateType = 'extend' | 'identity' | 'clamp'; -export type InterpolationConfigType = $ReadOnly<{ +export type InterpolationConfigType = $ReadOnly<{ inputRange: $ReadOnlyArray, - outputRange: $ReadOnlyArray | $ReadOnlyArray, + outputRange: $ReadOnlyArray, easing?: (input: number) => number, extrapolate?: ExtrapolateType, extrapolateLeft?: ExtrapolateType, @@ -38,28 +37,31 @@ const linear = (t: number) => t; * Very handy helper to map input ranges to output ranges with an easing * function and custom behavior outside of the ranges. */ -function createInterpolation( - config: InterpolationConfigType, -): (input: number) => number | string { +function createInterpolation( + config: InterpolationConfigType, +): (input: number) => OutputT { if (config.outputRange && typeof config.outputRange[0] === 'string') { - return createInterpolationFromStringOutputRange(config); + return (createInterpolationFromStringOutputRange((config: any)): any); } - const outputRange: Array = (config.outputRange: any); - checkInfiniteRange('outputRange', outputRange); + const outputRange: $ReadOnlyArray = (config.outputRange: any); const inputRange = config.inputRange; - checkInfiniteRange('inputRange', inputRange); - checkValidInputRange(inputRange); - invariant( - inputRange.length === outputRange.length, - 'inputRange (' + - inputRange.length + - ') and outputRange (' + - outputRange.length + - ') must have the same length', - ); + if (__DEV__) { + checkInfiniteRange('outputRange', outputRange); + checkInfiniteRange('inputRange', inputRange); + checkValidInputRange(inputRange); + + invariant( + inputRange.length === outputRange.length, + 'inputRange (' + + inputRange.length + + ') and outputRange (' + + outputRange.length + + ') must have the same length', + ); + } const easing = config.easing || linear; @@ -84,7 +86,7 @@ function createInterpolation( ); const range = findRange(input, inputRange); - return interpolate( + return (interpolate( input, inputRange[range], inputRange[range + 1], @@ -93,7 +95,7 @@ function createInterpolation( easing, extrapolateLeft, extrapolateRight, - ); + ): any); }; } @@ -192,7 +194,7 @@ const stringShapeRegex = /[+-]?(?:\d+\.?\d*|\.\d+)(?:[eE][+-]?\d+)?/g; * -45deg // values with units */ function createInterpolationFromStringOutputRange( - config: InterpolationConfigType, + config: InterpolationConfigType, ): (input: number) => string { let outputRange: Array = (config.outputRange: any); invariant(outputRange.length >= 2, 'Bad output range'); @@ -276,16 +278,10 @@ function findRange(input: number, inputRange: $ReadOnlyArray) { function checkValidInputRange(arr: $ReadOnlyArray) { invariant(arr.length >= 2, 'inputRange must have at least 2 elements'); + const message = + 'inputRange must be monotonically non-decreasing ' + String(arr); for (let i = 1; i < arr.length; ++i) { - invariant( - arr[i] >= arr[i - 1], - /* $FlowFixMe[incompatible-type] (>=0.13.0) - In the addition expression - * below this comment, one or both of the operands may be something that - * doesn't cleanly convert to a string, like undefined, null, and object, - * etc. If you really mean this implicit string conversion, you can do - * something like String(myThing) */ - 'inputRange must be monotonically non-decreasing ' + arr, - ); + invariant(arr[i] >= arr[i - 1], message); } } @@ -302,17 +298,19 @@ function checkInfiniteRange(name: string, arr: $ReadOnlyArray) { ); } -class AnimatedInterpolation extends AnimatedWithChildren { +export default class AnimatedInterpolation< + OutputT: number | string, +> extends AnimatedWithChildren { // Export for testing. static __createInterpolation: ( - config: InterpolationConfigType, - ) => (input: number) => number | string = createInterpolation; + config: InterpolationConfigType, + ) => (input: number) => OutputT = createInterpolation; _parent: AnimatedNode; - _config: InterpolationConfigType; - _interpolation: (input: number) => number | string; + _config: InterpolationConfigType; + _interpolation: (input: number) => OutputT; - constructor(parent: AnimatedNode, config: InterpolationConfigType) { + constructor(parent: AnimatedNode, config: InterpolationConfigType) { super(); this._parent = parent; this._config = config; @@ -333,7 +331,9 @@ class AnimatedInterpolation extends AnimatedWithChildren { return this._interpolation(parentValue); } - interpolate(config: InterpolationConfigType): AnimatedInterpolation { + interpolate( + config: InterpolationConfigType, + ): AnimatedInterpolation { return new AnimatedInterpolation(this, config); } @@ -346,7 +346,7 @@ class AnimatedInterpolation extends AnimatedWithChildren { super.__detach(); } - __transformDataType(range: Array): Array { + __transformDataType(range: $ReadOnlyArray): Array { return range.map(NativeAnimatedHelper.transformDataType); } @@ -358,9 +358,6 @@ class AnimatedInterpolation extends AnimatedWithChildren { return { inputRange: this._config.inputRange, // Only the `outputRange` can contain strings so we don't need to transform `inputRange` here - /* $FlowFixMe[incompatible-call] (>=0.38.0) - Flow error detected during - * the deployment of v0.38.0. To see the error, remove this comment and - * run flow */ outputRange: this.__transformDataType(this._config.outputRange), extrapolateLeft: this._config.extrapolateLeft || this._config.extrapolate || 'extend', @@ -370,5 +367,3 @@ class AnimatedInterpolation extends AnimatedWithChildren { }; } } - -module.exports = AnimatedInterpolation; diff --git a/Libraries/Animated/nodes/AnimatedModulo.js b/Libraries/Animated/nodes/AnimatedModulo.js index 88663cc0e12426..d5334478afd406 100644 --- a/Libraries/Animated/nodes/AnimatedModulo.js +++ b/Libraries/Animated/nodes/AnimatedModulo.js @@ -10,14 +10,14 @@ 'use strict'; -const AnimatedInterpolation = require('./AnimatedInterpolation'); -const AnimatedNode = require('./AnimatedNode'); -const AnimatedWithChildren = require('./AnimatedWithChildren'); - -import type {InterpolationConfigType} from './AnimatedInterpolation'; import type {PlatformConfig} from '../AnimatedPlatformConfig'; +import type {InterpolationConfigType} from './AnimatedInterpolation'; +import type AnimatedNode from './AnimatedNode'; -class AnimatedModulo extends AnimatedWithChildren { +import AnimatedInterpolation from './AnimatedInterpolation'; +import AnimatedWithChildren from './AnimatedWithChildren'; + +export default class AnimatedModulo extends AnimatedWithChildren { _a: AnimatedNode; _modulus: number; @@ -38,7 +38,9 @@ class AnimatedModulo extends AnimatedWithChildren { ); } - interpolate(config: InterpolationConfigType): AnimatedInterpolation { + interpolate( + config: InterpolationConfigType, + ): AnimatedInterpolation { return new AnimatedInterpolation(this, config); } @@ -59,5 +61,3 @@ class AnimatedModulo extends AnimatedWithChildren { }; } } - -module.exports = AnimatedModulo; diff --git a/Libraries/Animated/nodes/AnimatedMultiplication.js b/Libraries/Animated/nodes/AnimatedMultiplication.js index 9adb2570549703..b3cfaf3aed3ff5 100644 --- a/Libraries/Animated/nodes/AnimatedMultiplication.js +++ b/Libraries/Animated/nodes/AnimatedMultiplication.js @@ -10,15 +10,15 @@ 'use strict'; -const AnimatedInterpolation = require('./AnimatedInterpolation'); -const AnimatedNode = require('./AnimatedNode'); -const AnimatedValue = require('./AnimatedValue'); -const AnimatedWithChildren = require('./AnimatedWithChildren'); - -import type {InterpolationConfigType} from './AnimatedInterpolation'; import type {PlatformConfig} from '../AnimatedPlatformConfig'; +import type {InterpolationConfigType} from './AnimatedInterpolation'; +import type AnimatedNode from './AnimatedNode'; -class AnimatedMultiplication extends AnimatedWithChildren { +import AnimatedInterpolation from './AnimatedInterpolation'; +import AnimatedValue from './AnimatedValue'; +import AnimatedWithChildren from './AnimatedWithChildren'; + +export default class AnimatedMultiplication extends AnimatedWithChildren { _a: AnimatedNode; _b: AnimatedNode; @@ -38,10 +38,11 @@ class AnimatedMultiplication extends AnimatedWithChildren { return this._a.__getValue() * this._b.__getValue(); } - interpolate(config: InterpolationConfigType): AnimatedInterpolation { + interpolate( + config: InterpolationConfigType, + ): AnimatedInterpolation { return new AnimatedInterpolation(this, config); } - __attach(): void { this._a.__addChild(this); this._b.__addChild(this); @@ -60,5 +61,3 @@ class AnimatedMultiplication extends AnimatedWithChildren { }; } } - -module.exports = AnimatedMultiplication; diff --git a/Libraries/Animated/nodes/AnimatedNode.js b/Libraries/Animated/nodes/AnimatedNode.js index b4a649ff302afd..890e9e865bc11d 100644 --- a/Libraries/Animated/nodes/AnimatedNode.js +++ b/Libraries/Animated/nodes/AnimatedNode.js @@ -10,12 +10,13 @@ 'use strict'; -const NativeAnimatedHelper = require('../NativeAnimatedHelper'); +import type {PlatformConfig} from '../AnimatedPlatformConfig'; -const NativeAnimatedAPI = NativeAnimatedHelper.API; -const invariant = require('invariant'); +import ReactNativeFeatureFlags from '../../ReactNative/ReactNativeFeatureFlags'; +import NativeAnimatedHelper from '../NativeAnimatedHelper'; +import invariant from 'invariant'; -import type {PlatformConfig} from '../AnimatedPlatformConfig'; +const NativeAnimatedAPI = NativeAnimatedHelper.API; type ValueListenerCallback = (state: {value: number, ...}) => mixed; @@ -23,12 +24,15 @@ let _uniqueId = 1; // Note(vjeux): this would be better as an interface but flow doesn't // support them yet -class AnimatedNode { +export default class AnimatedNode { _listeners: {[key: string]: ValueListenerCallback, ...}; _platformConfig: ?PlatformConfig; __nativeAnimatedValueListener: ?any; __attach(): void {} __detach(): void { + if (ReactNativeFeatureFlags.removeListenersOnDetach()) { + this.removeAllListeners(); + } if (this.__isNative && this.__nativeTag != null) { NativeAnimatedHelper.API.dropAnimatedNode(this.__nativeTag); this.__nativeTag = undefined; @@ -53,7 +57,7 @@ class AnimatedNode { this._listeners = {}; } - __makeNative(platformConfig: ?PlatformConfig) { + __makeNative(platformConfig: ?PlatformConfig): void { if (!this.__isNative) { throw new Error('This node cannot be made a "native" animated node'); } @@ -193,5 +197,3 @@ class AnimatedNode { this._platformConfig = platformConfig; } } - -module.exports = AnimatedNode; diff --git a/Libraries/Animated/nodes/AnimatedProps.js b/Libraries/Animated/nodes/AnimatedProps.js index baf5c395c992e4..ef15cdf13120f6 100644 --- a/Libraries/Animated/nodes/AnimatedProps.js +++ b/Libraries/Animated/nodes/AnimatedProps.js @@ -10,17 +10,16 @@ 'use strict'; -const {AnimatedEvent} = require('../AnimatedEvent'); -const AnimatedNode = require('./AnimatedNode'); -const AnimatedStyle = require('./AnimatedStyle'); -const NativeAnimatedHelper = require('../NativeAnimatedHelper'); -const ReactNative = require('../../Renderer/shims/ReactNative'); - -const invariant = require('invariant'); - import type {PlatformConfig} from '../AnimatedPlatformConfig'; -class AnimatedProps extends AnimatedNode { +import {findNodeHandle} from '../../ReactNative/RendererProxy'; +import {AnimatedEvent} from '../AnimatedEvent'; +import NativeAnimatedHelper from '../NativeAnimatedHelper'; +import AnimatedNode from './AnimatedNode'; +import AnimatedStyle from './AnimatedStyle'; +import invariant from 'invariant'; + +export default class AnimatedProps extends AnimatedNode { _props: Object; _animatedView: any; _callback: () => void; @@ -38,26 +37,23 @@ class AnimatedProps extends AnimatedNode { } __getValue(): Object { - const props = {}; + const props: {[string]: any | ((...args: any) => void)} = {}; for (const key in this._props) { const value = this._props[key]; if (value instanceof AnimatedNode) { - if (!value.__isNative || value instanceof AnimatedStyle) { - // We cannot use value of natively driven nodes this way as the value we have access from - // JS may not be up to date. - props[key] = value.__getValue(); - } + props[key] = value.__getValue(); } else if (value instanceof AnimatedEvent) { props[key] = value.__getHandler(); } else { props[key] = value; } } + return props; } __getAnimatedValue(): Object { - const props = {}; + const props: {[string]: any} = {}; for (const key in this._props) { const value = this._props[key]; if (value instanceof AnimatedNode) { @@ -126,9 +122,7 @@ class AnimatedProps extends AnimatedNode { __connectAnimatedView(): void { invariant(this.__isNative, 'Expected node to be marked as "native"'); - const nativeViewTag: ?number = ReactNative.findNodeHandle( - this._animatedView, - ); + const nativeViewTag: ?number = findNodeHandle(this._animatedView); invariant( nativeViewTag != null, 'Unable to locate attached view in the native tree', @@ -141,9 +135,7 @@ class AnimatedProps extends AnimatedNode { __disconnectAnimatedView(): void { invariant(this.__isNative, 'Expected node to be marked as "native"'); - const nativeViewTag: ?number = ReactNative.findNodeHandle( - this._animatedView, - ); + const nativeViewTag: ?number = findNodeHandle(this._animatedView); invariant( nativeViewTag != null, 'Unable to locate attached view in the native tree', @@ -165,7 +157,7 @@ class AnimatedProps extends AnimatedNode { } __getNativeConfig(): Object { - const propsConfig = {}; + const propsConfig: {[string]: number} = {}; for (const propKey in this._props) { const value = this._props[propKey]; if (value instanceof AnimatedNode) { @@ -179,5 +171,3 @@ class AnimatedProps extends AnimatedNode { }; } } - -module.exports = AnimatedProps; diff --git a/Libraries/Animated/nodes/AnimatedStyle.js b/Libraries/Animated/nodes/AnimatedStyle.js index 6b6761ba256bbf..7cb11bb1b55679 100644 --- a/Libraries/Animated/nodes/AnimatedStyle.js +++ b/Libraries/Animated/nodes/AnimatedStyle.js @@ -10,21 +10,20 @@ 'use strict'; -const AnimatedNode = require('./AnimatedNode'); -const AnimatedTransform = require('./AnimatedTransform'); -const AnimatedWithChildren = require('./AnimatedWithChildren'); -const NativeAnimatedHelper = require('../NativeAnimatedHelper'); - -const flattenStyle = require('../../StyleSheet/flattenStyle'); - import type {PlatformConfig} from '../AnimatedPlatformConfig'; -class AnimatedStyle extends AnimatedWithChildren { +import flattenStyle from '../../StyleSheet/flattenStyle'; +import NativeAnimatedHelper from '../NativeAnimatedHelper'; +import AnimatedNode from './AnimatedNode'; +import AnimatedTransform from './AnimatedTransform'; +import AnimatedWithChildren from './AnimatedWithChildren'; + +export default class AnimatedStyle extends AnimatedWithChildren { _style: Object; constructor(style: any) { super(); - style = flattenStyle(style) || {}; + style = flattenStyle(style) || ({}: {[string]: any}); if (style.transform) { style = { ...style, @@ -35,16 +34,12 @@ class AnimatedStyle extends AnimatedWithChildren { } // Recursively get values for nested styles (like iOS's shadowOffset) - _walkStyleAndGetValues(style: any) { - const updatedStyle = {}; + _walkStyleAndGetValues(style: any): {[string]: any | {...}} { + const updatedStyle: {[string]: any | {...}} = {}; for (const key in style) { const value = style[key]; if (value instanceof AnimatedNode) { - if (!value.__isNative) { - // We cannot use value of natively driven nodes this way as the value we have access from - // JS may not be up to date. - updatedStyle[key] = value.__getValue(); - } + updatedStyle[key] = value.__getValue(); } else if (value && !Array.isArray(value) && typeof value === 'object') { // Support animating nested values (for example: shadowOffset.height) updatedStyle[key] = this._walkStyleAndGetValues(value); @@ -60,8 +55,8 @@ class AnimatedStyle extends AnimatedWithChildren { } // Recursively get animated values for nested styles (like iOS's shadowOffset) - _walkStyleAndGetAnimatedValues(style: any) { - const updatedStyle = {}; + _walkStyleAndGetAnimatedValues(style: any): {[string]: any | {...}} { + const updatedStyle: {[string]: any | {...}} = {}; for (const key in style) { const value = style[key]; if (value instanceof AnimatedNode) { @@ -108,7 +103,7 @@ class AnimatedStyle extends AnimatedWithChildren { } __getNativeConfig(): Object { - const styleConfig = {}; + const styleConfig: {[string]: ?number} = {}; for (const styleKey in this._style) { if (this._style[styleKey] instanceof AnimatedNode) { const style = this._style[styleKey]; @@ -125,5 +120,3 @@ class AnimatedStyle extends AnimatedWithChildren { }; } } - -module.exports = AnimatedStyle; diff --git a/Libraries/Animated/nodes/AnimatedSubtraction.js b/Libraries/Animated/nodes/AnimatedSubtraction.js index 3c8eb158fd05db..d9a423b4cbbc34 100644 --- a/Libraries/Animated/nodes/AnimatedSubtraction.js +++ b/Libraries/Animated/nodes/AnimatedSubtraction.js @@ -10,15 +10,15 @@ 'use strict'; -const AnimatedInterpolation = require('./AnimatedInterpolation'); -const AnimatedNode = require('./AnimatedNode'); -const AnimatedValue = require('./AnimatedValue'); -const AnimatedWithChildren = require('./AnimatedWithChildren'); - -import type {InterpolationConfigType} from './AnimatedInterpolation'; import type {PlatformConfig} from '../AnimatedPlatformConfig'; +import type {InterpolationConfigType} from './AnimatedInterpolation'; +import type AnimatedNode from './AnimatedNode'; -class AnimatedSubtraction extends AnimatedWithChildren { +import AnimatedInterpolation from './AnimatedInterpolation'; +import AnimatedValue from './AnimatedValue'; +import AnimatedWithChildren from './AnimatedWithChildren'; + +export default class AnimatedSubtraction extends AnimatedWithChildren { _a: AnimatedNode; _b: AnimatedNode; @@ -38,7 +38,9 @@ class AnimatedSubtraction extends AnimatedWithChildren { return this._a.__getValue() - this._b.__getValue(); } - interpolate(config: InterpolationConfigType): AnimatedInterpolation { + interpolate( + config: InterpolationConfigType, + ): AnimatedInterpolation { return new AnimatedInterpolation(this, config); } @@ -60,5 +62,3 @@ class AnimatedSubtraction extends AnimatedWithChildren { }; } } - -module.exports = AnimatedSubtraction; diff --git a/Libraries/Animated/nodes/AnimatedTracking.js b/Libraries/Animated/nodes/AnimatedTracking.js index e8f74eaa54ac75..bfaeafed47c413 100644 --- a/Libraries/Animated/nodes/AnimatedTracking.js +++ b/Libraries/Animated/nodes/AnimatedTracking.js @@ -10,17 +10,14 @@ 'use strict'; -const AnimatedValue = require('./AnimatedValue'); -const AnimatedNode = require('./AnimatedNode'); -const { - generateNewAnimationId, - shouldUseNativeDriver, -} = require('../NativeAnimatedHelper'); - import type {PlatformConfig} from '../AnimatedPlatformConfig'; import type {EndCallback} from '../animations/Animation'; +import type AnimatedValue from './AnimatedValue'; + +import NativeAnimatedHelper from '../NativeAnimatedHelper'; +import AnimatedNode from './AnimatedNode'; -class AnimatedTracking extends AnimatedNode { +export default class AnimatedTracking extends AnimatedNode { _value: AnimatedValue; _parent: AnimatedNode; _callback: ?EndCallback; @@ -40,7 +37,8 @@ class AnimatedTracking extends AnimatedNode { this._parent = parent; this._animationClass = animationClass; this._animationConfig = animationConfig; - this._useNativeDriver = shouldUseNativeDriver(animationConfig); + this._useNativeDriver = + NativeAnimatedHelper.shouldUseNativeDriver(animationConfig); this._callback = callback; this.__attach(); } @@ -93,12 +91,10 @@ class AnimatedTracking extends AnimatedNode { const animationConfig = animation.__getNativeAnimationConfig(); return { type: 'tracking', - animationId: generateNewAnimationId(), + animationId: NativeAnimatedHelper.generateNewAnimationId(), animationConfig, toValue: this._parent.__getNativeTag(), value: this._value.__getNativeTag(), }; } } - -module.exports = AnimatedTracking; diff --git a/Libraries/Animated/nodes/AnimatedTransform.js b/Libraries/Animated/nodes/AnimatedTransform.js index 0fee6b07787381..3b553c9a3d368f 100644 --- a/Libraries/Animated/nodes/AnimatedTransform.js +++ b/Libraries/Animated/nodes/AnimatedTransform.js @@ -10,13 +10,13 @@ 'use strict'; -const AnimatedNode = require('./AnimatedNode'); -const AnimatedWithChildren = require('./AnimatedWithChildren'); -const NativeAnimatedHelper = require('../NativeAnimatedHelper'); - import type {PlatformConfig} from '../AnimatedPlatformConfig'; -class AnimatedTransform extends AnimatedWithChildren { +import NativeAnimatedHelper from '../NativeAnimatedHelper'; +import AnimatedNode from './AnimatedNode'; +import AnimatedWithChildren from './AnimatedWithChildren'; + +export default class AnimatedTransform extends AnimatedWithChildren { _transforms: $ReadOnlyArray; constructor(transforms: $ReadOnlyArray) { @@ -37,34 +37,11 @@ class AnimatedTransform extends AnimatedWithChildren { } __getValue(): $ReadOnlyArray { - return this._transforms.map(transform => { - const result = {}; - for (const key in transform) { - const value = transform[key]; - if (value instanceof AnimatedNode) { - result[key] = value.__getValue(); - } else { - result[key] = value; - } - } - return result; - }); + return this._get(animatedNode => animatedNode.__getValue()); } __getAnimatedValue(): $ReadOnlyArray { - return this._transforms.map(transform => { - const result = {}; - for (const key in transform) { - const value = transform[key]; - if (value instanceof AnimatedNode) { - result[key] = value.__getAnimatedValue(); - } else { - // All transform components needed to recompose matrix - result[key] = value; - } - } - return result; - }); + return this._get(animatedNode => animatedNode.__getAnimatedValue()); } __attach(): void { @@ -118,6 +95,36 @@ class AnimatedTransform extends AnimatedWithChildren { transforms: transConfigs, }; } -} -module.exports = AnimatedTransform; + _get(getter: AnimatedNode => any): $ReadOnlyArray { + return this._transforms.map(transform => { + const result: {[string]: any} = {}; + for (const key in transform) { + const value = transform[key]; + if (value instanceof AnimatedNode) { + result[key] = getter(value); + } else if (Array.isArray(value)) { + result[key] = value.map(element => { + if (element instanceof AnimatedNode) { + return getter(element); + } else { + return element; + } + }); + } else if (typeof value === 'object') { + result[key] = {}; + for (const [nestedKey, nestedValue] of Object.entries(value)) { + if (nestedValue instanceof AnimatedNode) { + result[key][nestedKey] = getter(nestedValue); + } else { + result[key][nestedKey] = nestedValue; + } + } + } else { + result[key] = value; + } + } + return result; + }); + } +} diff --git a/Libraries/Animated/nodes/AnimatedValue.js b/Libraries/Animated/nodes/AnimatedValue.js index c829d3e5952513..f20307b310e26e 100644 --- a/Libraries/Animated/nodes/AnimatedValue.js +++ b/Libraries/Animated/nodes/AnimatedValue.js @@ -10,16 +10,20 @@ 'use strict'; -const AnimatedInterpolation = require('./AnimatedInterpolation'); -const AnimatedWithChildren = require('./AnimatedWithChildren'); -const InteractionManager = require('../../Interaction/InteractionManager'); -const NativeAnimatedHelper = require('../NativeAnimatedHelper'); - -import type AnimatedNode from './AnimatedNode'; import type Animation, {EndCallback} from '../animations/Animation'; import type {InterpolationConfigType} from './AnimatedInterpolation'; +import type AnimatedNode from './AnimatedNode'; import type AnimatedTracking from './AnimatedTracking'; +import InteractionManager from '../../Interaction/InteractionManager'; +import NativeAnimatedHelper from '../NativeAnimatedHelper'; +import AnimatedInterpolation from './AnimatedInterpolation'; +import AnimatedWithChildren from './AnimatedWithChildren'; + +export type AnimatedValueConfig = $ReadOnly<{ + useNativeDriver: boolean, +}>; + const NativeAnimatedAPI = NativeAnimatedHelper.API; /** @@ -45,7 +49,7 @@ const NativeAnimatedAPI = NativeAnimatedHelper.API; * transform which can receive values from multiple parents. */ function _flush(rootNode: AnimatedValue): void { - const animatedStyles = new Set(); + const animatedStyles = new Set(); function findAnimatedStyles(node: AnimatedValue | AnimatedNode) { /* $FlowFixMe[prop-missing] (>=0.68.0 site=react_native_fb) This comment * suppresses an error found when Flow v0.68 was deployed. To see the error @@ -80,14 +84,15 @@ function _executeAsAnimatedBatch(id: string, operation: () => void) { * * See https://reactnative.dev/docs/animatedvalue */ -class AnimatedValue extends AnimatedWithChildren { +export default class AnimatedValue extends AnimatedWithChildren { _value: number; _startingValue: number; _offset: number; _animation: ?Animation; _tracking: ?AnimatedTracking; - constructor(value: number) { + // $FlowFixMe[missing-local-annot] + constructor(value: number, config?: ?AnimatedValueConfig) { super(); if (typeof value !== 'number') { throw new Error('AnimatedValue: Attempting to set value to undefined'); @@ -95,6 +100,9 @@ class AnimatedValue extends AnimatedWithChildren { this._startingValue = this._value = value; this._offset = 0; this._animation = null; + if (config && config.useNativeDriver) { + this.__makeNative(); + } } __detach() { @@ -127,9 +135,9 @@ class AnimatedValue extends AnimatedWithChildren { !this.__isNative /* don't perform a flush for natively driven values */, ); if (this.__isNative) { - _executeAsAnimatedBatch(this.__getNativeTag().toString(), () => { - NativeAnimatedAPI.setAnimatedNodeValue(this.__getNativeTag(), value); - }); + _executeAsAnimatedBatch(this.__getNativeTag().toString(), () => + NativeAnimatedAPI.setAnimatedNodeValue(this.__getNativeTag(), value), + ); } } @@ -219,7 +227,9 @@ class AnimatedValue extends AnimatedWithChildren { * Interpolates the value before updating the property, e.g. mapping 0-1 to * 0-10. */ - interpolate(config: InterpolationConfigType): AnimatedInterpolation { + interpolate( + config: InterpolationConfigType, + ): AnimatedInterpolation { return new AnimatedInterpolation(this, config); } @@ -294,5 +304,3 @@ class AnimatedValue extends AnimatedWithChildren { }; } } - -module.exports = AnimatedValue; diff --git a/Libraries/Animated/nodes/AnimatedValueXY.js b/Libraries/Animated/nodes/AnimatedValueXY.js index bc1f80fe2941a3..dc24a674bba4a7 100644 --- a/Libraries/Animated/nodes/AnimatedValueXY.js +++ b/Libraries/Animated/nodes/AnimatedValueXY.js @@ -10,11 +10,15 @@ 'use strict'; -const AnimatedValue = require('./AnimatedValue'); -const AnimatedWithChildren = require('./AnimatedWithChildren'); +import type {PlatformConfig} from '../AnimatedPlatformConfig'; -const invariant = require('invariant'); +import AnimatedValue from './AnimatedValue'; +import AnimatedWithChildren from './AnimatedWithChildren'; +import invariant from 'invariant'; +export type AnimatedValueXYConfig = $ReadOnly<{ + useNativeDriver: boolean, +}>; type ValueXYListenerCallback = (value: { x: number, y: number, @@ -29,7 +33,7 @@ let _uniqueId = 1; * * See https://reactnative.dev/docs/animatedvaluexy */ -class AnimatedValueXY extends AnimatedWithChildren { +export default class AnimatedValueXY extends AnimatedWithChildren { x: AnimatedValue; y: AnimatedValue; _listeners: { @@ -47,6 +51,7 @@ class AnimatedValueXY extends AnimatedWithChildren { +y: number | AnimatedValue, ... }, + config?: ?AnimatedValueXYConfig, ) { super(); const value: any = valueIn || {x: 0, y: 0}; // @flowfixme: shouldn't need `: any` @@ -63,6 +68,9 @@ class AnimatedValueXY extends AnimatedWithChildren { this.y = value.y; } this._listeners = {}; + if (config && config.useNativeDriver) { + this.__makeNative(); + } } /** @@ -168,7 +176,7 @@ class AnimatedValueXY extends AnimatedWithChildren { */ addListener(callback: ValueXYListenerCallback): string { const id = String(_uniqueId++); - const jointCallback = ({value: number}) => { + const jointCallback = ({value: number}: any) => { callback(this.__getValue()); }; this._listeners[id] = { @@ -221,6 +229,22 @@ class AnimatedValueXY extends AnimatedWithChildren { getTranslateTransform(): Array<{[key: string]: AnimatedValue, ...}> { return [{translateX: this.x}, {translateY: this.y}]; } -} -module.exports = AnimatedValueXY; + __attach(): void { + this.x.__addChild(this); + this.y.__addChild(this); + super.__attach(); + } + + __detach(): void { + this.x.__removeChild(this); + this.y.__removeChild(this); + super.__detach(); + } + + __makeNative(platformConfig: ?PlatformConfig) { + this.x.__makeNative(platformConfig); + this.y.__makeNative(platformConfig); + super.__makeNative(platformConfig); + } +} diff --git a/Libraries/Animated/nodes/AnimatedWithChildren.js b/Libraries/Animated/nodes/AnimatedWithChildren.js index 435365d1f6ee6d..ac4ade64612f9d 100644 --- a/Libraries/Animated/nodes/AnimatedWithChildren.js +++ b/Libraries/Animated/nodes/AnimatedWithChildren.js @@ -11,10 +11,11 @@ 'use strict'; import type {PlatformConfig} from '../AnimatedPlatformConfig'; -const AnimatedNode = require('./AnimatedNode'); -const NativeAnimatedHelper = require('../NativeAnimatedHelper'); -class AnimatedWithChildren extends AnimatedNode { +import NativeAnimatedHelper from '../NativeAnimatedHelper'; +import AnimatedNode from './AnimatedNode'; + +export default class AnimatedWithChildren extends AnimatedNode { _children: Array; constructor() { @@ -85,5 +86,3 @@ class AnimatedWithChildren extends AnimatedNode { } } } - -module.exports = AnimatedWithChildren; diff --git a/Libraries/Animated/useAnimatedProps.js b/Libraries/Animated/useAnimatedProps.js index 8629fd4ebdf915..1b7d81009fd885 100644 --- a/Libraries/Animated/useAnimatedProps.js +++ b/Libraries/Animated/useAnimatedProps.js @@ -10,10 +10,10 @@ 'use strict'; -import AnimatedProps from './nodes/AnimatedProps'; -import {AnimatedEvent} from './AnimatedEvent'; import useRefEffect from '../Utilities/useRefEffect'; +import {AnimatedEvent} from './AnimatedEvent'; import NativeAnimatedHelper from './NativeAnimatedHelper'; +import AnimatedProps from './nodes/AnimatedProps'; import { useCallback, useEffect, @@ -21,7 +21,6 @@ import { useMemo, useReducer, useRef, - useState, } from 'react'; type ReducedProps = { @@ -31,12 +30,10 @@ type ReducedProps = { }; type CallbackRef = T => mixed; -let animatedComponentNextId = 1; - export default function useAnimatedProps( props: TProps, ): [ReducedProps, CallbackRef] { - const [, scheduleUpdate] = useReducer(count => count + 1, 0); + const [, scheduleUpdate] = useReducer(count => count + 1, 0); const onUpdateRef = useRef void>(null); // TODO: Only invalidate `node` if animated props or `style` change. In the @@ -63,7 +60,7 @@ export default function useAnimatedProps( // But there is no way to transparently compose three separate callback refs, // so we just combine them all into one for now. const refEffect = useCallback( - instance => { + (instance: TInstance) => { // NOTE: This may be called more often than necessary (e.g. when `props` // changes), but `setNativeView` already optimizes for that. node.setNativeView(instance); @@ -82,6 +79,7 @@ export default function useAnimatedProps( scheduleUpdate(); } else if (!node.__isNative) { // $FlowIgnore[not-a-function] - Assume it's still a function. + // $FlowFixMe[incompatible-use] instance.setNativeProps(node.__getAnimatedValue()); } else { throw new Error( @@ -140,16 +138,11 @@ function useAnimatedPropsLifecycle(node: AnimatedProps): void { const prevNodeRef = useRef(null); const isUnmountingRef = useRef(false); - const [animatedComponentId] = useState( - () => `${animatedComponentNextId++}:animatedComponent`, - ); - - useLayoutEffect(() => { - NativeAnimatedHelper.API.setWaitingForIdentifier(animatedComponentId); - }); - useEffect(() => { - NativeAnimatedHelper.API.unsetWaitingForIdentifier(animatedComponentId); + // It is ok for multiple components to call `flushQueue` because it noops + // if the queue is empty. When multiple animated components are mounted at + // the same time. Only first component flushes the queue and the others will noop. + NativeAnimatedHelper.API.flushQueue(); }); useLayoutEffect(() => { diff --git a/Libraries/Animated/useAnimatedValue.d.ts b/Libraries/Animated/useAnimatedValue.d.ts new file mode 100644 index 00000000000000..69e5a59fcf0951 --- /dev/null +++ b/Libraries/Animated/useAnimatedValue.d.ts @@ -0,0 +1,15 @@ +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @format + */ + +import type {Animated} from './Animated'; + +export function useAnimatedValue( + initialValue: number, + config?: Animated.AnimatedConfig, +): Animated.Value; diff --git a/Libraries/Animated/useAnimatedValue.js b/Libraries/Animated/useAnimatedValue.js new file mode 100644 index 00000000000000..0a430ed5c3c071 --- /dev/null +++ b/Libraries/Animated/useAnimatedValue.js @@ -0,0 +1,25 @@ +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @flow strict-local + * @format + */ + +import type {AnimatedValueConfig} from './nodes/AnimatedValue'; + +import Animated from './Animated'; +import {useRef} from 'react'; + +export default function useAnimatedValue( + initialValue: number, + config?: ?AnimatedValueConfig, +): Animated.Value { + const ref = useRef(null); + if (ref.current == null) { + ref.current = new Animated.Value(initialValue, config); + } + return ref.current; +} diff --git a/Libraries/AppDelegate/RCTAppDelegate.h b/Libraries/AppDelegate/RCTAppDelegate.h new file mode 100644 index 00000000000000..a4e6b2755d6e5a --- /dev/null +++ b/Libraries/AppDelegate/RCTAppDelegate.h @@ -0,0 +1,133 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#import +#import +#import // [macOS] + +#if RCT_NEW_ARCH_ENABLED +// When the new architecture is enabled, the RCTAppDelegate imports some additional headers +#import +#import +#import + +#endif + +/** + * The RCTAppDelegate is an utility class that implements some base configurations for all the React Native apps. + * It is not mandatory to use it, but it could simplify your AppDelegate code. + * + * To use it, you just need to make your AppDelegate a subclass of RCTAppDelegate: + * + * ```objc + * #import + * @interface AppDelegate: RCTAppDelegate + * @end + * ``` + * + * All the methods implemented by the RCTAppDelegate can be overriden by your AppDelegate if you need to provide a + custom implementation. + * If you need to customize the default implementation, you can invoke `[super ]` and use the returned + object. + * + * Overridable methods + * Shared: + * - (RCTBridge *)createBridgeWithDelegate:(id)delegate launchOptions:(NSDictionary + *)launchOptions; + * - (UIView *)createRootViewWithBridge:(RCTBridge *)bridge moduleName:(NSString*)moduleName initProps:(NSDictionary + *)initProps; + * - (UIViewController *)createRootViewController; + * New Architecture: + * - (BOOL)concurrentRootEnabled + * - (BOOL)turboModuleEnabled; + * - (BOOL)fabricEnabled; + * - (NSDictionary *)prepareInitialProps + * - (Class)getModuleClassFromName:(const char *)name + * - (std::shared_ptr)getTurboModule:(const std::string &)name + jsInvoker:(std::shared_ptr)jsInvoker + * - (std::shared_ptr)getTurboModule:(const std::string &)name + initParams: + (const facebook::react::ObjCTurboModule::InitParams &)params + * - (id)getModuleInstanceFromClass:(Class)moduleClass + */ +#if !TARGET_OS_OSX // [macOS] +@interface RCTAppDelegate : UIResponder +#else // [macOS +@interface RCTAppDelegate : NSResponder +#endif // macOS] +/// The window object, used to render the UViewControllers +@property (nonatomic, strong) RCTPlatformWindow *window; // [macOS] +@property (nonatomic, strong) RCTBridge *bridge; +@property (nonatomic, strong) NSString *moduleName; + +/** + * It creates a `RCTBridge` using a delegate and some launch options. + * By default, it is invoked passing `self` as a delegate. + * You can override this function to customize the logic that creates the RCTBridge + * + * @parameter: delegate - an object that implements the `RCTBridgeDelegate` protocol. + * @parameter: launchOptions - a dictionary with a set of options. + * + * @returns: a newly created instance of RCTBridge. + */ +- (RCTBridge *)createBridgeWithDelegate:(id)delegate launchOptions:(NSDictionary *)launchOptions; + +/** + * It creates a `UIView` starting from a bridge, a module name and a set of initial properties. + * By default, it is invoked using the bridge created by `createBridgeWithDelegate:launchOptions` and + * the name in the `self.moduleName` variable. + * You can override this function to customize the logic that creates the Root View. + * + * @parameter: bridge - an instance of the `RCTBridge` object. + * @parameter: moduleName - the name of the app, used by Metro to resolve the module. + * @parameter: initProps - a set of initial properties. + * + * @returns: a UIView properly configured with a bridge for React Native. + */ +- (RCTPlatformView *)createRootViewWithBridge:(RCTBridge *)bridge // [macOS] + moduleName:(NSString *)moduleName + initProps:(NSDictionary *)initProps; + +/** + * It creates the RootViewController. + * By default, it creates a new instance of a `UIViewController`. + * You can override it to provide your own initial ViewController. + * + * @return: an instance of `UIViewController`. + */ +- (UIViewController *)createRootViewController; + +@end + +#if RCT_NEW_ARCH_ENABLED +/// Extension that makes the RCTAppDelegate conform to New Architecture delegates +@interface RCTAppDelegate () + +/// The TurboModule manager +@property (nonatomic, strong) RCTTurboModuleManager *turboModuleManager; +@property (nonatomic, strong) RCTSurfacePresenterBridgeAdapter *bridgeAdapter; + +/// This method controls whether the `concurrentRoot` feature of React18 is turned on or off. +/// +/// @see: https://reactjs.org/blog/2022/03/29/react-v18.html +/// @note: This requires to be rendering on Fabric (i.e. on the New Architecture). +/// @return: `true` if the `concurrentRoot` feature is enabled. Otherwise, it returns `false`. +- (BOOL)concurrentRootEnabled; + +/// This method controls whether the `turboModules` feature of the New Architecture is turned on or off. +/// +/// @note: This is required to be rendering on Fabric (i.e. on the New Architecture). +/// @return: `true` if the Turbo Native Module are enabled. Otherwise, it returns `false`. +- (BOOL)turboModuleEnabled; + +/// This method controls whether the App will use the Fabric renderer of the New Architecture or not. +/// +/// @return: `true` if the Fabric Renderer is enabled. Otherwise, it returns `false`. +- (BOOL)fabricEnabled; + +@end +#endif diff --git a/Libraries/AppDelegate/RCTAppDelegate.mm b/Libraries/AppDelegate/RCTAppDelegate.mm new file mode 100644 index 00000000000000..438f53b8ec1f7b --- /dev/null +++ b/Libraries/AppDelegate/RCTAppDelegate.mm @@ -0,0 +1,190 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#import "RCTAppDelegate.h" +#import +#import + +#if RCT_NEW_ARCH_ENABLED +#import +#import +#import +#import + +static NSString *const kRNConcurrentRoot = @"concurrentRoot"; + +@interface RCTAppDelegate () { + std::shared_ptr _reactNativeConfig; + facebook::react::ContextContainer::Shared _contextContainer; +} +@end + +#endif + +@implementation RCTAppDelegate + +#if !TARGET_OS_OSX // [macOS] +- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions +{ +#else // [macOS +- (void)applicationDidFinishLaunching:(NSNotification *)notification +{ + NSApplication *application = [notification object]; + NSDictionary *launchOptions = [notification userInfo]; +#endif // macOS] + BOOL enableTM = NO; +#if RCT_NEW_ARCH_ENABLED + enableTM = self.turboModuleEnabled; +#endif + + RCTAppSetupPrepareApp(application, enableTM); + + if (!self.bridge) { + self.bridge = [self createBridgeWithDelegate:self launchOptions:launchOptions]; + } +#if RCT_NEW_ARCH_ENABLED + _contextContainer = std::make_shared(); + _reactNativeConfig = std::make_shared(); + _contextContainer->insert("ReactNativeConfig", _reactNativeConfig); + self.bridgeAdapter = [[RCTSurfacePresenterBridgeAdapter alloc] initWithBridge:self.bridge + contextContainer:_contextContainer]; + self.bridge.surfacePresenter = self.bridgeAdapter.surfacePresenter; +#endif + + NSDictionary *initProps = [self prepareInitialProps]; + RCTPlatformView *rootView = [self createRootViewWithBridge:self.bridge moduleName:self.moduleName initProps:initProps]; // [macOS] + +#if !TARGET_OS_OSX // [macOS] + if (@available(iOS 13.0, *)) { + rootView.backgroundColor = [UIColor systemBackgroundColor]; + } else { + rootView.backgroundColor = [UIColor whiteColor]; + } +#else // [macOS + rootView.layer.backgroundColor = [[NSColor windowBackgroundColor] CGColor]; +#endif // macOS] + +#if !TARGET_OS_OSX // [macOS + self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds]; + UIViewController *rootViewController = [self createRootViewController]; + rootViewController.view = rootView; + self.window.rootViewController = rootViewController; + [self.window makeKeyAndVisible]; + return YES; +#else // [macOS + self.window = [[NSWindow alloc] init]; + NSViewController *rootViewController = [self createRootViewController]; + rootViewController.view = rootView; + self.window.contentViewController = rootViewController; + [self.window makeKeyAndOrderFront:self]; +#endif // macOS] +} + +- (NSURL *)sourceURLForBridge:(RCTBridge *)bridge +{ + [NSException raise:@"RCTBridgeDelegate::sourceURLForBridge not implemented" + format:@"Subclasses must implement a valid sourceURLForBridge method"]; + return nil; +} + +- (BOOL)concurrentRootEnabled +{ + [NSException raise:@"concurrentRootEnabled not implemented" + format:@"Subclasses must implement a valid concurrentRootEnabled method"]; + return true; +} + +- (NSDictionary *)prepareInitialProps +{ + NSMutableDictionary *initProps = [NSMutableDictionary new]; + +#ifdef RCT_NEW_ARCH_ENABLED + initProps[kRNConcurrentRoot] = @([self concurrentRootEnabled]); +#endif + + return initProps; +} + +- (RCTBridge *)createBridgeWithDelegate:(id)delegate launchOptions:(NSDictionary *)launchOptions +{ + return [[RCTBridge alloc] initWithDelegate:delegate launchOptions:launchOptions]; +} + +- (RCTPlatformView *)createRootViewWithBridge:(RCTBridge *)bridge // [macOS] + moduleName:(NSString *)moduleName + initProps:(NSDictionary *)initProps +{ + BOOL enableFabric = NO; +#if RCT_NEW_ARCH_ENABLED + enableFabric = self.fabricEnabled; +#endif + return RCTAppSetupDefaultRootView(bridge, moduleName, initProps, enableFabric); +} + +#if !TARGET_OS_OSX // [macOS] +- (UIViewController *)createRootViewController +{ + return [UIViewController new]; +} +#else // [macOS +- (NSViewController *)createRootViewController +{ + return [NSViewController new]; +} +#endif // macOS] + +#if RCT_NEW_ARCH_ENABLED +#pragma mark - RCTCxxBridgeDelegate + +- (std::unique_ptr)jsExecutorFactoryForBridge:(RCTBridge *)bridge +{ + self.turboModuleManager = [[RCTTurboModuleManager alloc] initWithBridge:bridge + delegate:self + jsInvoker:bridge.jsCallInvoker]; + return RCTAppSetupDefaultJsExecutorFactory(bridge, _turboModuleManager); +} + +#pragma mark RCTTurboModuleManagerDelegate + +- (Class)getModuleClassFromName:(const char *)name +{ + return RCTCoreModulesClassProvider(name); +} + +- (std::shared_ptr)getTurboModule:(const std::string &)name + jsInvoker:(std::shared_ptr)jsInvoker +{ + return nullptr; +} + +- (std::shared_ptr)getTurboModule:(const std::string &)name + initParams: + (const facebook::react::ObjCTurboModule::InitParams &)params +{ + return nullptr; +} + +- (id)getModuleInstanceFromClass:(Class)moduleClass +{ + return RCTAppSetupDefaultModuleFromClass(moduleClass); +} + +#pragma mark - New Arch Enabled settings + +- (BOOL)turboModuleEnabled +{ + return YES; +} + +- (BOOL)fabricEnabled +{ + return YES; +} + +#endif + +@end diff --git a/Libraries/AppDelegate/React-RCTAppDelegate.podspec b/Libraries/AppDelegate/React-RCTAppDelegate.podspec new file mode 100644 index 00000000000000..31c094671b3a99 --- /dev/null +++ b/Libraries/AppDelegate/React-RCTAppDelegate.podspec @@ -0,0 +1,73 @@ +# Copyright (c) Meta Platforms, Inc. and affiliates. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +require "json" + +package = JSON.parse(File.read(File.join(__dir__, "..", "..", "package.json"))) +version = package['version'] + +source = { :git => 'https://github.com/facebook/react-native.git' } +if version == '1000.0.0' + # This is an unpublished version, use the latest commit hash of the react-native repo, which we’re presumably in. + source[:commit] = `git rev-parse HEAD`.strip if system("git rev-parse --git-dir > /dev/null 2>&1") +else + source[:tag] = "v#{version}" +end + +folly_flags = '-DFOLLY_NO_CONFIG -DFOLLY_MOBILE=1 -DFOLLY_USE_LIBCPP=1' +folly_compiler_flags = folly_flags + ' ' + '-Wno-comma -Wno-shorten-64-to-32' + +new_arch_enabled_flag="RCT_NEW_ARCH_ENABLED" +is_new_arch_enabled = ENV[new_arch_enabled_flag] == "1" +other_cflags = "$(inherited) -DRN_FABRIC_ENABLED " + folly_flags + (is_new_arch_enabled ? " -D"+"RCT_NEW_ARCH_ENABLED" : "") + +use_hermes = ENV['USE_HERMES'] == '1' + +header_search_paths = [ + "$(PODS_TARGET_SRCROOT)/ReactCommon", + "$(PODS_ROOT)/Headers/Private/React-Core", + "$(PODS_ROOT)/boost", + "$(PODS_ROOT)/DoubleConversion", + "$(PODS_ROOT)/RCT-Folly", + "${PODS_ROOT}/Headers/Public/FlipperKit", + "$(PODS_ROOT)/Headers/Public/ReactCommon", + "$(PODS_ROOT)/Headers/Public/React-RCTFabric" +].concat(use_hermes ? [ + "$(PODS_ROOT)/Headers/Public/React-hermes", + "$(PODS_ROOT)/Headers/Public/hermes-engine" +] : []).map{|p| "\"#{p}\""}.join(" ") + +Pod::Spec.new do |s| + s.name = "React-RCTAppDelegate" + s.version = version + s.summary = "An utility library to simplify common operations for the New Architecture" + s.homepage = "https://reactnative.dev/" + s.documentation_url = "https://reactnative.dev/docs/actionsheetios" + s.license = package["license"] + s.author = "Facebook, Inc. and its affiliates" + s.platforms = { :ios => "12.4", :osx => "10.15" } # [macOS] + s.source = source + s.source_files = "**/*.{c,h,m,mm,S,cpp}" + + # This guard prevent to install the dependencies when we run `pod install` in the old architecture. + s.compiler_flags = other_cflags + s.pod_target_xcconfig = { + "HEADER_SEARCH_PATHS" => header_search_paths, + "OTHER_CPLUSPLUSFLAGS" => other_cflags, + "CLANG_CXX_LANGUAGE_STANDARD" => "c++17" + } + s.user_target_xcconfig = { "HEADER_SEARCH_PATHS" => "\"$(PODS_ROOT)/Headers/Private/React-Core\""} + + s.dependency "React-Core" + s.dependency "RCT-Folly" + s.dependency "RCTRequired" + s.dependency "RCTTypeSafety" + s.dependency "ReactCommon/turbomodule/core" + + if is_new_arch_enabled + s.dependency "React-RCTFabric" + s.dependency "React-graphics" + end +end diff --git a/Libraries/AppState/AppState.d.ts b/Libraries/AppState/AppState.d.ts new file mode 100644 index 00000000000000..45beaca9bde90b --- /dev/null +++ b/Libraries/AppState/AppState.d.ts @@ -0,0 +1,58 @@ +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @format + */ + +import {NativeEventSubscription} from '../EventEmitter/RCTNativeAppEventEmitter'; + +/** + * AppState can tell you if the app is in the foreground or background, + * and notify you when the state changes. + * + * AppState is frequently used to determine the intent and proper behavior + * when handling push notifications. + * + * App State Events + * change - This even is received when the app state has changed. + * focus [Android] - Received when the app gains focus (the user is interacting with the app). + * blur [Android] - Received when the user is not actively interacting with the app. + * + * App States + * active - The app is running in the foreground + * background - The app is running in the background. The user is either in another app or on the home screen + * inactive [iOS] - This is a transition state that currently never happens for typical React Native apps. + * unknown [iOS] - Initial value until the current app state is determined + * extension [iOS] - The app is running as an app extension + * + * For more information, see Apple's documentation: https://developer.apple.com/library/ios/documentation/iPhone/Conceptual/iPhoneOSProgrammingGuide/TheAppLifeCycle/TheAppLifeCycle.html + * + * @see https://reactnative.dev/docs/appstate#app-states + */ +export type AppStateEvent = 'change' | 'memoryWarning' | 'blur' | 'focus'; +export type AppStateStatus = + | 'active' + | 'background' + | 'inactive' + | 'unknown' + | 'extension'; + +export interface AppStateStatic { + currentState: AppStateStatus; + isAvailable: boolean; + + /** + * Add a handler to AppState changes by listening to the change event + * type and providing the handler + */ + addEventListener( + type: AppStateEvent, + listener: (state: AppStateStatus) => void, + ): NativeEventSubscription; +} + +export const AppState: AppStateStatic; +export type AppState = AppStateStatic; diff --git a/Libraries/AppState/AppState.js b/Libraries/AppState/AppState.js index 05143400926545..6ec9a262bedfea 100644 --- a/Libraries/AppState/AppState.js +++ b/Libraries/AppState/AppState.js @@ -8,11 +8,11 @@ * @format */ -import {type EventSubscription} from '../vendor/emitter/EventEmitter'; import NativeEventEmitter from '../EventEmitter/NativeEventEmitter'; import logError from '../Utilities/logError'; -import NativeAppState from './NativeAppState'; import Platform from '../Utilities/Platform'; +import {type EventSubscription} from '../vendor/emitter/EventEmitter'; +import NativeAppState from './NativeAppState'; export type AppStateValues = 'inactive' | 'background' | 'active'; @@ -78,17 +78,13 @@ class AppState { // It's possible that the state will have changed here & listeners need to be notified if (!eventUpdated && this.currentState !== appStateData.app_state) { this.currentState = appStateData.app_state; + // $FlowFixMe[incompatible-call] emitter.emit('appStateDidChange', appStateData); } }, logError); } } - // TODO: now that AppState is a subclass of NativeEventEmitter, we could - // deprecate `addEventListener` and `removeEventListener` and just use - // addListener` and `listener.remove()` directly. That will be a breaking - // change though, as both the method and event names are different - // (addListener events are currently required to be globally unique). /** * Add a handler to AppState changes by listening to the `change` event type * and providing the handler. @@ -129,38 +125,6 @@ class AppState { } throw new Error('Trying to subscribe to unknown event: ' + type); } - - /** - * @deprecated Use `remove` on the EventSubscription from `addEventListener`. - */ - removeEventListener>( - type: K, - listener: (...$ElementType) => mixed, - ): void { - const emitter = this._emitter; - if (emitter == null) { - throw new Error('Cannot use AppState when `isAvailable` is false.'); - } - // NOTE: This will report a deprecation notice via `console.error`. - switch (type) { - case 'change': - // $FlowIssue[invalid-tuple-arity] Flow cannot refine handler based on the event type - // $FlowIssue[incompatible-call] - emitter.removeListener('appStateDidChange', listener); - return; - case 'memoryWarning': - // $FlowIssue[invalid-tuple-arity] Flow cannot refine handler based on the event type - emitter.removeListener('memoryWarning', listener); - return; - case 'blur': - case 'focus': - // $FlowIssue[invalid-tuple-arity] Flow cannot refine handler based on the event type - // $FlowIssue[incompatible-call] - emitter.addListener('appStateFocusChange', listener); - return; - } - throw new Error('Trying to unsubscribe from unknown event: ' + type); - } } module.exports = (new AppState(): AppState); diff --git a/Libraries/AppState/NativeAppState.js b/Libraries/AppState/NativeAppState.js index d546e70051d0d1..177e167c6790d8 100644 --- a/Libraries/AppState/NativeAppState.js +++ b/Libraries/AppState/NativeAppState.js @@ -9,6 +9,7 @@ */ import type {TurboModule} from '../TurboModule/RCTExport'; + import * as TurboModuleRegistry from '../TurboModule/TurboModuleRegistry'; export interface Spec extends TurboModule { diff --git a/Libraries/BatchedBridge/MessageQueue.js b/Libraries/BatchedBridge/MessageQueue.js index b4745342911659..a9810bc6f94204 100644 --- a/Libraries/BatchedBridge/MessageQueue.js +++ b/Libraries/BatchedBridge/MessageQueue.js @@ -10,13 +10,12 @@ 'use strict'; -const ErrorUtils = require('../vendor/core/ErrorUtils'); const Systrace = require('../Performance/Systrace'); - const deepFreezeAndThrowOnMutationInDev = require('../Utilities/deepFreezeAndThrowOnMutationInDev'); -const invariant = require('invariant'); const stringifySafe = require('../Utilities/stringifySafe').default; const warnOnce = require('../Utilities/warnOnce'); +const ErrorUtils = require('../vendor/core/ErrorUtils'); +const invariant = require('invariant'); export type SpyData = { type: number, @@ -199,7 +198,7 @@ class MessageQueue { delete this._debugInfo[this._callID - DEBUG_INFO_LIMIT]; } if (this._successCallbacks.size > 500) { - const info = {}; + const info: {[number]: {method: string, module: string}} = {}; this._successCallbacks.forEach((_, callID) => { const debug = this._debugInfo[callID]; const module = debug && this._remoteModuleTable[debug[0]]; @@ -242,7 +241,7 @@ class MessageQueue { params: mixed[], onFail: ?(...mixed[]) => void, onSucc: ?(...mixed[]) => void, - ) { + ): void { this.processCallbacks(moduleID, methodID, params, onFail, onSucc); this._queue[MODULE_IDS].push(moduleID); @@ -253,7 +252,7 @@ class MessageQueue { // folly-convertible. As a special case, if a prop value is a // function it is permitted here, and special-cased in the // conversion. - const isValidArgument = val => { + const isValidArgument = (val: mixed): boolean => { switch (typeof val) { case 'undefined': case 'boolean': @@ -287,7 +286,7 @@ class MessageQueue { // Replacement allows normally non-JSON-convertible values to be // seen. There is ambiguity with string values, but in context, // it should at least be a strong hint. - const replacer = (key, val) => { + const replacer = (key: string, val: $FlowFixMe) => { const t = typeof val; if (t === 'function') { return '<>'; @@ -322,6 +321,7 @@ class MessageQueue { } Systrace.counterEvent('pending_js_to_native_queue', this._queue[0].length); if (__DEV__ && this.__spy && isFinite(moduleID)) { + // $FlowFixMe[not-a-function] this.__spy({ type: TO_NATIVE, module: this._remoteModuleTable[moduleID], @@ -381,7 +381,7 @@ class MessageQueue { return ( // $FlowFixMe[cannot-resolve-name] typeof DebuggerInternal !== 'undefined' && - DebuggerInternal.shouldPauseOnThrow === true // eslint-disable-line no-undef + DebuggerInternal.shouldPauseOnThrow === true ); } @@ -405,20 +405,30 @@ class MessageQueue { this.__spy({type: TO_JS, module, method, args}); } const moduleMethods = this.getCallableModule(module); - invariant( - !!moduleMethods, - `Module ${module} is not a registered callable module (calling ${method}). A frequent cause of the error is that the application entry file path is incorrect. - This can also happen when the JS bundle is corrupt or there is an early initialization error when loading React Native.`, - ); - invariant( - !!moduleMethods[method], - `Method ${method} does not exist on module ${module}`, - ); + if (!moduleMethods) { + const callableModuleNames = Object.keys(this._lazyCallableModules); + const n = callableModuleNames.length; + const callableModuleNameList = callableModuleNames.join(', '); + + // TODO(T122225939): Remove after investigation: Why are we getting to this line in bridgeless mode? + const isBridgelessMode = global.RN$Bridgeless === true ? 'true' : 'false'; + invariant( + false, + `Failed to call into JavaScript module method ${module}.${method}(). Module has not been registered as callable. Bridgeless Mode: ${isBridgelessMode}. Registered callable JavaScript modules (n = ${n}): ${callableModuleNameList}. + A frequent cause of the error is that the application entry file path is incorrect. This can also happen when the JS bundle is corrupt or there is an early initialization error when loading React Native.`, + ); + } + if (!moduleMethods[method]) { + invariant( + false, + `Failed to call into JavaScript module method ${module}.${method}(). Module exists, but the method is undefined.`, + ); + } moduleMethods[method].apply(moduleMethods, args); Systrace.endEvent(); } - __invokeCallback(cbID: number, args: mixed[]) { + __invokeCallback(cbID: number, args: mixed[]): void { this._lastFlush = Date.now(); this._eventLoopStartTime = this._lastFlush; diff --git a/Libraries/BatchedBridge/NativeModules.d.ts b/Libraries/BatchedBridge/NativeModules.d.ts new file mode 100644 index 00000000000000..ba35cca1e1bcb3 --- /dev/null +++ b/Libraries/BatchedBridge/NativeModules.d.ts @@ -0,0 +1,25 @@ +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @format + */ + +/** + * Interface for NativeModules which allows to augment NativeModules with type informations. + * See react-native-sensor-manager for example. + */ +interface NativeModulesStatic { + [name: string]: any; +} + +/** + * Native Modules written in ObjectiveC/Swift/Java exposed via the RCTBridge + * Define lazy getters for each module. These will return the module if already loaded, or load it if not. + * See https://reactnative.dev/docs/native-modules-ios + * @example + * const MyModule = NativeModules.ModuleName + */ +export const NativeModules: NativeModulesStatic; diff --git a/Libraries/BatchedBridge/NativeModules.js b/Libraries/BatchedBridge/NativeModules.js index 8b407884a30d41..0ea6b7c5c4a83e 100644 --- a/Libraries/BatchedBridge/NativeModules.js +++ b/Libraries/BatchedBridge/NativeModules.js @@ -10,12 +10,11 @@ 'use strict'; -const BatchedBridge = require('./BatchedBridge'); +import type {ExtendedError} from '../Core/ExtendedError'; +const BatchedBridge = require('./BatchedBridge'); const invariant = require('invariant'); -import type {ExtendedError} from '../Core/ExtendedError'; - export type ModuleConfig = [ string /* name */, ?{...} /* constants */, @@ -51,7 +50,7 @@ function genModule( return {name: moduleName}; } - const module = {}; + const module: {[string]: mixed} = {}; methods && methods.forEach((methodName, methodID) => { const isPromise = @@ -156,6 +155,7 @@ function genMethod(moduleID: number, methodID: number, type: MethodType) { } }; } + // $FlowFixMe[prop-missing] fn.type = type; return fn; } diff --git a/Libraries/BatchedBridge/__tests__/MessageQueue-test.js b/Libraries/BatchedBridge/__tests__/MessageQueue-test.js index 2edb9ed76690db..46304de89ad7ac 100644 --- a/Libraries/BatchedBridge/__tests__/MessageQueue-test.js +++ b/Libraries/BatchedBridge/__tests__/MessageQueue-test.js @@ -4,8 +4,8 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @emails oncall+react_native * @format + * @oncall react_native */ 'use strict'; @@ -108,8 +108,8 @@ describe('MessageQueue', function () { const unknownModule = 'UnknownModule', unknownMethod = 'UnknownMethod'; expect(() => queue.__callFunction(unknownModule, unknownMethod)).toThrow( - `Module ${unknownModule} is not a registered callable module (calling ${unknownMethod}). A frequent cause of the error is that the application entry file path is incorrect. - This can also happen when the JS bundle is corrupt or there is an early initialization error when loading React Native.`, + `Failed to call into JavaScript module method ${unknownModule}.${unknownMethod}(). Module has not been registered as callable. Bridgeless Mode: false. Registered callable JavaScript modules (n = 1): MessageQueueTestModule. + A frequent cause of the error is that the application entry file path is incorrect. This can also happen when the JS bundle is corrupt or there is an early initialization error when loading React Native.`, ); }); diff --git a/Libraries/BatchedBridge/__tests__/NativeModules-test.js b/Libraries/BatchedBridge/__tests__/NativeModules-test.js index f4d4aa7a93a6c8..570c95127940f8 100644 --- a/Libraries/BatchedBridge/__tests__/NativeModules-test.js +++ b/Libraries/BatchedBridge/__tests__/NativeModules-test.js @@ -5,7 +5,7 @@ * LICENSE file in the root directory of this source tree. * * @format - * @emails oncall+react_native + * @oncall react_native */ 'use strict'; diff --git a/Libraries/Blob/BlobManager.js b/Libraries/Blob/BlobManager.js index 0d4cee7282baaf..98e69112957d7b 100644 --- a/Libraries/Blob/BlobManager.js +++ b/Libraries/Blob/BlobManager.js @@ -8,13 +8,14 @@ * @format */ -const Blob = require('./Blob'); -const BlobRegistry = require('./BlobRegistry'); +import type {BlobCollector, BlobData, BlobOptions} from './BlobTypes'; -import type {BlobData, BlobOptions, BlobCollector} from './BlobTypes'; import NativeBlobModule from './NativeBlobModule'; import invariant from 'invariant'; +const Blob = require('./Blob'); +const BlobRegistry = require('./BlobRegistry'); + /*eslint-disable no-bitwise */ /*eslint-disable eqeqeq */ @@ -110,6 +111,7 @@ class BlobManager { */ static createFromOptions(options: BlobData): Blob { BlobRegistry.register(options.blobId); + // $FlowFixMe[prop-missing] return Object.assign(Object.create(Blob.prototype), { data: // Reuse the collector instance when creating from an existing blob. diff --git a/Libraries/Blob/File.js b/Libraries/Blob/File.js index 5aa2dd73c46f3d..6f643307c5d021 100644 --- a/Libraries/Blob/File.js +++ b/Libraries/Blob/File.js @@ -10,12 +10,11 @@ 'use strict'; -const Blob = require('./Blob'); +import type {BlobOptions} from './BlobTypes'; +const Blob = require('./Blob'); const invariant = require('invariant'); -import type {BlobOptions} from './BlobTypes'; - /** * The File interface provides information about files. */ diff --git a/Libraries/Blob/FileReader.js b/Libraries/Blob/FileReader.js index c58dfba687df62..57b3093cf6b025 100644 --- a/Libraries/Blob/FileReader.js +++ b/Libraries/Blob/FileReader.js @@ -8,11 +8,12 @@ * @format */ -const Blob = require('./Blob'); -const EventTarget = require('event-target-shim'); +import type Blob from './Blob'; import NativeFileReaderModule from './NativeFileReaderModule'; +const EventTarget = require('event-target-shim'); + type ReadyState = | 0 // EMPTY | 1 // LOADING @@ -46,7 +47,6 @@ class FileReader extends (EventTarget(...READER_EVENTS): any) { _error: ?Error; _result: ?ReaderResult; _aborted: boolean = false; - _subscriptions: Array = []; constructor() { super(); @@ -59,11 +59,6 @@ class FileReader extends (EventTarget(...READER_EVENTS): any) { this._result = null; } - _clearSubscriptions(): void { - this._subscriptions.forEach(sub => sub.remove()); - this._subscriptions = []; - } - _setReadyState(newState: ReadyState) { this._readyState = newState; this.dispatchEvent({type: 'readystatechange'}); @@ -79,11 +74,11 @@ class FileReader extends (EventTarget(...READER_EVENTS): any) { } } - readAsArrayBuffer() { + readAsArrayBuffer(): any { throw new Error('FileReader.readAsArrayBuffer is not implemented'); } - readAsDataURL(blob: ?Blob) { + readAsDataURL(blob: ?Blob): void { this._aborted = false; if (blob == null) { @@ -110,7 +105,7 @@ class FileReader extends (EventTarget(...READER_EVENTS): any) { ); } - readAsText(blob: ?Blob, encoding: string = 'UTF-8') { + readAsText(blob: ?Blob, encoding: string = 'UTF-8'): void { this._aborted = false; if (blob == null) { diff --git a/Libraries/Blob/NativeBlobModule.js b/Libraries/Blob/NativeBlobModule.js index 2b474d693527b6..00a86fae31bfb8 100644 --- a/Libraries/Blob/NativeBlobModule.js +++ b/Libraries/Blob/NativeBlobModule.js @@ -9,6 +9,7 @@ */ import type {TurboModule} from '../TurboModule/RCTExport'; + import * as TurboModuleRegistry from '../TurboModule/TurboModuleRegistry'; export interface Spec extends TurboModule { diff --git a/Libraries/Blob/NativeFileReaderModule.js b/Libraries/Blob/NativeFileReaderModule.js index ac964b3af42ea7..e581aba74d176b 100644 --- a/Libraries/Blob/NativeFileReaderModule.js +++ b/Libraries/Blob/NativeFileReaderModule.js @@ -9,6 +9,7 @@ */ import type {TurboModule} from '../TurboModule/RCTExport'; + import * as TurboModuleRegistry from '../TurboModule/TurboModuleRegistry'; export interface Spec extends TurboModule { diff --git a/Libraries/Blob/RCTBlobCollector.h b/Libraries/Blob/RCTBlobCollector.h index fdd68112d6820a..4d0166aab7db94 100644 --- a/Libraries/Blob/RCTBlobCollector.h +++ b/Libraries/Blob/RCTBlobCollector.h @@ -7,8 +7,6 @@ #import -using namespace facebook; - @class RCTBlobManager; namespace facebook { diff --git a/Libraries/Blob/RCTBlobCollector.mm b/Libraries/Blob/RCTBlobCollector.mm index b7387c445a5038..60053c3a140351 100644 --- a/Libraries/Blob/RCTBlobCollector.mm +++ b/Libraries/Blob/RCTBlobCollector.mm @@ -7,16 +7,19 @@ #import "RCTBlobCollector.h" -#import #import +#import namespace facebook { namespace react { RCTBlobCollector::RCTBlobCollector(RCTBlobManager *blobManager, const std::string &blobId) -: blobId_(blobId), blobManager_(blobManager) {} + : blobId_(blobId), blobManager_(blobManager) +{ +} -RCTBlobCollector::~RCTBlobCollector() { +RCTBlobCollector::~RCTBlobCollector() +{ RCTBlobManager *blobManager = blobManager_; NSString *blobId = [NSString stringWithUTF8String:blobId_.c_str()]; dispatch_async([blobManager_ methodQueue], ^{ @@ -24,28 +27,29 @@ }); } -void RCTBlobCollector::install(RCTBlobManager *blobManager) { +void RCTBlobCollector::install(RCTBlobManager *blobManager) +{ __weak RCTCxxBridge *cxxBridge = (RCTCxxBridge *)blobManager.bridge; - [cxxBridge dispatchBlock:^{ - if (!cxxBridge || cxxBridge.runtime == nullptr) { - return; - } - jsi::Runtime &runtime = *(jsi::Runtime *)cxxBridge.runtime; - runtime.global().setProperty( - runtime, - "__blobCollectorProvider", - jsi::Function::createFromHostFunction( - runtime, - jsi::PropNameID::forAscii(runtime, "__blobCollectorProvider"), - 1, - [blobManager](jsi::Runtime& rt, const jsi::Value& thisVal, const jsi::Value* args, size_t count) { - auto blobId = args[0].asString(rt).utf8(rt); - auto blobCollector = std::make_shared(blobManager, blobId); - return jsi::Object::createFromHostObject(rt, blobCollector); + [cxxBridge + dispatchBlock:^{ + if (!cxxBridge || cxxBridge.runtime == nullptr) { + return; } - ) - ); - } queue:RCTJSThread]; + jsi::Runtime &runtime = *(jsi::Runtime *)cxxBridge.runtime; + runtime.global().setProperty( + runtime, + "__blobCollectorProvider", + jsi::Function::createFromHostFunction( + runtime, + jsi::PropNameID::forAscii(runtime, "__blobCollectorProvider"), + 1, + [blobManager](jsi::Runtime &rt, const jsi::Value &thisVal, const jsi::Value *args, size_t count) { + auto blobId = args[0].asString(rt).utf8(rt); + auto blobCollector = std::make_shared(blobManager, blobId); + return jsi::Object::createFromHostObject(rt, blobCollector); + })); + } + queue:RCTJSThread]; } } // namespace react diff --git a/Libraries/Blob/RCTBlobManager.h b/Libraries/Blob/RCTBlobManager.h index 34cd8b82cf908d..317b202911df48 100755 --- a/Libraries/Blob/RCTBlobManager.h +++ b/Libraries/Blob/RCTBlobManager.h @@ -7,8 +7,8 @@ #import #import -#import #import +#import @interface RCTBlobManager : NSObject diff --git a/Libraries/Blob/RCTBlobManager.mm b/Libraries/Blob/RCTBlobManager.mm index 567e16ffee56c1..14496f7e491099 100755 --- a/Libraries/Blob/RCTBlobManager.mm +++ b/Libraries/Blob/RCTBlobManager.mm @@ -15,17 +15,20 @@ #import #import -#import "RCTBlobPlugins.h" #import "RCTBlobCollector.h" +#import "RCTBlobPlugins.h" static NSString *const kBlobURIScheme = @"blob"; -@interface RCTBlobManager () +@interface RCTBlobManager () < + RCTNetworkingRequestHandler, + RCTNetworkingResponseHandler, + RCTWebSocketContentHandler, + NativeBlobModuleSpec> @end -@implementation RCTBlobManager -{ +@implementation RCTBlobManager { // Blobs should be thread safe since they are used from the websocket and networking module, // make sure to use proper locking when accessing this. NSMutableDictionary *_blobs; @@ -61,8 +64,8 @@ + (BOOL)requiresMainQueueSetup - (NSDictionary *)getConstants { return @{ - @"BLOB_URI_SCHEME": kBlobURIScheme, - @"BLOB_URI_HOST": [NSNull null], + @"BLOB_URI_SCHEME" : kBlobURIScheme, + @"BLOB_URI_HOST" : [NSNull null], }; } @@ -84,9 +87,7 @@ - (NSData *)resolve:(NSDictionary *)blob NSString *blobId = [RCTConvert NSString:blob[@"blobId"]]; NSNumber *offset = [RCTConvert NSNumber:blob[@"offset"]]; NSNumber *size = [RCTConvert NSNumber:blob[@"size"]]; - return [self resolve:blobId - offset:offset ? [offset integerValue] : 0 - size:size ? [size integerValue] : -1]; + return [self resolve:blobId offset:offset ? [offset integerValue] : 0 size:size ? [size integerValue] : -1]; } - (NSData *)resolve:(NSString *)blobId offset:(NSInteger)offset size:(NSInteger)size @@ -152,29 +153,32 @@ - (void)remove:(NSString *)blobId }); } -RCT_EXPORT_METHOD(addWebSocketHandler:(double)socketID) +RCT_EXPORT_METHOD(addWebSocketHandler : (double)socketID) { dispatch_async(((RCTWebSocketModule *)[_moduleRegistry moduleForName:"WebSocketModule"]).methodQueue, ^{ - [[self->_moduleRegistry moduleForName:"WebSocketModule"] setContentHandler:self forSocketID:[NSNumber numberWithDouble:socketID]]; + [[self->_moduleRegistry moduleForName:"WebSocketModule"] setContentHandler:self + forSocketID:[NSNumber numberWithDouble:socketID]]; }); } -RCT_EXPORT_METHOD(removeWebSocketHandler:(double)socketID) +RCT_EXPORT_METHOD(removeWebSocketHandler : (double)socketID) { dispatch_async(((RCTWebSocketModule *)[_moduleRegistry moduleForName:"WebSocketModule"]).methodQueue, ^{ - [[self->_moduleRegistry moduleForName:"WebSocketModule"] setContentHandler:nil forSocketID:[NSNumber numberWithDouble:socketID]]; + [[self->_moduleRegistry moduleForName:"WebSocketModule"] setContentHandler:nil + forSocketID:[NSNumber numberWithDouble:socketID]]; }); } // @lint-ignore FBOBJCUNTYPEDCOLLECTION1 -RCT_EXPORT_METHOD(sendOverSocket:(NSDictionary *)blob socketID:(double)socketID) +RCT_EXPORT_METHOD(sendOverSocket : (NSDictionary *)blob socketID : (double)socketID) { dispatch_async(((RCTWebSocketModule *)[_moduleRegistry moduleForName:"WebSocketModule"]).methodQueue, ^{ - [[self->_moduleRegistry moduleForName:"WebSocketModule"] sendData:[self resolve:blob] forSocketID:[NSNumber numberWithDouble:socketID]]; + [[self->_moduleRegistry moduleForName:"WebSocketModule"] sendData:[self resolve:blob] + forSocketID:[NSNumber numberWithDouble:socketID]]; }); } -RCT_EXPORT_METHOD(createFromParts:(NSArray *> *)parts withId:(NSString *)blobId) +RCT_EXPORT_METHOD(createFromParts : (NSArray *> *)parts withId : (NSString *)blobId) { NSMutableData *data = [NSMutableData new]; for (NSDictionary *part in parts) { @@ -193,7 +197,7 @@ - (void)remove:(NSString *)blobId [self store:data withId:blobId]; } -RCT_EXPORT_METHOD(release:(NSString *)blobId) +RCT_EXPORT_METHOD(release : (NSString *)blobId) { [self remove:blobId]; } @@ -267,7 +271,7 @@ - (NSDictionary *)handleNetworkingRequest:(NSDictionary *)data contentType = blob[@"type"]; } - return @{@"body": [self resolve:blob], @"contentType": contentType}; + return @{@"body" : [self resolve:blob], @"contentType" : contentType}; } - (BOOL)canHandleNetworkingResponse:(NSString *)responseType @@ -281,11 +285,11 @@ - (id)handleNetworkingResponse:(NSURLResponse *)response data:(NSData *)data // an empty blob as per the XMLHttpRequest spec. data = data ?: [NSData new]; return @{ - @"blobId": [self store:data], - @"offset": @0, - @"size": @(data.length), - @"name": RCTNullIfNil([response suggestedFilename]), - @"type": RCTNullIfNil([response MIMEType]), + @"blobId" : [self store:data], + @"offset" : @0, + @"size" : @(data.length), + @"name" : RCTNullIfNil([response suggestedFilename]), + @"type" : RCTNullIfNil([response MIMEType]), }; } @@ -302,19 +306,21 @@ - (id)processWebsocketMessage:(id)message *type = @"blob"; return @{ - @"blobId": [self store:message], - @"offset": @0, - @"size": @(((NSData *)message).length), + @"blobId" : [self store:message], + @"offset" : @0, + @"size" : @(((NSData *)message).length), }; } -- (std::shared_ptr)getTurboModule:(const facebook::react::ObjCTurboModule::InitParams &)params +- (std::shared_ptr)getTurboModule: + (const facebook::react::ObjCTurboModule::InitParams &)params { return std::make_shared(params); } @end -Class RCTBlobManagerCls(void) { +Class RCTBlobManagerCls(void) +{ return RCTBlobManager.class; } diff --git a/Libraries/Blob/RCTFileReaderModule.mm b/Libraries/Blob/RCTFileReaderModule.mm index e834c61cc7970f..685d86b48d80ae 100644 --- a/Libraries/Blob/RCTFileReaderModule.mm +++ b/Libraries/Blob/RCTFileReaderModule.mm @@ -5,7 +5,6 @@ * LICENSE file in the root directory of this source tree. */ - #import #import @@ -16,7 +15,7 @@ #import "RCTBlobPlugins.h" -@interface RCTFileReaderModule() +@interface RCTFileReaderModule () @end @implementation RCTFileReaderModule @@ -25,53 +24,65 @@ @implementation RCTFileReaderModule @synthesize moduleRegistry = _moduleRegistry; -RCT_EXPORT_METHOD(readAsText:(NSDictionary *)blob - encoding:(NSString *)encoding - resolve:(RCTPromiseResolveBlock)resolve - reject:(RCTPromiseRejectBlock)reject) +RCT_EXPORT_METHOD(readAsText + : (NSDictionary *)blob encoding + : (NSString *)encoding resolve + : (RCTPromiseResolveBlock)resolve reject + : (RCTPromiseRejectBlock)reject) { RCTBlobManager *blobManager = [_moduleRegistry moduleForName:"BlobModule"]; - NSData *data = [blobManager resolve:blob]; - - if (data == nil) { - reject(RCTErrorUnspecified, - [NSString stringWithFormat:@"Unable to resolve data for blob: %@", [RCTConvert NSString:blob[@"blobId"]]], nil); - } else { - NSStringEncoding stringEncoding; - - if (encoding == nil) { - stringEncoding = NSUTF8StringEncoding; + dispatch_async(blobManager.methodQueue, ^{ + NSData *data = [blobManager resolve:blob]; + + if (data == nil) { + reject( + RCTErrorUnspecified, + [NSString stringWithFormat:@"Unable to resolve data for blob: %@", [RCTConvert NSString:blob[@"blobId"]]], + nil); } else { - stringEncoding = CFStringConvertEncodingToNSStringEncoding(CFStringConvertIANACharSetNameToEncoding((CFStringRef) encoding)); - } + NSStringEncoding stringEncoding; + + if (encoding == nil) { + stringEncoding = NSUTF8StringEncoding; + } else { + stringEncoding = + CFStringConvertEncodingToNSStringEncoding(CFStringConvertIANACharSetNameToEncoding((CFStringRef)encoding)); + } - NSString *text = [[NSString alloc] initWithData:data encoding:stringEncoding]; + NSString *text = [[NSString alloc] initWithData:data encoding:stringEncoding]; - resolve(text); - } + resolve(text); + } + }); } -RCT_EXPORT_METHOD(readAsDataURL:(NSDictionary *)blob - resolve:(RCTPromiseResolveBlock)resolve - reject:(RCTPromiseRejectBlock)reject) +RCT_EXPORT_METHOD(readAsDataURL + : (NSDictionary *)blob resolve + : (RCTPromiseResolveBlock)resolve reject + : (RCTPromiseRejectBlock)reject) { RCTBlobManager *blobManager = [_moduleRegistry moduleForName:"BlobModule"]; - NSData *data = [blobManager resolve:blob]; - - if (data == nil) { - reject(RCTErrorUnspecified, - [NSString stringWithFormat:@"Unable to resolve data for blob: %@", [RCTConvert NSString:blob[@"blobId"]]], nil); - } else { - NSString *type = [RCTConvert NSString:blob[@"type"]]; - NSString *text = [NSString stringWithFormat:@"data:%@;base64,%@", - type != nil && [type length] > 0 ? type : @"application/octet-stream", - [data base64EncodedStringWithOptions:0]]; - - resolve(text); - } + dispatch_async(blobManager.methodQueue, ^{ + NSData *data = [blobManager resolve:blob]; + + if (data == nil) { + reject( + RCTErrorUnspecified, + [NSString stringWithFormat:@"Unable to resolve data for blob: %@", [RCTConvert NSString:blob[@"blobId"]]], + nil); + } else { + NSString *type = [RCTConvert NSString:blob[@"type"]]; + NSString *text = [NSString stringWithFormat:@"data:%@;base64,%@", + type != nil && [type length] > 0 ? type : @"application/octet-stream", + [data base64EncodedStringWithOptions:0]]; + + resolve(text); + } + }); } -- (std::shared_ptr)getTurboModule:(const facebook::react::ObjCTurboModule::InitParams &)params +- (std::shared_ptr)getTurboModule: + (const facebook::react::ObjCTurboModule::InitParams &)params { return std::make_shared(params); } diff --git a/Libraries/Blob/React-RCTBlob.podspec b/Libraries/Blob/React-RCTBlob.podspec index d05e7736c569a1..0c911e1d632541 100644 --- a/Libraries/Blob/React-RCTBlob.podspec +++ b/Libraries/Blob/React-RCTBlob.podspec @@ -17,7 +17,7 @@ else end folly_compiler_flags = '-DFOLLY_NO_CONFIG -DFOLLY_MOBILE=1 -DFOLLY_USE_LIBCPP=1 -Wno-comma -Wno-shorten-64-to-32' -folly_version = '2021.06.28.00-v2' +folly_version = '2021.07.22.00' Pod::Spec.new do |s| s.name = "React-RCTBlob" @@ -26,7 +26,7 @@ Pod::Spec.new do |s| s.homepage = "https://reactnative.dev/" s.license = package["license"] s.author = "Facebook, Inc. and its affiliates" - s.platforms = { :ios => "11.0", :osx => "10.15" } # [macOS] + s.platforms = { :ios => "12.4", :osx => "10.15" } # [macOS] s.compiler_flags = folly_compiler_flags + ' -Wno-nullability-completeness' s.source = source s.source_files = "*.{h,m,mm}" @@ -35,7 +35,7 @@ Pod::Spec.new do |s| s.pod_target_xcconfig = { "USE_HEADERMAP" => "YES", "CLANG_CXX_LANGUAGE_STANDARD" => "c++17", - "HEADER_SEARCH_PATHS" => "\"$(PODS_ROOT)/RCT-Folly\" \"${PODS_ROOT}/Headers/Public/React-Codegen/react/renderer/components\"" + "HEADER_SEARCH_PATHS" => "\"$(PODS_ROOT)/RCT-Folly\" \"${PODS_ROOT}/Headers/Public/React-Codegen/react/renderer/components\" \"${PODS_CONFIGURATION_BUILD_DIR}/React-Codegen/React_Codegen.framework/Headers\"" } s.dependency "RCT-Folly", folly_version @@ -45,5 +45,4 @@ Pod::Spec.new do |s| s.dependency "React-Core/RCTBlobHeaders", version s.dependency "React-Core/RCTWebSocket", version s.dependency "React-RCTNetwork", version - s.dependency "React-jsi", version end diff --git a/Libraries/Blob/URL.js b/Libraries/Blob/URL.js index 9bcc8060e05e27..1cc3a9e8c4a2cb 100644 --- a/Libraries/Blob/URL.js +++ b/Libraries/Blob/URL.js @@ -8,7 +8,7 @@ * @flow */ -const Blob = require('./Blob'); +import type Blob from './Blob'; import NativeBlobModule from './NativeBlobModule'; @@ -54,7 +54,7 @@ if ( // Small subset from whatwg-url: https://github.com/jsdom/whatwg-url/tree/master/src // The reference code bloat comes from Unicode issues with URLs, so those won't work here. export class URLSearchParams { - _searchParams = []; + _searchParams: Array> = []; constructor(params: any) { if (typeof params === 'object') { @@ -62,35 +62,36 @@ export class URLSearchParams { } } - append(key: string, value: string) { + append(key: string, value: string): void { this._searchParams.push([key, value]); } - delete(name: string) { + delete(name: string): void { throw new Error('URLSearchParams.delete is not implemented'); } - get(name: string) { + get(name: string): void { throw new Error('URLSearchParams.get is not implemented'); } - getAll(name: string) { + getAll(name: string): void { throw new Error('URLSearchParams.getAll is not implemented'); } - has(name: string) { + has(name: string): void { throw new Error('URLSearchParams.has is not implemented'); } - set(name: string, value: string) { + set(name: string, value: string): void { throw new Error('URLSearchParams.set is not implemented'); } - sort() { + sort(): void { throw new Error('URLSearchParams.sort is not implemented'); } // $FlowFixMe[unsupported-syntax] + // $FlowFixMe[missing-local-annot] [Symbol.iterator]() { return this._searchParams[Symbol.iterator](); } @@ -101,7 +102,13 @@ export class URLSearchParams { } const last = this._searchParams.length - 1; return this._searchParams.reduce((acc, curr, index) => { - return acc + curr.join('=') + (index === last ? '' : '&'); + return ( + acc + + encodeURIComponent(curr[0]) + + '=' + + encodeURIComponent(curr[1]) + + (index === last ? '' : '&') + ); }, ''); } } @@ -128,6 +135,7 @@ export class URL { // Do nothing. } + // $FlowFixMe[missing-local-annot] constructor(url: string, base: string | URL) { let baseUrl = null; if (!base || validateBaseUrl(url)) { diff --git a/Libraries/Blob/__tests__/Blob-test.js b/Libraries/Blob/__tests__/Blob-test.js index 5e406f024dd084..9fdabab67ef530 100644 --- a/Libraries/Blob/__tests__/Blob-test.js +++ b/Libraries/Blob/__tests__/Blob-test.js @@ -5,7 +5,7 @@ * LICENSE file in the root directory of this source tree. * * @format - * @emails oncall+react_native + * @oncall react_native */ 'use strict'; diff --git a/Libraries/Blob/__tests__/BlobManager-test.js b/Libraries/Blob/__tests__/BlobManager-test.js index e03dd87d9d1c85..856eac1ad869d5 100644 --- a/Libraries/Blob/__tests__/BlobManager-test.js +++ b/Libraries/Blob/__tests__/BlobManager-test.js @@ -5,7 +5,7 @@ * LICENSE file in the root directory of this source tree. * * @format - * @emails oncall+react_native + * @oncall react_native */ 'use strict'; diff --git a/Libraries/Blob/__tests__/File-test.js b/Libraries/Blob/__tests__/File-test.js index 21b50650a99879..b6d6c31ec2fe72 100644 --- a/Libraries/Blob/__tests__/File-test.js +++ b/Libraries/Blob/__tests__/File-test.js @@ -5,7 +5,7 @@ * LICENSE file in the root directory of this source tree. * * @format - * @emails oncall+react_native + * @oncall react_native */ 'use strict'; diff --git a/Libraries/Blob/__tests__/FileReader-test.js b/Libraries/Blob/__tests__/FileReader-test.js index 8ae1c81a31f8a8..1e1ac1ab7a4dd6 100644 --- a/Libraries/Blob/__tests__/FileReader-test.js +++ b/Libraries/Blob/__tests__/FileReader-test.js @@ -5,7 +5,7 @@ * LICENSE file in the root directory of this source tree. * * @format - * @emails oncall+react_native + * @oncall react_native */ 'use strict'; diff --git a/Libraries/Blob/__tests__/URL-test.js b/Libraries/Blob/__tests__/URL-test.js index 28e89950b267db..c317217c8fe724 100644 --- a/Libraries/Blob/__tests__/URL-test.js +++ b/Libraries/Blob/__tests__/URL-test.js @@ -5,7 +5,7 @@ * LICENSE file in the root directory of this source tree. * * @format - * @emails oncall+react_native + * @oncall react_native */ 'use strict'; diff --git a/Libraries/BugReporting/NativeBugReporting.js b/Libraries/BugReporting/NativeBugReporting.js index 13a51a585c0b25..f886208de3d3f3 100644 --- a/Libraries/BugReporting/NativeBugReporting.js +++ b/Libraries/BugReporting/NativeBugReporting.js @@ -9,6 +9,7 @@ */ import type {TurboModule} from '../TurboModule/RCTExport'; + import * as TurboModuleRegistry from '../TurboModule/TurboModuleRegistry'; export interface Spec extends TurboModule { diff --git a/Libraries/BugReporting/getReactData.js b/Libraries/BugReporting/getReactData.js index 4440cc4e0d0e60..cc988ced109854 100644 --- a/Libraries/BugReporting/getReactData.js +++ b/Libraries/BugReporting/getReactData.js @@ -165,7 +165,7 @@ function copyWithSetImpl( path: Array, idx: number, value: any, -) { +): any { if (idx >= path.length) { return value; } diff --git a/Libraries/Components/AccessibilityInfo/AccessibilityInfo.d.ts b/Libraries/Components/AccessibilityInfo/AccessibilityInfo.d.ts new file mode 100644 index 00000000000000..749d44e36717d0 --- /dev/null +++ b/Libraries/Components/AccessibilityInfo/AccessibilityInfo.d.ts @@ -0,0 +1,128 @@ +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @format + */ + +import type * as React from 'react'; +import {HostComponent} from '../../../types/public/ReactNativeTypes'; +import {EmitterSubscription} from '../../vendor/emitter/EventEmitter'; + +type AccessibilityChangeEventName = + | 'change' // deprecated, maps to screenReaderChanged + | 'boldTextChanged' // iOS-only Event + | 'grayscaleChanged' // iOS-only Event + | 'invertColorsChanged' // iOS-only Event + | 'reduceMotionChanged' + | 'screenReaderChanged' + | 'reduceTransparencyChanged'; // iOS-only Event + +type AccessibilityChangeEvent = boolean; + +type AccessibilityChangeEventHandler = ( + event: AccessibilityChangeEvent, +) => void; + +type AccessibilityAnnouncementEventName = 'announcementFinished'; // iOS-only Event + +type AccessibilityAnnouncementFinishedEvent = { + announcement: string; + success: boolean; +}; + +type AccessibilityAnnouncementFinishedEventHandler = ( + event: AccessibilityAnnouncementFinishedEvent, +) => void; + +type AccessibilityEventTypes = 'click' | 'focus'; + +/** + * @see https://reactnative.dev/docs/accessibilityinfo + */ +export interface AccessibilityInfoStatic { + /** + * Query whether bold text is currently enabled. + * + * @platform ios + */ + isBoldTextEnabled: () => Promise; + + /** + * Query whether grayscale is currently enabled. + * + * @platform ios + */ + isGrayscaleEnabled: () => Promise; + + /** + * Query whether invert colors is currently enabled. + * + * @platform ios + */ + isInvertColorsEnabled: () => Promise; + + /** + * Query whether reduce motion is currently enabled. + */ + isReduceMotionEnabled: () => Promise; + + /** + * Query whether reduce transparency is currently enabled. + * + * @platform ios + */ + isReduceTransparencyEnabled: () => Promise; + + /** + * Query whether a screen reader is currently enabled. + */ + isScreenReaderEnabled: () => Promise; + + /** + * Add an event handler. Supported events: + * - announcementFinished: iOS-only event. Fires when the screen reader has finished making an announcement. + * The argument to the event handler is a dictionary with these keys: + * - announcement: The string announced by the screen reader. + * - success: A boolean indicating whether the announcement was successfully made. + * - AccessibilityEventName constants other than announcementFinished: Fires on accessibility feature change. + * The argument to the event handler is a boolean. + * The boolean is true when the related event's feature is enabled and false otherwise. + * + */ + addEventListener( + eventName: AccessibilityChangeEventName, + handler: AccessibilityChangeEventHandler, + ): EmitterSubscription; + addEventListener( + eventName: AccessibilityAnnouncementEventName, + handler: AccessibilityAnnouncementFinishedEventHandler, + ): EmitterSubscription; + + /** + * Set accessibility focus to a react component. + */ + setAccessibilityFocus: (reactTag: number) => void; + + /** + * Post a string to be announced by the screen reader. + */ + announceForAccessibility: (announcement: string) => void; + + /** + * Gets the timeout in millisecond that the user needs. + * This value is set in "Time to take action (Accessibility timeout)" of "Accessibility" settings. + * + * @platform android + */ + getRecommendedTimeoutMillis: (originalTimeout: number) => Promise; + sendAccessibilityEvent: ( + handle: React.ElementRef>, + eventType: AccessibilityEventTypes, + ) => void; +} + +export const AccessibilityInfo: AccessibilityInfoStatic; +export type AccessibilityInfo = AccessibilityInfoStatic; diff --git a/Libraries/Components/AccessibilityInfo/AccessibilityInfo.flow.js b/Libraries/Components/AccessibilityInfo/AccessibilityInfo.flow.js new file mode 100644 index 00000000000000..68a743fd5a0393 --- /dev/null +++ b/Libraries/Components/AccessibilityInfo/AccessibilityInfo.flow.js @@ -0,0 +1,223 @@ +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @flow strict-local + * @format + */ + +import type {HostComponent} from '../../Renderer/shims/ReactNativeTypes'; +import type {EventSubscription} from '../../vendor/emitter/EventEmitter'; +import type {ElementRef} from 'react'; + +// Events that are only supported on Android. +type AccessibilityEventDefinitionsAndroid = { + accessibilityServiceChanged: [boolean], +}; + +// Events that are only supported on iOS. +type AccessibilityEventDefinitionsIOS = { + announcementFinished: [{announcement: string, success: boolean}], + boldTextChanged: [boolean], + grayscaleChanged: [boolean], + invertColorsChanged: [boolean], + reduceTransparencyChanged: [boolean], +}; + +// [macOS +// Events that are only supported on macOS. +type AccessibilityEventDefinitionsMacOS = { + highContrastChanged: [boolean], // [macOS] highContrastChanged is used on macOS +}; +// macOS] + +type AccessibilityEventDefinitions = { + ...AccessibilityEventDefinitionsAndroid, + ...AccessibilityEventDefinitionsIOS, + ...AccessibilityEventDefinitionsMacOS, // [macOS] + change: [boolean], // screenReaderChanged + reduceMotionChanged: [boolean], + screenReaderChanged: [boolean], +}; + +type AccessibilityEventTypes = 'click' | 'focus'; +/** + * Sometimes it's useful to know whether or not the device has a screen reader + * that is currently active. The `AccessibilityInfo` API is designed for this + * purpose. You can use it to query the current state of the screen reader as + * well as to register to be notified when the state of the screen reader + * changes. + * + * See https://reactnative.dev/docs/accessibilityinfo + */ +export type AccessibilityInfoType = { + /** + * Query whether bold text is currently enabled. + * + * Returns a promise which resolves to a boolean. + * The result is `true` when bold text is enabled and `false` otherwise. + * + * See https://reactnative.dev/docs/accessibilityinfo#isBoldTextEnabled + */ + isBoldTextEnabled: () => Promise, + + /** + * Query whether grayscale is currently enabled. + * + * Returns a promise which resolves to a boolean. + * The result is `true` when grayscale is enabled and `false` otherwise. + * + * See https://reactnative.dev/docs/accessibilityinfo#isGrayscaleEnabled + */ + isGrayscaleEnabled: () => Promise, + + // [macOS + /** + * macOS only + */ + isHighContrastEnabled: () => Promise, + // macOS] + + /** + * Query whether inverted colors are currently enabled. + * + * Returns a promise which resolves to a boolean. + * The result is `true` when invert color is enabled and `false` otherwise. + * + * See https://reactnative.dev/docs/accessibilityinfo#isInvertColorsEnabled + */ + isInvertColorsEnabled: () => Promise, + + /** + * Query whether reduced motion is currently enabled. + * + * Returns a promise which resolves to a boolean. + * The result is `true` when a reduce motion is enabled and `false` otherwise. + * + * See https://reactnative.dev/docs/accessibilityinfo#isReduceMotionEnabled + */ + isReduceMotionEnabled: () => Promise, + + /** + * Query whether reduce motion and prefer cross-fade transitions settings are currently enabled. + * + * Returns a promise which resolves to a boolean. + * The result is `true` when prefer cross-fade transitions is enabled and `false` otherwise. + * + * See https://reactnative.dev/docs/accessibilityinfo#prefersCrossFadeTransitions + */ + prefersCrossFadeTransitions: () => Promise, + + /** + * Query whether reduced transparency is currently enabled. + * + * Returns a promise which resolves to a boolean. + * The result is `true` when a reduce transparency is enabled and `false` otherwise. + * + * See https://reactnative.dev/docs/accessibilityinfo#isReduceTransparencyEnabled + */ + isReduceTransparencyEnabled: () => Promise, + + /** + * Query whether a screen reader is currently enabled. + * + * Returns a promise which resolves to a boolean. + * The result is `true` when a screen reader is enabled and `false` otherwise. + * + * See https://reactnative.dev/docs/accessibilityinfo#isScreenReaderEnabled + */ + isScreenReaderEnabled: () => Promise, + + /** + * Query whether Accessibility Service is currently enabled. + * + * Returns a promise which resolves to a boolean. + * The result is `true` when any service is enabled and `false` otherwise. + * + * @platform android + * + * See https://reactnative.dev/docs/accessibilityinfo/#isaccessibilityserviceenabled-android + */ + isAccessibilityServiceEnabled: () => Promise, + + /** + * Add an event handler. Supported events: + * + * - `reduceMotionChanged`: Fires when the state of the reduce motion toggle changes. + * The argument to the event handler is a boolean. The boolean is `true` when a reduce + * motion is enabled (or when "Transition Animation Scale" in "Developer options" is + * "Animation off") and `false` otherwise. + * - `screenReaderChanged`: Fires when the state of the screen reader changes. The argument + * to the event handler is a boolean. The boolean is `true` when a screen + * reader is enabled and `false` otherwise. + * + * These events are only supported on iOS: + * + * - `boldTextChanged`: iOS-only event. Fires when the state of the bold text toggle changes. + * The argument to the event handler is a boolean. The boolean is `true` when a bold text + * is enabled and `false` otherwise. + * - `grayscaleChanged`: iOS-only event. Fires when the state of the gray scale toggle changes. + * The argument to the event handler is a boolean. The boolean is `true` when a gray scale + * is enabled and `false` otherwise. + * - `invertColorsChanged`: iOS-only event. Fires when the state of the invert colors toggle + * changes. The argument to the event handler is a boolean. The boolean is `true` when a invert + * colors is enabled and `false` otherwise. + * - `reduceTransparencyChanged`: iOS-only event. Fires when the state of the reduce transparency + * toggle changes. The argument to the event handler is a boolean. The boolean is `true` + * when a reduce transparency is enabled and `false` otherwise. + * - `announcementFinished`: iOS-only event. Fires when the screen reader has + * finished making an announcement. The argument to the event handler is a + * dictionary with these keys: + * - `announcement`: The string announced by the screen reader. + * - `success`: A boolean indicating whether the announcement was + * successfully made. + * + * See https://reactnative.dev/docs/accessibilityinfo#addeventlistener + */ + addEventListener>( + eventName: K, + handler: (...$ElementType) => void, + ): EventSubscription, + + /** + * Set accessibility focus to a React component. + * + * See https://reactnative.dev/docs/accessibilityinfo#setaccessibilityfocus + */ + setAccessibilityFocus: (reactTag: number) => void, + + /** + * Send a named accessibility event to a HostComponent. + */ + sendAccessibilityEvent: ( + handle: ElementRef>, + eventType: AccessibilityEventTypes, + ) => void, + + /** + * Post a string to be announced by the screen reader. + * + * See https://reactnative.dev/docs/accessibilityinfo#announceforaccessibility + */ + announceForAccessibility: (announcement: string) => void, + + /** + * Post a string to be announced by the screen reader. + * - `announcement`: The string announced by the screen reader. + * - `options`: An object that configures the reading options. + * - `queue`: The announcement will be queued behind existing announcements. iOS only. + */ + announceForAccessibilityWithOptions: ( + announcement: string, + options: {queue?: boolean}, + ) => void, + + /** + * Get the recommended timeout for changes to the UI needed by this user. + * + * See https://reactnative.dev/docs/accessibilityinfo#getrecommendedtimeoutmillis + */ + getRecommendedTimeoutMillis: (originalTimeout: number) => Promise, +}; diff --git a/Libraries/Components/AccessibilityInfo/AccessibilityInfo.js b/Libraries/Components/AccessibilityInfo/AccessibilityInfo.js index db3f6828f3635e..908dd2f4a35015 100644 --- a/Libraries/Components/AccessibilityInfo/AccessibilityInfo.js +++ b/Libraries/Components/AccessibilityInfo/AccessibilityInfo.js @@ -8,17 +8,18 @@ * @format */ -import RCTDeviceEventEmitter from '../../EventEmitter/RCTDeviceEventEmitter'; -import {sendAccessibilityEvent} from '../../Renderer/shims/ReactNative'; import type {HostComponent} from '../../Renderer/shims/ReactNativeTypes'; -import Platform from '../../Utilities/Platform'; -import type EventEmitter from '../../vendor/emitter/EventEmitter'; import type {EventSubscription} from '../../vendor/emitter/EventEmitter'; -import NativeAccessibilityInfoAndroid from './NativeAccessibilityInfo'; -import NativeAccessibilityManagerApple from './NativeAccessibilityManager'; -import legacySendAccessibilityEvent from './legacySendAccessibilityEvent'; +import type {AccessibilityInfoType} from './AccessibilityInfo.flow'; import type {ElementRef} from 'react'; +import RCTDeviceEventEmitter from '../../EventEmitter/RCTDeviceEventEmitter'; +import {sendAccessibilityEvent} from '../../ReactNative/RendererProxy'; +import Platform from '../../Utilities/Platform'; +import legacySendAccessibilityEvent from './legacySendAccessibilityEvent'; +import NativeAccessibilityInfoAndroid from './NativeAccessibilityInfo'; +import NativeAccessibilityManagerApple from './NativeAccessibilityManager'; // [macOS] + // Events that are only supported on Android. type AccessibilityEventDefinitionsAndroid = { accessibilityServiceChanged: [boolean], @@ -33,10 +34,17 @@ type AccessibilityEventDefinitionsIOS = { reduceTransparencyChanged: [boolean], }; +// [macOS +// Events that are only supported on macOS. +type AccessibilityEventDefinitionsMacOS = { + highContrastChanged: [boolean], // [macOS] highContrastChanged is used on macOS +}; +// macOS] + type AccessibilityEventDefinitions = { ...AccessibilityEventDefinitionsAndroid, ...AccessibilityEventDefinitionsIOS, - highContrastChanged: [boolean], // [macOS] highContrastChanged is used on macOS + ...AccessibilityEventDefinitionsMacOS, // [macOS] change: [boolean], // screenReaderChanged reduceMotionChanged: [boolean], screenReaderChanged: [boolean], @@ -76,7 +84,7 @@ const EventNames: Map< * * See https://reactnative.dev/docs/accessibilityinfo */ -const AccessibilityInfo = { +const AccessibilityInfo: AccessibilityInfoType = { /** * Query whether bold text is currently enabled. * @@ -131,10 +139,10 @@ const AccessibilityInfo = { // macOS] }, + // [macOS /** * macOS only */ - // [macOS isHighContrastEnabled: function (): Promise { if (Platform.OS === 'macos') { return new Promise((resolve, reject) => { @@ -209,6 +217,35 @@ const AccessibilityInfo = { }); }, + /** + * Query whether reduce motion and prefer cross-fade transitions settings are currently enabled. + * + * Returns a promise which resolves to a boolean. + * The result is `true` when prefer cross-fade transitions is enabled and `false` otherwise. + * + * See https://reactnative.dev/docs/accessibilityinfo#prefersCrossFadeTransitions + */ + prefersCrossFadeTransitions(): Promise { + return new Promise((resolve, reject) => { + if (Platform.OS === 'android') { + return Promise.resolve(false); + } else { + if ( + NativeAccessibilityManagerApple?.getCurrentPrefersCrossFadeTransitionsState != // [macOS] + null + ) { + // [macOS] + NativeAccessibilityManagerApple.getCurrentPrefersCrossFadeTransitionsState( + resolve, + reject, + ); + } else { + reject(null); + } + } + }); + }, + /** * Query whether reduced transparency is currently enabled. * @@ -328,12 +365,14 @@ const AccessibilityInfo = { */ addEventListener>( eventName: K, + // $FlowIssue[incompatible-type] - Flow bug with unions and generics (T128099423) handler: (...$ElementType) => void, ): EventSubscription { const deviceEventName = EventNames.get(eventName); return deviceEventName == null ? {remove(): void {}} - : RCTDeviceEventEmitter.addListener(deviceEventName, handler); + : // $FlowFixMe[incompatible-call] + RCTDeviceEventEmitter.addListener(deviceEventName, handler); }, /** @@ -348,7 +387,7 @@ const AccessibilityInfo = { /** * Send a named accessibility event to a HostComponent. */ - sendAccessibilityEvent_unstable( + sendAccessibilityEvent( handle: ElementRef>, eventType: AccessibilityEventTypes, ) { @@ -369,7 +408,7 @@ const AccessibilityInfo = { if (Platform.OS === 'android') { NativeAccessibilityInfoAndroid?.announceForAccessibility(announcement); } else { - NativeAccessibilityManagerApple?.announceForAccessibility(announcement); + NativeAccessibilityManagerApple?.announceForAccessibility(announcement); // [macOS] } }, @@ -386,7 +425,7 @@ const AccessibilityInfo = { if (Platform.OS === 'android') { NativeAccessibilityInfoAndroid?.announceForAccessibility(announcement); } else { - // [macOS NativeAccessibilityManagerIOS -> NativeAccessibilityManagerApple + // [macOS NativeAccessibilityManagerApple -> NativeAccessibilityManagerApple if ( NativeAccessibilityManagerApple?.announceForAccessibilityWithOptions ) { @@ -401,25 +440,6 @@ const AccessibilityInfo = { } }, - /** - * @deprecated Use `remove` on the EventSubscription from `addEventListener`. - */ - removeEventListener>( - eventName: K, - handler: (...$ElementType) => void, - ): void { - // NOTE: This will report a deprecation notice via `console.error`. - const deviceEventName = EventNames.get(eventName); - if (deviceEventName != null) { - // $FlowIgnore[incompatible-cast] - (RCTDeviceEventEmitter: EventEmitter<$FlowFixMe>).removeListener( - 'deviceEventName', - // $FlowFixMe[invalid-tuple-arity] - handler, - ); - } - }, - /** * Get the recommended timeout for changes to the UI needed by this user. * diff --git a/Libraries/Components/AccessibilityInfo/NativeAccessibilityInfo.js b/Libraries/Components/AccessibilityInfo/NativeAccessibilityInfo.js index beee9e28517569..e4661589749a04 100644 --- a/Libraries/Components/AccessibilityInfo/NativeAccessibilityInfo.js +++ b/Libraries/Components/AccessibilityInfo/NativeAccessibilityInfo.js @@ -9,6 +9,7 @@ */ import type {TurboModule} from '../../TurboModule/RCTExport'; + import * as TurboModuleRegistry from '../../TurboModule/TurboModuleRegistry'; export interface Spec extends TurboModule { diff --git a/Libraries/Components/AccessibilityInfo/NativeAccessibilityManager.js b/Libraries/Components/AccessibilityInfo/NativeAccessibilityManager.js index 5bb2e5d8a11d24..35e54a2340021c 100644 --- a/Libraries/Components/AccessibilityInfo/NativeAccessibilityManager.js +++ b/Libraries/Components/AccessibilityInfo/NativeAccessibilityManager.js @@ -9,6 +9,7 @@ */ import type {TurboModule} from '../../TurboModule/RCTExport'; + import * as TurboModuleRegistry from '../../TurboModule/TurboModuleRegistry'; export interface Spec extends TurboModule { @@ -34,6 +35,10 @@ export interface Spec extends TurboModule { onSuccess: (isReduceMotionEnabled: boolean) => void, onError: (error: Object) => void, ) => void; + +getCurrentPrefersCrossFadeTransitionsState?: ( + onSuccess: (prefersCrossFadeTransitions: boolean) => void, + onError: (error: Object) => void, + ) => void; +getCurrentReduceTransparencyState: ( onSuccess: (isReduceTransparencyEnabled: boolean) => void, onError: (error: Object) => void, diff --git a/Libraries/Components/ActivityIndicator/ActivityIndicator.d.ts b/Libraries/Components/ActivityIndicator/ActivityIndicator.d.ts new file mode 100644 index 00000000000000..f1a4b246dd44fe --- /dev/null +++ b/Libraries/Components/ActivityIndicator/ActivityIndicator.d.ts @@ -0,0 +1,86 @@ +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @format + */ + +import type * as React from 'react'; +import {Constructor} from '../../../types/private/Utilities'; +import {NativeMethods} from '../../../types/public/ReactNativeTypes'; +import {ColorValue, StyleProp} from '../../StyleSheet/StyleSheet'; +import {ViewStyle} from '../../StyleSheet/StyleSheetTypes'; +import {LayoutChangeEvent} from '../../Types/CoreEventTypes'; +import {ViewProps} from '../View/ViewPropTypes'; + +/** + * @see https://reactnative.dev/docs/activityindicator#props + */ +export interface ActivityIndicatorProps extends ViewProps { + /** + * Whether to show the indicator (true, the default) or hide it (false). + */ + animating?: boolean | undefined; + + /** + * The foreground color of the spinner (default is gray). + */ + color?: ColorValue | undefined; + + /** + * Whether the indicator should hide when not animating (true by default). + */ + hidesWhenStopped?: boolean | undefined; + + /** + * Size of the indicator. + * Small has a height of 20, large has a height of 36. + * + * enum('small', 'large') + */ + size?: number | 'small' | 'large' | undefined; + + style?: StyleProp | undefined; +} + +declare class ActivityIndicatorComponent extends React.Component {} +declare const ActivityIndicatorBase: Constructor & + typeof ActivityIndicatorComponent; +export class ActivityIndicator extends ActivityIndicatorBase {} + +/** + * @see https://reactnative.dev/docs/activityindicatorios#props + */ +export interface ActivityIndicatorIOSProps extends ViewProps { + /** + * Whether to show the indicator (true, the default) or hide it (false). + */ + animating?: boolean | undefined; + + /** + * The foreground color of the spinner (default is gray). + */ + color?: ColorValue | undefined; + + /** + * Whether the indicator should hide when not animating (true by default). + */ + hidesWhenStopped?: boolean | undefined; + + /** + * Invoked on mount and layout changes with + */ + onLayout?: ((event: LayoutChangeEvent) => void) | undefined; + + /** + * Size of the indicator. + * Small has a height of 20, large has a height of 36. + * + * enum('small', 'large') + */ + size?: 'small' | 'large' | undefined; + + style?: StyleProp | undefined; +} diff --git a/Libraries/Components/ActivityIndicator/ActivityIndicator.flow.js b/Libraries/Components/ActivityIndicator/ActivityIndicator.flow.js new file mode 100644 index 00000000000000..ebfb8272cb2579 --- /dev/null +++ b/Libraries/Components/ActivityIndicator/ActivityIndicator.flow.js @@ -0,0 +1,58 @@ +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @format + * @flow + */ + +'use strict'; +import type {HostComponent} from '../../Renderer/shims/ReactNativeTypes'; +import type {ViewProps} from '../View/ViewPropTypes'; + +import {type ColorValue} from '../../StyleSheet/StyleSheet'; +import * as React from 'react'; + +type IndicatorSize = number | 'small' | 'large'; + +type IOSProps = $ReadOnly<{| + /** + Whether the indicator should hide when not animating. + + @platform ios + */ + hidesWhenStopped?: ?boolean, +|}>; + +type Props = $ReadOnly<{| + ...ViewProps, + ...IOSProps, + + /** + Whether to show the indicator (`true`) or hide it (`false`). + */ + animating?: ?boolean, + + /** + The foreground color of the spinner. + + @default {@platform android} `null` (system accent default color) + @default {@platform ios} '#999999' + */ + color?: ?ColorValue, + + /** + Size of the indicator. + + @type enum(`'small'`, `'large'`) + @type {@platform android} number + */ + size?: ?IndicatorSize, +|}>; + +export type ActivityIndicator = React.AbstractComponent< + Props, + HostComponent, +>; diff --git a/Libraries/Components/ActivityIndicator/ActivityIndicator.js b/Libraries/Components/ActivityIndicator/ActivityIndicator.js index eb8b733e15a2cd..0b57dc1273bd29 100644 --- a/Libraries/Components/ActivityIndicator/ActivityIndicator.js +++ b/Libraries/Components/ActivityIndicator/ActivityIndicator.js @@ -10,12 +10,13 @@ */ 'use strict'; -import * as React from 'react'; -import Platform from '../../Utilities/Platform'; +import type {ViewProps} from '../View/ViewPropTypes'; +import type {ActivityIndicator as ActivityIndicatorType} from './ActivityIndicator.flow'; + import StyleSheet, {type ColorValue} from '../../StyleSheet/StyleSheet'; +import Platform from '../../Utilities/Platform'; import View from '../View/View'; -import type {HostComponent} from '../../Renderer/shims/ReactNativeTypes'; -import type {ViewProps} from '../View/ViewPropTypes'; +import * as React from 'react'; const PlatformActivityIndicator = Platform.OS === 'android' @@ -183,10 +184,8 @@ const ActivityIndicator = ( ``` */ -const ActivityIndicatorWithRef: React.AbstractComponent< - Props, - HostComponent, -> = React.forwardRef(ActivityIndicator); +const ActivityIndicatorWithRef: ActivityIndicatorType = + React.forwardRef(ActivityIndicator); ActivityIndicatorWithRef.displayName = 'ActivityIndicator'; const styles = StyleSheet.create({ diff --git a/Libraries/Components/ActivityIndicator/ActivityIndicatorViewNativeComponent.js b/Libraries/Components/ActivityIndicator/ActivityIndicatorViewNativeComponent.js index 548069e885d653..7394582902dcf0 100644 --- a/Libraries/Components/ActivityIndicator/ActivityIndicatorViewNativeComponent.js +++ b/Libraries/Components/ActivityIndicator/ActivityIndicatorViewNativeComponent.js @@ -8,13 +8,12 @@ * @flow strict-local */ -import type {WithDefault} from '../../Types/CodegenTypes'; - +import type {HostComponent} from '../../Renderer/shims/ReactNativeTypes'; import type {ColorValue} from '../../StyleSheet/StyleSheet'; +import type {WithDefault} from '../../Types/CodegenTypes'; import type {ViewProps} from '../View/ViewPropTypes'; import codegenNativeComponent from '../../Utilities/codegenNativeComponent'; -import type {HostComponent} from '../../Renderer/shims/ReactNativeTypes'; type NativeProps = $ReadOnly<{| ...ViewProps, diff --git a/Libraries/Components/ActivityIndicator/__tests__/ActivityIndicator-test.js b/Libraries/Components/ActivityIndicator/__tests__/ActivityIndicator-test.js index 91cb7bd6e29291..1c1338618976d8 100644 --- a/Libraries/Components/ActivityIndicator/__tests__/ActivityIndicator-test.js +++ b/Libraries/Components/ActivityIndicator/__tests__/ActivityIndicator-test.js @@ -4,17 +4,16 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @format - * @emails oncall+react_native * @flow strict-local + * @format + * @oncall react_native */ 'use strict'; -const React = require('react'); -const ActivityIndicator = require('../ActivityIndicator'); - const ReactNativeTestTools = require('../../../Utilities/ReactNativeTestTools'); +const ActivityIndicator = require('../ActivityIndicator'); +const React = require('react'); describe('', () => { it('should set displayName to prevent regressions', () => { diff --git a/Libraries/Components/Button.d.ts b/Libraries/Components/Button.d.ts new file mode 100644 index 00000000000000..706307156b8516 --- /dev/null +++ b/Libraries/Components/Button.d.ts @@ -0,0 +1,42 @@ +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @format + */ + +import type * as React from 'react'; +import {ColorValue} from '../StyleSheet/StyleSheet'; +import {TouchableNativeFeedbackProps} from './Touchable/TouchableNativeFeedback'; +import {TouchableOpacityProps} from './Touchable/TouchableOpacity'; + +export interface ButtonProps + extends Pick< + TouchableNativeFeedbackProps & TouchableOpacityProps, + | 'accessibilityLabel' + | 'accessibilityState' + | 'hasTVPreferredFocus' + | 'nextFocusDown' + | 'nextFocusForward' + | 'nextFocusLeft' + | 'nextFocusRight' + | 'nextFocusUp' + | 'testID' + | 'disabled' + | 'onPress' + | 'touchSoundDisabled' + > { + /** + * Text to display inside the button. On Android the given title will be converted to the uppercased form. + */ + title: string; + + /** + * Color of the text (iOS), or background color of the button (Android). + */ + color?: ColorValue | undefined; +} + +export class Button extends React.Component {} diff --git a/Libraries/Components/Button.flow.js b/Libraries/Components/Button.flow.js new file mode 100644 index 00000000000000..1cf32db90e76dc --- /dev/null +++ b/Libraries/Components/Button.flow.js @@ -0,0 +1,318 @@ +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @format + * @flow + * @generate-docs + */ + +'use strict'; + +import type {PressEvent} from '../Types/CoreEventTypes'; +import type {BlurEvent, FocusEvent, KeyEvent} from '../Types/CoreEventTypes'; // [macOS] +import type { + AccessibilityActionEvent, + AccessibilityActionInfo, + // [macOS + AccessibilityRole, + // macOS] + AccessibilityState, +} from './View/ViewAccessibility'; + +import {type ColorValue} from '../StyleSheet/StyleSheet'; +import * as React from 'react'; + +type ButtonProps = $ReadOnly<{| + /** + Text to display inside the button. On Android the given title will be + converted to the uppercased form. + */ + title: string, + + /** + Handler to be called when the user taps the button. The first function + argument is an event in form of [PressEvent](pressevent). + */ + onPress: (event?: PressEvent) => mixed, + + /** + If `true`, doesn't play system sound on touch. + + @platform android + + @default false + */ + touchSoundDisabled?: ?boolean, + + /** + Color of the text (iOS), or background color of the button (Android). + + @default {@platform android} '#2196F3' + @default {@platform ios} '#007AFF' + */ + color?: ?ColorValue, + + /** + TV preferred focus. + + @platform tv + + @default false + */ + hasTVPreferredFocus?: ?boolean, + + /** + Designates the next view to receive focus when the user navigates down. See + the [Android documentation][android:nextFocusDown]. + + [android:nextFocusDown]: + https://developer.android.com/reference/android/view/View.html#attr_android:nextFocusDown + + @platform android, tv + */ + nextFocusDown?: ?number, + + /** + Designates the next view to receive focus when the user navigates forward. + See the [Android documentation][android:nextFocusForward]. + + [android:nextFocusForward]: + https://developer.android.com/reference/android/view/View.html#attr_android:nextFocusForward + + @platform android, tv + */ + nextFocusForward?: ?number, + + /** + Designates the next view to receive focus when the user navigates left. See + the [Android documentation][android:nextFocusLeft]. + + [android:nextFocusLeft]: + https://developer.android.com/reference/android/view/View.html#attr_android:nextFocusLeft + + @platform android, tv + */ + nextFocusLeft?: ?number, + + /** + Designates the next view to receive focus when the user navigates right. See + the [Android documentation][android:nextFocusRight]. + + [android:nextFocusRight]: + https://developer.android.com/reference/android/view/View.html#attr_android:nextFocusRight + + @platform android, tv + */ + nextFocusRight?: ?number, + + /** + Designates the next view to receive focus when the user navigates up. See + the [Android documentation][android:nextFocusUp]. + + [android:nextFocusUp]: + https://developer.android.com/reference/android/view/View.html#attr_android:nextFocusUp + + @platform android, tv + */ + nextFocusUp?: ?number, + + /** + Text to display for blindness accessibility features. + */ + accessibilityLabel?: ?string, + /** + * Alias for accessibilityLabel https://reactnative.dev/docs/view#accessibilitylabel + * https://github.com/facebook/react-native/issues/34424 + */ + 'aria-label'?: ?string, + /** + If `true`, disable all interactions for this component. + + @default false + */ + disabled?: ?boolean, + + /** + Used to locate this view in end-to-end tests. + */ + testID?: ?string, + + /** + * Accessibility props. + */ + accessible?: ?boolean, + accessibilityActions?: ?$ReadOnlyArray, + onAccessibilityAction?: ?(event: AccessibilityActionEvent) => mixed, + accessibilityState?: ?AccessibilityState, + + /** + * [Android] Controlling if a view fires accessibility events and if it is reported to accessibility services. + */ + importantForAccessibility?: ?('auto' | 'yes' | 'no' | 'no-hide-descendants'), + accessibilityHint?: ?string, + accessibilityLanguage?: ?Stringish, + + // [macOS + /** + * Custom accessibility role -- otherwise we use button + */ + accessibilityRole?: ?AccessibilityRole, + + /** + * Accessibility action handlers + */ + onAccessibilityAction?: ?(event: AccessibilityActionEvent) => mixed, + + /** + * Handler to be called when the button receives key focus + */ + onBlur?: ?(e: BlurEvent) => void, + + /** + * Handler to be called when the button loses key focus + */ + onFocus?: ?(e: FocusEvent) => void, + + /** + * Handler to be called when a key down press is detected + */ + onKeyDown?: ?(e: KeyEvent) => void, + + /** + * Handler to be called when a key up press is detected + */ + onKeyUp?: ?(e: KeyEvent) => void, + + /* + * Array of keys to receive key down events for + * For arrow keys, add "ArrowLeft", "ArrowRight", "ArrowUp", "ArrowDown", + */ + validKeysDown?: ?Array, + + /* + * Array of keys to receive key up events for + * For arrow keys, add "ArrowLeft", "ArrowRight", "ArrowUp", "ArrowDown", + */ + validKeysUp?: ?Array, + + /* + * Specifies the Tooltip for the view + */ + tooltip?: string, + // macOS] +|}>; + +/** + A basic button component that should render nicely on any platform. Supports a + minimal level of customization. + + If this button doesn't look right for your app, you can build your own button + using [TouchableOpacity](touchableopacity) or + [TouchableWithoutFeedback](touchablewithoutfeedback). For inspiration, look at + the [source code for this button component][button:source]. Or, take a look at + the [wide variety of button components built by the community] + [button:examples]. + + [button:source]: + https://github.com/facebook/react-native/blob/HEAD/Libraries/Components/Button.js + + [button:examples]: + https://js.coach/?menu%5Bcollections%5D=React%20Native&page=1&query=button + + ```jsx +