diff --git a/appveyor.yml b/.appveyor/config.yml similarity index 95% rename from appveyor.yml rename to .appveyor/config.yml index c41066d86eca60..85b77e9664a251 100644 --- a/appveyor.yml +++ b/.appveyor/config.yml @@ -1,8 +1,8 @@ environment: ANDROID_HOME: "C:\\android-sdk-windows" ANDROID_NDK: "C:\\android-sdk-windows\\android-ndk-r17c" - ANDROID_BUILD_VERSION: 27 - ANDROID_TOOLS_VERSION: 27.0.3 + ANDROID_BUILD_VERSION: 28 + ANDROID_TOOLS_VERSION: 28.0.3 GRADLE_OPTS: -Dorg.gradle.daemon=false diff --git a/.buckconfig b/.buckconfig index 18bc1909ec0766..de7e1f2e3895c1 100644 --- a/.buckconfig +++ b/.buckconfig @@ -7,7 +7,7 @@ [maven_repositories] central = https://repo1.maven.org/maven2 - google = https://maven.google.com + google = https://dl.google.com/dl/android/maven2/ [alias] rntester = //RNTester/android/app:app diff --git a/.circleci/config.yml b/.circleci/config.yml index 65770d6a99a83f..ab5385eecfd72d 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -3,7 +3,7 @@ aliases: - &restore-yarn-cache keys: - v1-yarn-cache-{{ arch }}-{{ checksum "package.json" }} - - v1-yarn-cache-{{ arch }} + - v1-yarn-cache-{{ arch }}-fixed - &save-yarn-cache paths: - ~/.cache/yarn @@ -36,16 +36,14 @@ aliases: - &restore-cache-gradle keys: - - v1-gradle-{{ .Branch }}-{{ checksum "build.gradle" }}-{{ checksum "ReactAndroid/build.gradle" }} + - v2-gradle-{{ .Branch }}-{{ checksum "build.gradle" }}-{{ checksum "ReactAndroid/build.gradle" }} # Fallback in case checksum fails - - v1-gradle-{{ .Branch }}-{{ checksum "build.gradle" }}- - - v1-gradle-{{ .Branch }}- - # Fallback in case this is a first-time run on a fork - - v1-gradle-master- + - v2-gradle-{{ .Branch }}-{{ checksum "build.gradle" }}- + - v2-gradle-{{ .Branch }}-fixed - &save-cache-gradle paths: - ~/.gradle - key: v1-gradle-{{ .Branch }}-{{ checksum "build.gradle" }}-{{ checksum "ReactAndroid/build.gradle" }} + key: v2-gradle-{{ .Branch }}-{{ checksum "build.gradle" }}-{{ checksum "ReactAndroid/build.gradle" }} - &restore-cache-ndk keys: @@ -57,13 +55,13 @@ aliases: - &restore-cache-downloads-buck keys: - - v3-buck-v2018.07.23.01-{{ checksum "scripts/circleci/buck_fetch.sh" }}} - - v3-buck-v2018.07.23.01- + - v3-buck-v2018.10.29.01-{{ checksum "scripts/circleci/buck_fetch.sh" }}} + - v3-buck-v2018.10.29.01-fixed - &save-cache-downloads-buck paths: - ~/buck - ~/okbuck - key: v3-buck-v2018.07.23.01-{{ checksum "scripts/circleci/buck_fetch.sh" }} + key: v3-buck-v2018.10.29.01-{{ checksum "scripts/circleci/buck_fetch.sh" }} - &restore-cache-watchman keys: @@ -75,14 +73,22 @@ aliases: - &restore-cache-downloads-gradle keys: - - v1-gradle-{{ checksum "ReactAndroid/build.gradle" }}-{{ checksum "scripts/circleci/gradle_download_deps.sh" }} - - v1-gradle- + - v2-gradle-{{ checksum "ReactAndroid/build.gradle" }}-{{ checksum "scripts/circleci/gradle_download_deps.sh" }} + - v2-gradle-fixed - &save-cache-downloads-gradle paths: - ~/.gradle - ReactAndroid/build/downloads - ReactAndroid/build/third-party-ndk - key: v1-gradle-{{ checksum "ReactAndroid/build.gradle" }}-{{ checksum "scripts/circleci/gradle_download_deps.sh" }} + key: v2-gradle-{{ checksum "ReactAndroid/build.gradle" }}-{{ checksum "scripts/circleci/gradle_download_deps.sh" }} + + - &restore-cache-homebrew + keys: + - v1-homebrew-fixed + - &save-cache-homebrew + paths: + - /usr/local/Homebrew + key: v1-homebrew # Branch Filtering - &filter-only-master-stable @@ -132,7 +138,7 @@ aliases: name: Install BUCK command: | if [[ ! -e ~/buck ]]; then - git clone https://github.com/facebook/buck.git ~/buck --branch v2018.07.23.01 --depth=1 + git clone https://github.com/facebook/buck.git ~/buck --branch v2018.10.29.01 --depth=1 fi cd ~/buck && ant buck --version @@ -185,15 +191,19 @@ aliases: name: Lint code command: scripts/circleci/exec_swallow_error.sh yarn lint --format junit -o ~/react-native/reports/junit/eslint/results.xml - - &run-flow-checks - name: Check for errors in code using Flow - command: yarn flow check + - &run-flow-checks-ios + name: Check for errors in code using Flow (iOS) + command: yarn flow-check-ios + + - &run-flow-checks-android + name: Check for errors in code using Flow (Android) + command: yarn flow-check-android - &run-sanity-checks name: Sanity checks command: | ./scripts/circleci/check_license.sh - ./scripts/circleci/check_cache.sh + ./scripts/circleci/validate_yarn_lockfile.sh when: always - &download-dependencies-gradle @@ -229,7 +239,7 @@ aliases: - &compile-native-libs name: Compile Native Libs for Unit and Integration Tests - command: ./gradlew :ReactAndroid:packageReactNdkLibsForBuck -Pjobs=$BUILD_THREADS -Pcom.android.build.threadPoolSize=1 + command: ./gradlew :ReactAndroid:packageReactNdkLibsForBuck -Pjobs=$BUILD_THREADS no_output_timeout: 6m - &run-android-unit-tests @@ -273,20 +283,12 @@ aliases: - &boot-simulator-iphone name: Boot iPhone Simulator - command: xcrun simctl boot "iPhone 5s" || true - - - &boot-simulator-appletv - name: Boot Apple TV Simulator - command: xcrun simctl boot "Apple TV" || true + command: source scripts/.tests.env && xcrun simctl boot "$IOS_DEVICE" || true - &run-objc-ios-tests name: iOS Test Suite command: ./scripts/objc-test-ios.sh test - - &run-objc-tvos-tests - name: tvOS Test Suite - command: ./scripts/objc-test-tvos.sh test - - &display-broken-tests-warning name: Running broken tests (Ignore any failures past this point) command: | @@ -300,16 +302,12 @@ aliases: - &run-e2e-tests name: End-to-End Test Suite (Disabled) - command: ./scripts/circleci/exec_author_check.sh node ./scripts/run-ci-e2e-tests.js --android --ios --tvos --js --retries 3; + command: ./scripts/circleci/exec_author_check.sh node ./scripts/run-ci-e2e-tests.js --android --ios --js --retries 3; - &run-objc-ios-e2e-tests name: iOS End-to-End Test Suite (Disabled) command: ./scripts/circleci/exec_author_check.sh node ./scripts/run-ci-e2e-tests.js --ios --retries 3; - - &run-objc-tvos-e2e-tests - name: tvOS End-to-End Test Suite (Disabled) - command: ./scripts/circleci/exec_author_check.sh node ./scripts/run-ci-e2e-tests.js --tvos --js --retries 3; - - &run-android-e2e-tests name: Android End-to-End Test Suite (Disabled) command: ./scripts/circleci/exec_author_check.sh node ./scripts/run-ci-e2e-tests.js --android --retries 3; @@ -346,7 +344,7 @@ android_defaults: &android_defaults macos_defaults: &macos_defaults <<: *defaults macos: - xcode: "9.4.0" + xcode: "10.1.0" version: 2 jobs: @@ -377,7 +375,8 @@ jobs: at: ~/react-native - run: *run-lint-checks - - run: *run-flow-checks + - run: *run-flow-checks-ios + - run: *run-flow-checks-android - store_test_results: path: ~/react-native/reports/junit @@ -411,25 +410,19 @@ jobs: - store_test_results: path: ~/react-native/reports/junit - # Runs unit tests on iOS and Apple TV devices - test_objc: + # Runs unit tests on iOS devices + test_ios: <<: *macos_defaults steps: - attach_workspace: at: ~/react-native - run: *boot-simulator-iphone - - run: *boot-simulator-appletv - - run: *brew-install-watchman + - restore-cache: *restore-cache-homebrew + - run: *brew-install-watchman + - save-cache: *save-cache-homebrew - run: *run-objc-ios-tests - - run: *run-objc-tvos-tests - - # TODO: Fix these failing tests. - - run: *display-broken-tests-warning - - run: *run-podspec-tests - - run: *run-objc-ios-e2e-tests - - run: *run-objc-tvos-e2e-tests - store_test_results: path: ~/react-native/reports/junit @@ -538,12 +531,18 @@ jobs: # Analyze pull request and raise any lint/flow issues. # Issues will be posted to the PR itself via GitHub bots. # This workflow should only fail if the bots fail to run. + # The public github tokens are publicly visible by design analyze_pr: <<: *defaults docker: - image: circleci/node:10 environment: - PATH: "/opt/yarn/yarn-v1.5.1/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" + - PUBLIC_PULLBOT_GITHUB_TOKEN_A: "a6edf8e8d40ce4e8b11a" + - PUBLIC_PULLBOT_GITHUB_TOKEN_B: "150e1341f4dd9c944d2a" + - PUBLIC_ANALYSISBOT_GITHUB_TOKEN_A: "78a72af35445ca3f8180" + - PUBLIC_ANALYSISBOT_GITHUB_TOKEN_B: "b1a98e0bbd56ff1ccba1" + steps: - checkout - run: *setup-artifacts @@ -552,29 +551,41 @@ jobs: - run: *yarn - run: - name: Analyze Code + name: Analyze Shell Scripts command: | - # GITHUB_TOKEN=eslint-bot public_repo access token - if [ -n "$CIRCLE_PR_NUMBER" ]; then - echo -e "\\x1B[36mInstalling additional dependencies\\x1B[0m"; yarn add @octokit/rest@15.10.0 - echo -e "\\x1B[36mAnalyzing code\\x1B[0m"; GITHUB_TOKEN="af6ef0d15709bc91d""06a6217a5a826a226fb57b7" ./scripts/circleci/analyze_code.sh - else - echo "Skipping code analysis." - fi + echo -e "\\x1B[36mInstalling additional dependencies\\x1B[0m" + sudo apt-get install -y shellcheck + yarn add @octokit/rest@15.10.0 + echo -e "\\x1B[36mAnalyzing shell scripts\\x1B[0m"; \ + GITHUB_TOKEN="$PUBLIC_ANALYSISBOT_GITHUB_TOKEN_A""$PUBLIC_ANALYSISBOT_GITHUB_TOKEN_B" \ + GITHUB_OWNER="$CIRCLE_PROJECT_USERNAME" \ + GITHUB_REPO="$CIRCLE_PROJECT_REPONAME" \ + GITHUB_PR_NUMBER="$CIRCLE_PR_NUMBER" \ + ./scripts/circleci/analyze_scripts.sh when: always - restore-cache: *restore-cache-analysis + - run: + name: Analyze Code + command: | + echo -e "\\x1B[36mInstalling additional dependencies\\x1B[0m"; yarn add @octokit/rest@15.10.0 + echo -e "\\x1B[36mAnalyzing code\\x1B[0m"; \ + GITHUB_TOKEN="$PUBLIC_ANALYSISBOT_GITHUB_TOKEN_A""$PUBLIC_ANALYSISBOT_GITHUB_TOKEN_B" \ + GITHUB_OWNER="$CIRCLE_PROJECT_USERNAME" \ + GITHUB_REPO="$CIRCLE_PROJECT_REPONAME" \ + GITHUB_PR_NUMBER="$CIRCLE_PR_NUMBER" \ + ./scripts/circleci/analyze_code.sh + when: always + - run: name: Analyze Pull Request command: | - # DANGER_GITHUB_API_TOKEN=React-Linter public_repo access token - if [ -n "$CIRCLE_PR_NUMBER" ]; then - cd bots - yarn install --non-interactive --cache-folder ~/.cache/yarn - DANGER_GITHUB_API_TOKEN="80aa64c50f38a267e9ba""575d41d528f9c234edb8" yarn danger - else - echo "Skipping pull request analysis." - fi + echo -e "\\x1B[36mInstalling additional dependencies\\x1B[0m" + cd bots + yarn install --non-interactive --cache-folder ~/.cache/yarn + echo -e "\\x1B[36mAnalyzing pull request\\x1B[0m"; \ + DANGER_GITHUB_API_TOKEN="$PUBLIC_PULLBOT_GITHUB_TOKEN_A""$PUBLIC_PULLBOT_GITHUB_TOKEN_B" \ + yarn danger when: always - save-cache: *save-cache-analysis @@ -659,8 +670,8 @@ workflows: requires: - checkout_code - # Test iOS & tvOS - - test_objc: + # Test iOS + - test_ios: filters: *filter-ignore-gh-pages requires: - checkout_code @@ -670,15 +681,22 @@ workflows: requires: - checkout_code + # Tooling Compatibility Checks + - test_node10: + filters: *filter-ignore-gh-pages + # Only runs on vX.X.X tags if all tests are green - publish_npm_package: filters: + # ignore any commit on any branch by default branches: - only: - - /.*-stable/ + ignore: /.*/ + # only act on version tags tags: only: /v[0-9]+(\.[0-9]+)*(\-rc(\.[0-9]+)?)?/ - # Run code checks + # Run code checks on PRs from forks - analyze_pr: - filters: *filter-ignore-master-stable + filters: + branches: + only: /^pull\/.*$/ diff --git a/.editorconfig b/.editorconfig index 4cde30709106fc..dadac3a2b6d50b 100644 --- a/.editorconfig +++ b/.editorconfig @@ -12,3 +12,6 @@ indent_size = 2 [*.gradle] indent_size = 4 + +[BUCK] +indent_size = 4 diff --git a/.eslintrc b/.eslintrc index 01842b1bcd0e5f..983395c9806b15 100644 --- a/.eslintrc +++ b/.eslintrc @@ -65,6 +65,7 @@ "no-constant-condition": 0, // disallow use of constant expressions in conditions "no-control-regex": 1, // disallow control characters in regular expressions "no-debugger": 1, // disallow use of debugger + "no-dupe-class-members": 2, // Disallow duplicate name in class members "no-dupe-keys": 2, // disallow duplicate keys when creating object literals "no-empty": 0, // disallow empty statements "no-ex-assign": 1, // disallow assigning to the exception in a catch block diff --git a/.flowconfig b/.flowconfig index 5318fc23f4bfcd..90fe54c3f4b959 100644 --- a/.flowconfig +++ b/.flowconfig @@ -63,6 +63,7 @@ module.system.haste.paths.blacklist=.*/__mocks__/.* module.system.haste.paths.whitelist=/Libraries/.* module.system.haste.paths.whitelist=/RNTester/.* module.system.haste.paths.whitelist=/IntegrationTests/.* +module.system.haste.paths.blacklist=/Libraries/react-native/react-native-implementation.js module.system.haste.paths.blacklist=/Libraries/Animated/src/polyfills/.* munge_underscores=true @@ -75,8 +76,8 @@ suppress_type=$FlowFixMe suppress_type=$FlowFixMeProps suppress_type=$FlowFixMeState -suppress_comment=\\(.\\|\n\\)*\\$FlowFixMe\\($\\|[^(]\\|(\\(\\)? *\\(site=[a-z,_]*[react_native\\(_ios\\)?_oss|react_native\\(_ios\\)?_fb][a-z,_]*\\)?)\\) -suppress_comment=\\(.\\|\n\\)*\\$FlowIssue\\((\\(\\)? *\\(site=[a-z,_]*[react_native\\(_ios\\)?_oss|react_native\\(_ios\\)?_fb][a-z,_]*\\)?)\\)?:? #[0-9]+ +suppress_comment=\\(.\\|\n\\)*\\$FlowFixMe\\($\\|[^(]\\|(\\(\\)? *\\(site=[a-z,_]*react_native\\(_ios\\)?_\\(oss\\|fb\\)[a-z,_]*\\)?)\\) +suppress_comment=\\(.\\|\n\\)*\\$FlowIssue\\((\\(\\)? *\\(site=[a-z,_]*react_native\\(_ios\\)?_\\(oss\\|fb\\)[a-z,_]*\\)?)\\)?:? #[0-9]+ suppress_comment=\\(.\\|\n\\)*\\$FlowFixedInNextDeploy suppress_comment=\\(.\\|\n\\)*\\$FlowExpectedError @@ -105,4 +106,7 @@ untyped-import untyped-type-import [version] -^0.78.0 +^0.86.0 + +[untyped] +.*/node_modules/metro/.* diff --git a/.flowconfig.android b/.flowconfig.android new file mode 100644 index 00000000000000..49de66e3b9fa40 --- /dev/null +++ b/.flowconfig.android @@ -0,0 +1,104 @@ +[ignore] +; We fork some components by platform +.*/*[.]ios.js + +; Ignore templates for 'react-native init' +.*/local-cli/templates/.* + +; Ignore the Dangerfile +/bots/dangerfile.js + +; Ignore "BUCK" generated dirs +/\.buckd/ + +; Ignore unexpected extra "@providesModule" +.*/node_modules/.*/node_modules/fbjs/.* + +; Ignore duplicate module providers +; For RN Apps installed via npm, "Libraries" folder is inside +; "node_modules/react-native" but in the source repo it is in the root +.*/Libraries/react-native/React.js + +; Ignore polyfills +.*/Libraries/polyfills/.* + +; These should not be required directly +; require from fbjs/lib instead: require('fbjs/lib/invariant') +.*/node_modules/invariant/.* +.*/node_modules/warning/.* + +[include] + +[libs] +Libraries/react-native/react-native-interface.js +flow/ +flow-github/ + +[options] +emoji=true + +esproposal.optional_chaining=enable +esproposal.nullish_coalescing=enable + +module.system=haste +module.system.haste.use_name_reducers=true +# keep the following in sync with server/haste/hasteImpl.js +# get basename +module.system.haste.name_reducers='^.*/\([a-zA-Z0-9$_.-]+\.js\(\.flow\)?\)$' -> '\1' +# strip .js or .js.flow suffix +module.system.haste.name_reducers='^\(.*\)\.js\(\.flow\)?$' -> '\1' +# strip .android suffix +module.system.haste.name_reducers='^\(.*\)\.android$' -> '\1' +module.system.haste.name_reducers='^\(.*\)\.ios$' -> '\1' +module.system.haste.name_reducers='^\(.*\)\.native$' -> '\1' +module.system.haste.paths.blacklist=.*/__tests__/.* +module.system.haste.paths.blacklist=.*/__mocks__/.* +module.system.haste.paths.whitelist=/Libraries/.* +module.system.haste.paths.whitelist=/RNTester/.* +module.system.haste.paths.whitelist=/IntegrationTests/.* +module.system.haste.paths.blacklist=/Libraries/react-native/react-native-implementation.js +module.system.haste.paths.blacklist=/Libraries/Animated/src/polyfills/.* + +munge_underscores=true + +module.name_mapper='^[./a-zA-Z0-9$_-]+\.\(bmp\|gif\|jpg\|jpeg\|png\|psd\|svg\|webp\|m4v\|mov\|mp4\|mpeg\|mpg\|webm\|aac\|aiff\|caf\|m4a\|mp3\|wav\|html\|pdf\)$' -> 'RelativeImageStub' + +suppress_type=$FlowIssue +suppress_type=$FlowFixMe +suppress_type=$FlowFixMeProps +suppress_type=$FlowFixMeState + +suppress_comment=\\(.\\|\n\\)*\\$FlowFixMe\\($\\|[^(]\\|(\\(\\)? *\\(site=[a-z,_]*react_native\\(_android\\)?_\\(oss\\|fb\\)[a-z,_]*\\)?)\\) +suppress_comment=\\(.\\|\n\\)*\\$FlowIssue\\((\\(\\)? *\\(site=[a-z,_]*react_native\\(_android\\)?_\\(oss\\|fb\\)[a-z,_]*\\)?)\\)?:? #[0-9]+ +suppress_comment=\\(.\\|\n\\)*\\$FlowFixedInNextDeploy +suppress_comment=\\(.\\|\n\\)*\\$FlowExpectedError + +[lints] +all=warn +unnecessary-optional-chain=off + +# There is an ESLint rule for this +unclear-type=off + +sketchy-null=off +sketchy-null-number=warn +sketchy-null-mixed=warn + +# This is noisy for now. We *do* still want to warn on importing types +# from untyped files, which is covered by untyped-type-import +untyped-import=off + +[strict] +deprecated-type +nonstrict-import +sketchy-null +unclear-type +unsafe-getters-setters +untyped-import +untyped-type-import + +[version] +^0.86.0 + +[untyped] +.*/node_modules/metro/.* diff --git a/.github/ISSUE_TEMPLATE/discussion.md b/.github/ISSUE_TEMPLATE/discussion.md index 4bd6a92cfc6e71..b83e727da0a269 100644 --- a/.github/ISSUE_TEMPLATE/discussion.md +++ b/.github/ISSUE_TEMPLATE/discussion.md @@ -3,15 +3,16 @@ name: 🗣 Start a Discussion about: Use https://github.com/react-native-community/discussions-and-proposals to propose changes or discuss feature requests. --- -Please use https://github.com/react-native-community/discussions-and-proposals to propose changes or discuss feature requests. +Use https://github.com/react-native-community/discussions-and-proposals to propose changes or discuss feature requests. This helps us ensure bug reports and regressions are given the priority they require. -We kindly ask that issues of this type are kept in that dedicated repo, to ensure bug reports and regressions are given the priority they require. - -Maintainers may flag an issue for Stack Overflow or kindly ask you to move the discussion to https://github.com/react-native-community/discussions-and-proposals at their own discretion. +You may also use https://discuss.reactjs.org/ for discussions on topics that are not necessarily served by the Bug Report template. --- # For Discussion - + diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index dc039073dc9822..7c1323d0314fb5 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -23,6 +23,3 @@ If you are making a new change then one of the following should be done: #### Focus areas to test (optional) - - - diff --git a/.github/stale.yml b/.github/stale.yml index 538514d6469695..4e334d27a425b0 100644 --- a/.github/stale.yml +++ b/.github/stale.yml @@ -2,7 +2,7 @@ # Number of days of inactivity before an issue becomes stale daysUntilStale: 90 # Number of days of inactivity before a stale issue is closed -daysUntilClose: 30 +daysUntilClose: 7 # Issues with these labels will never be considered stale exemptLabels: - Good first issue @@ -10,6 +10,7 @@ exemptLabels: - Core Team - "Help Wanted :octocat:" - ":warning:Regression" + - ":clock1:PR Pending" # Label to use when marking an issue as stale staleLabel: Stale # Comment to post when marking an issue as stale. Set to `false` to disable diff --git a/.gitignore b/.gitignore index 76e86e6bc8c90f..ef7a07a6cd91aa 100644 --- a/.gitignore +++ b/.gitignore @@ -68,11 +68,9 @@ package-lock.json /third-party /packages/ -/third-party - # Root dir shouldn't have Xcode project /*.xcodeproj # ReactCommon subdir shouldn't have Xcode project /ReactCommon/**/*.xcodeproj -RNTester/build \ No newline at end of file +RNTester/build diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md index 062c7ca1df5c2d..0f7ad8bfc173ea 100644 --- a/CODE_OF_CONDUCT.md +++ b/CODE_OF_CONDUCT.md @@ -1,43 +1,5 @@ -# [Open Source Code of Conduct](https://code.facebook.com/codeofconduct) +# Code of Conduct -This code of conduct outlines our expectations for participants within the **Facebook Open Source** community, as well as steps to reporting unacceptable behavior. We are committed to providing a welcoming and inspiring community for all and expect our code of conduct to be honored. Anyone who violates this code of conduct may be banned from the community. - -Our open source community strives to: - -* **Be friendly and patient.** -* **Be welcoming:** We strive to be a community that welcomes and supports people of all backgrounds and identities. This includes, but is not limited to members of any race, ethnicity, culture, national origin, colour, immigration status, social and economic class, educational level, sex, sexual orientation, gender identity and expression, age, size, family status, political belief, religion, and mental and physical ability. -* **Be considerate:** Your work will be used by other people, and you in turn will depend on the work of others. Any decision you take will affect users and colleagues, and you should take those consequences into account when making decisions. Remember that we’re a world-wide community, so you might not be communicating in someone else’s primary language. -* **Be respectful:** Not all of us will agree all the time, but disagreement is no excuse for poor behavior and poor manners. We might all experience some frustration now and then, but we cannot allow that frustration to turn into a personal attack. It’s important to remember that a community where people feel uncomfortable or threatened is not a productive one. -* **Be careful in the words that you choose:** we are a community of professionals, and we conduct ourselves professionally. Be kind to others. Do not insult or put down other participants. Harassment and other exclusionary behavior aren’t acceptable. This includes, but is not limited to: - * Violent threats or language directed against another person. - * Discriminatory jokes and language. - * Posting sexually explicit or violent material. - * Posting (or threatening to post) other people’s personally identifying information (“doxing”). - * Personal insults, especially those using racist or sexist terms. - * Unwelcome sexual attention. - * Advocating for, or encouraging, any of the above behavior. - * Repeated harassment of others. In general, if someone asks you to stop, then stop. -* **When we disagree, try to understand why:** Disagreements, both social and technical, happen all the time. It is important that we resolve disagreements and differing views constructively. -* **Remember that we’re different.** The strength of our community comes from its diversity, people from a wide range of backgrounds. Different people have different perspectives on issues. Being unable to understand why someone holds a viewpoint doesn’t mean that they’re wrong. Don’t forget that it is human to err and blaming each other doesn’t get us anywhere. Instead, focus on helping to resolve issues and learning from mistakes. - -This code is not exhaustive or complete. It serves to distill our common understanding of a collaborative, shared environment, and goals. We expect it to be followed in spirit as much as in the letter. - -## Diversity Statement - -We encourage everyone to participate and are committed to building a community for all. Although we may not be able to satisfy everyone, we all agree that everyone is equal. Whenever a participant has made a mistake, we expect them to take responsibility for it. If someone has been harmed or offended, it is our responsibility to listen carefully and respectfully, and do our best to right the wrong. - -Although this list cannot be exhaustive, we explicitly honor diversity in age, gender, gender identity or expression, culture, ethnicity, language, national origin, political beliefs, profession, race, religion, sexual orientation, socioeconomic status, and technical ability. We will not tolerate discrimination based on any of the protected characteristics above, including participants with disabilities. - -## Reporting Issues - -If you experience or witness unacceptable behavior—or have any other concerns—please report it by contacting us via opensource@fb.com. All reports will be handled with discretion. In your report please include: - -* Your contact information. -* Names (real, nicknames, or pseudonyms) of any individuals involved. If there are additional witnesses, please include them as well. Your account of what occurred, and if you believe the incident is ongoing. If there is a publicly available record (e.g. a mailing list archive or a public IRC logger), please include a link. -* Any additional information that may be helpful. - -After filing a report, a representative will contact you personally. If the person who is harassing you is part of the response team, they will recuse themselves from handling your incident. A representative will then review the incident, follow up with any additional questions, and make a decision as to how to respond. We will respect confidentiality requests for the purpose of protecting victims of abuse. - -Anyone asked to stop unacceptable behavior is expected to comply immediately. If an individual engages in unacceptable behavior, the representative may take any action they deem appropriate, up to and including a permanent ban from our community without warning. - -_This Code Of Conduct follows the [template](http://todogroup.org/opencodeofconduct/) established by the [TODO Group](http://todogroup.org/)._ +Facebook has adopted a Code of Conduct that we expect project participants to adhere to. +Please read the [full text](https://code.fb.com/codeofconduct/) +so that you can understand what actions will and will not be tolerated. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 25ba2d5c1e1d51..743a6db7f3cecc 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,192 +1,41 @@ # Contributing to React Native - -React Native is one of Facebook's first open source projects that is both under very active development and is also being used to ship code to everybody using Facebook's mobile apps. If you're interested in contributing to React Native, hopefully this document makes the process for contributing clear. +We want to make contributing to this project as easy and transparent as possible. Read on to learn more about our development process and how to propose bug fixes and improvements. The [How to Contribute](https://facebook.github.io/react-native/docs/contributing.html) guide on the website goes into more detail for each of these areas. -## [Code of Conduct](https://code.facebook.com/codeofconduct) +## Our Development Process -Facebook has adopted a Code of Conduct that we expect project participants to adhere to. Please read [the full text](https://code.facebook.com/codeofconduct) so that you can understand what actions will and will not be tolerated. +Most changes from engineers at Facebook will sync to [GitHub](https://github.com/facebook/react-native) through a bridge with Facebook's internal source control. Changes from the community are handled through GitHub pull requests. Once a change made on GitHub is approved, it will first be imported into Facebook's internal source control. The change will eventually sync back to GitHub as a single commit once it has passed Facebook's internal tests. -## Get involved - -There are many ways to contribute to React Native, and many of them do not involve writing any code. Here's a few ideas to get started: - -* Simply start using React Native. Go through the [Getting Started](https://facebook.github.io/react-native/docs/getting-started.html) guide. Does everything work as expected? If not, we're always looking for improvements. Let us know by [opening an issue](https://facebook.github.io/react-native/docs/contributing.html#reporting-new-issues). -* Look through the [open issues](https://github.com/facebook/react-native/issues). Provide workarounds, ask for clarification, or suggest labels. Help [triage issues](https://facebook.github.io/react-native/docs/contributing.html#triaging-issues-and-pull-requests). -* If you find an issue you would like to fix, [open a pull request](https://facebook.github.io/react-native/docs/contributing.html#your-first-pull-request). Issues tagged as [_Good first issue_](https://github.com/facebook/react-native/labels/Good%20first%20issue) are a good place to get started. -* Read through the [React Native docs](https://facebook.github.io/react-native/docs/getting-started.html). If you find anything that is confusing or can be improved, you can make edits by clicking the "EDIT" button in the top-right corner of most docs. -* Browse [Stack Overflow](https://stackoverflow.com/questions/tagged/react-native) and answer questions. This will help you get familiarized with common pitfalls or misunderstandings, which can be useful when contributing updates to the documentation. -* Take a look at the [features requested](https://react-native.canny.io/feature-requests) by others in the community and consider opening a pull request if you see something you want to work on. - -Contributions are very welcome. If you think you need help planning your contribution, please hop into [#react-native](https://discord.gg/0ZcbPKXt5bZjGY5n) and let people know you're looking for a mentor. - -Core contributors to React Native meet monthly and post their meeting notes on the [React Native blog](https://facebook.github.io/react-native/blog). You can also find ad hoc discussions in the [React Native Core Contributors](https://www.facebook.com/groups/reactnativeoss/) Facebook group. - -### Triaging issues and pull requests - -One great way you can contribute to the project without writing any code is to help triage issues and pull requests as they come in. - -* Ask for more information if the issue does not provide all the details required by the template. -* Suggest [labels](https://github.com/facebook/react-native/labels) that can help categorize issues. -* Flag issues that are stale or that should be closed. -* Ask for test plans and review code. - -You can learn more about handling issues in the [maintainer's guide](docs/maintainers.html#handling-issues). - -## Our development process - -Some of the core team will be working directly on [GitHub](https://github.com/facebook/react-native). These changes will be public from the beginning. Other changesets will come via a bridge with Facebook's internal source control. This is a necessity as it allows engineers at Facebook outside of the core team to move fast and contribute from an environment they are comfortable in. - -When a change made on GitHub is approved, it will first be imported into Facebook's internal source control. The change will eventually sync back to GitHub as a single commit once it has passed all internal tests. - -### Branch organization - -We will do our best to keep `master` in good shape, with tests passing at all times. But in order to move fast, we will make API changes that your application might not be compatible with. We will do our best to [communicate these changes](https://github.com/facebook/react-native/releases) and version appropriately so you can lock into a specific version if need be. - -To see what changes are coming and provide better feedback to React Native contributors, use the [latest release candidate](https://facebook.github.io/react-native/versions.html) when possible. By the time a release candidate is released, the changes it contains will have been shipped in production Facebook apps for over two weeks. - -## Bugs - -We use [GitHub Issues](https://github.com/facebook/react-native/issues) for our public bugs. If you would like to report a problem, take a look around and see if someone already opened an issue about it. If you a are certain this is a new, unreported bug, you can submit a [bug report](https://facebook.github.io/react-native/docs/contributing.html#reporting-new-issues). - -If you have questions about using React Native, the [Community page](https://facebook.github.io/react-native/help.html) list various resources that should help you get started. - -We also have a [place where you can request features or enhancements](https://react-native.canny.io/feature-requests). If you see anything you'd like to be implemented, vote it up and explain your use case. - -## Reporting new issues - -When [opening a new issue](https://github.com/facebook/react-native/issues/new), always make sure to fill out the [issue template](https://raw.githubusercontent.com/facebook/react-native/master/.github/ISSUE_TEMPLATE.md). **This step is very important!** Not doing so may result in your issue getting closed. Don't take this personally if this happens, and feel free to open a new issue once you've gathered all the information required by the template. - -* **One issue, one bug:** Please report a single bug per issue. -* **Provide a Snack:** The best way to get attention on your issue is to provide a reduced test case. You can use [Snack](https://snack.expo.io/) to demonstrate the issue. -* **Provide reproduction steps:** List all the steps necessary to reproduce the issue. Provide a Snack or upload a sample project to GitHub. The person reading your bug report should be able to follow these steps to reproduce your issue with minimal effort. -* **Try out the latest version:** Verify that the issue can be reproduced locally by updating your project to use [React Native from `master`](https://facebook.github.io/react-native/versions.html). The bug may have already been fixed! - -We're not able to provide support through GitHub Issues. If you're looking for help with your code, consider asking on [Stack Overflow](https://stackoverflow.com/questions/tagged/react-native) or reaching out to the community through [other channels](https://facebook.github.io/react-native/support.html). - -### Security bugs - -Facebook has a [bounty program](https://www.facebook.com/whitehat/) for the safe disclosure of security bugs. With that in mind, please do not file public issues; go through the process outlined on that page. - -## Pull requests - -### Your first pull request - -So you have decided to contribute code back to upstream by opening a pull request. You've invested a good chunk of time, and we appreciate it. We will do our best to work with you and get the PR looked at. - -Working on your first Pull Request? You can learn how from this free video series: - -[**How to Contribute to an Open Source Project on GitHub**](https://egghead.io/courses/how-to-contribute-to-an-open-source-project-on-github) - -We have a list of [beginner friendly issues](https://github.com/facebook/react-native/labels/Good%20first%20issue) to help you get your feet wet in the React Native codebase and familiar with our contribution process. This is a great place to get started. - -### Proposing a change - -If you would like to request a new feature or enhancement but are not yet thinking about opening a pull request, we have a [place to track feature requests](https://react-native.canny.io/feature-requests). - -If you intend to change the public API, or make any non-trivial changes to the implementation, we recommend [filing an issue](https://github.com/facebook/react-native/issues/new?title=%5BProposal%5D) that includes `[Proposal]` in the title. This lets us reach an agreement on your proposal before you put significant effort into it. These types of issues should be rare. If you have been contributing to the project long enough, you will probably already have access to the [React Native Core Contributors](https://www.facebook.com/groups/reactnativeoss/) Facebook Group, where this sort of discussion is usually held. - -If you're only fixing a bug, it's fine to submit a pull request right away but we still recommend to file an issue detailing what you're fixing. This is helpful in case we don't accept that specific fix but want to keep track of the issue. - -### Sending a pull request - -Small pull requests are much easier to review and more likely to get merged. Make sure the PR does only one thing, otherwise please split it. +## Pull Requests Please make sure the following is done when submitting a pull request: -1. Fork [the repository](https://github.com/facebook/react-native) and create your branch from `master`. -2. Add the copyright notice to the top of any new files you've added. -3. Describe your [**test plan**](https://facebook.github.io/react-native/docs/contributing.html#test-plan) in your pull request description. Make sure to [test your changes](https://facebook.github.io/react-native/docs/testing.html)! -4. Make sure your code lints (`npm run lint`). -5. If you haven't already, [sign the CLA](https://code.facebook.com/cla). - -All pull requests should be opened against the `master` branch. After opening your pull request, ensure [**all tests pass**](https://facebook.github.io/react-native/docs/contributing.html#contrinuous-integration-tests) on Circle CI. If a test fails and you believe it is unrelated to your change, leave a comment on the pull request explaining why. - -> **Note:** It is not necessary to keep clicking `Merge master to your branch` on the PR page. You would want to merge master if there are conflicts or tests are failing. The Facebook-GitHub-Bot ultimately squashes all commits to a single one before merging your PR. - -#### Test plan - -A good test plan has the exact commands you ran and their output, provides screenshots or videos if the pull request changes UI. - -* If you've added code that should be tested, add tests! -* If you've changed APIs, update the documentation. - -See [What is a Test Plan?](https://medium.com/@martinkonicek/what-is-a-test-plan-8bfc840ec171#.y9lcuqqi9) to learn more. - -#### Continuous integration tests - -Make sure all **tests pass** on [Circle CI][circle]. PRs that break tests are unlikely to be merged. Learn more about [testing your changes here](https://facebook.github.io/react-native/docs/testing.html). - -[circle]: https://circleci.com/gh/facebook/react-native +1. Fork the repo and create your branch from `master`. +2. If you've added code that should be tested, add tests. +3. If you've changed APIs, update the documentation. +4. Ensure the test suite passes. +5. Make sure your code lints. +6. If you haven't already, complete the Contributor License Agreement ("CLA"). -#### Breaking changes +## Contributor License Agreement ("CLA") -When adding a new breaking change, follow this template in your pull request: +In order to accept your pull request, we need you to submit a CLA. You only need to do this once to work on any of Facebook's open source projects. -``` -### New breaking change here +Complete your CLA here: -* **Who does this affect**: -* **How to migrate**: -* **Why make this breaking change**: -* **Severity (number of people affected x effort)**: -``` +## Issues -If your pull request is merged, a core contributor will update the [list of breaking changes](https://github.com/facebook/react-native/wiki/Breaking-Changes) which is then used to populate the release notes. +We use GitHub issues to track public bugs. Please ensure your description is clear and has sufficient instructions to be able to reproduce the issue. -#### Copyright Notice for files +Facebook has a [bounty program](https://www.facebook.com/whitehat/) for the safe disclosure of security bugs. In those cases, please go through the process outlined on that page and do not file a public issue. -Copy and paste this to the top of your new file(s): +## Coding Style -```JS -/** - * Copyright (c) 2015-present, Facebook, Inc. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ -``` +We use Prettier to format our JavaScript code. This saves you time and energy as you can let Prettier fix up any formatting issues automatically through its editor integrations, or by manually running `npm run prettier`. We also use a linter to catch styling issues that may exist in your code. You can check the status of your code styling by simply running `npm run lint`. -#### Contributor License Agreement (CLA) +However, there are still some styles that the linter cannot pick up, notably in Java or Objective-C code. -In order to accept your pull request, we need you to submit a CLA. You only need to do this once, so if you've done this for another Facebook open source project, you're good to go. If you are submitting a pull request for the first time, the Facebook GitHub Bot will reply with a link to the CLA form. You may also [complete your CLA here](https://code.facebook.com/cla). - -### What happens next? - -The core team will be monitoring for pull requests. Read [what to expect from maintainers](https://facebook.github.io/react-native/docs/maintainers.html#handling-pull-requests) to understand what may happen after you open a pull request. - -## Style Guide - -Our linter will catch most styling issues that may exist in your code. You can check the status of your code styling by simply running `npm run lint`. - -However, there are still some styles that the linter cannot pick up. - -### Code Conventions - -#### General - -* **Most important: Look around.** Match the style you see used in the rest of the project. This includes formatting, naming things in code, naming things in documentation. -* Add trailing commas, -* 2 spaces for indentation (no tabs) -* "Attractive" - -#### JavaScript - -* Use semicolons; -* ES6 standards -* Prefer `'` over `"` -* Do not use the optional parameters of `setTimeout` and `setInterval` -* 80 character line length - -#### JSX - -* Prefer `"` over `'` for string literal props -* When wrapping opening tags over multiple lines, place one prop per line -* `{}` of props should hug their values (no spaces) -* Place the closing `>` of opening tags on the same line as the last prop -* Place the closing `/>` of self-closing tags on their own line and left-align them with the opening `<` - -#### Objective-C +**Objective-C:** * Space after `@property` declarations * Brackets on *every* `if`, on the *same* line @@ -194,17 +43,13 @@ However, there are still some styles that the linter cannot pick up. * *Try* to keep it around 80 characters line length (sometimes it's just not possible...) * `*` operator goes with the variable name (e.g. `NSObject *variableName;`) -#### Java +**Java:** * If a method call spans multiple lines closing bracket is on the same line as the last argument. * If a method header doesn't fit on one line each argument goes on a separate line. * 100 character line length -### Documentation - -* Do not wrap lines at 80 characters - configure your editor to soft-wrap when editing documentation. - ## License -By contributing to React Native, you agree that your contributions will be licensed under its MIT license. - +By contributing to React Native, you agree that your contributions will be licensed +under the LICENSE file in the root directory of this source tree. diff --git a/ContainerShip/Dockerfile.android b/ContainerShip/Dockerfile.android index 881957d324def5..33ab9da509be6a 100644 --- a/ContainerShip/Dockerfile.android +++ b/ContainerShip/Dockerfile.android @@ -1,3 +1,8 @@ +# 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. + # React Native Android Unit Tests # # This image builds upon the React Native Base Android Development Environment @@ -52,7 +57,7 @@ ADD build.gradle /app/build.gradle ADD react.gradle /app/react.gradle # compile native libs with Gradle script, we need bridge for unit and integration tests -RUN ./gradlew :ReactAndroid:packageReactNdkLibsForBuck -Pjobs=1 -Pcom.android.build.threadPoolSize=1 +RUN ./gradlew :ReactAndroid:packageReactNdkLibsForBuck -Pjobs=1 # add all react-native code ADD . /app diff --git a/ContainerShip/Dockerfile.android-base b/ContainerShip/Dockerfile.android-base index ab9e86dd27c7ad..b07bcd2cf063a3 100644 --- a/ContainerShip/Dockerfile.android-base +++ b/ContainerShip/Dockerfile.android-base @@ -1,3 +1,8 @@ +# 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. + # React Native Base Android Development Environment # # This image provides a base Android development environment for React Native, @@ -18,10 +23,10 @@ LABEL maintainer="Héctor Ramos " # set default build arguments ARG SDK_VERSION=sdk-tools-linux-3859397.zip -ARG ANDROID_BUILD_VERSION=27 -ARG ANDROID_TOOLS_VERSION=27.0.3 -ARG BUCK_VERSION=v2018.07.23.01 -ARG NDK_VERSION=17b +ARG ANDROID_BUILD_VERSION=28 +ARG ANDROID_TOOLS_VERSION=28.0.3 +ARG BUCK_VERSION=v2018.10.29.01 +ARG NDK_VERSION=17c ARG NODE_VERSION=8.10.0 ARG WATCHMAN_VERSION=4.9.0 diff --git a/ContainerShip/Dockerfile.javascript b/ContainerShip/Dockerfile.javascript index 7c1e14bb9b845b..5e077f972318c9 100644 --- a/ContainerShip/Dockerfile.javascript +++ b/ContainerShip/Dockerfile.javascript @@ -1,3 +1,8 @@ +# 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. + FROM library/node:6.9.2 ENV YARN_VERSION=0.27.5 diff --git a/ContainerShip/scripts/run-android-ci-instrumentation-tests.js b/ContainerShip/scripts/run-android-ci-instrumentation-tests.js index c16c7990ed317d..a788bf19b80a26 100644 --- a/ContainerShip/scripts/run-android-ci-instrumentation-tests.js +++ b/ContainerShip/scripts/run-android-ci-instrumentation-tests.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. @@ -38,7 +38,7 @@ const test_opts = { PATH: argv.path || './ReactAndroid/src/androidTest/java/com/facebook/react/tests', RETRIES: parseInt(argv.retries || 2, 10), - TEST_TIMEOUT: parseInt(argv['test-timeout'] || 1000 * 60 * 10), + TEST_TIMEOUT: parseInt(argv['test-timeout'] || 1000 * 60 * 10, 10), OFFSET: argv.offset, COUNT: argv.count, @@ -68,7 +68,6 @@ testClasses = testClasses.map((clazz) => { // only process subset of the tests at corresponding offset and count if args provided if (test_opts.COUNT != null && test_opts.OFFSET != null) { - const testCount = testClasses.length; const start = test_opts.COUNT * test_opts.OFFSET; const end = start + test_opts.COUNT; diff --git a/ContainerShip/scripts/run-android-docker-instrumentation-tests.sh b/ContainerShip/scripts/run-android-docker-instrumentation-tests.sh index ed7183dec9d5fc..63ee31b47cf2d6 100644 --- a/ContainerShip/scripts/run-android-docker-instrumentation-tests.sh +++ b/ContainerShip/scripts/run-android-docker-instrumentation-tests.sh @@ -1,4 +1,10 @@ #!/bin/bash +# +# 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. +# # for buck gen mount -o remount,exec /dev/shm @@ -6,7 +12,7 @@ mount -o remount,exec /dev/shm AVD_UUID=$(cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 8 | head -n 1) # create virtual device -echo no | android create avd -n $AVD_UUID -f -t android-19 --abi default/armeabi-v7a +echo no | android create avd -n "$AVD_UUID" -f -t android-19 --abi default/armeabi-v7a # emulator setup emulator64-arm -avd $AVD_UUID -no-skin -no-audio -no-window -no-boot-anim & @@ -28,8 +34,9 @@ watchman shutdown-server node local-cli/cli.js bundle --platform android --dev true --entry-file ReactAndroid/src/androidTest/js/TestBundle.js --bundle-output ReactAndroid/src/androidTest/assets/AndroidTestBundle.js # 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 # run installed apk with tests -node ./ContainerShip/scripts/run-android-ci-instrumentation-tests.js $* +node ./ContainerShip/scripts/run-android-ci-instrumentation-tests.js "$*" exit $? diff --git a/ContainerShip/scripts/run-android-docker-unit-tests.sh b/ContainerShip/scripts/run-android-docker-unit-tests.sh index 5a58bb352e5421..8653ccd9d19555 100644 --- a/ContainerShip/scripts/run-android-docker-unit-tests.sh +++ b/ContainerShip/scripts/run-android-docker-unit-tests.sh @@ -1,4 +1,10 @@ #!/bin/bash +# +# 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. +# # set default environment variables UNIT_TESTS_BUILD_THREADS="${UNIT_TESTS_BUILD_THREADS:-1}" @@ -9,4 +15,4 @@ mount -o remount,exec /dev/shm set -x # run unit tests -buck test ReactAndroid/src/test/... --config build.threads=$UNIT_TESTS_BUILD_THREADS +buck test ReactAndroid/src/test/... --config build.threads="$UNIT_TESTS_BUILD_THREADS" diff --git a/ContainerShip/scripts/run-ci-e2e-tests.sh b/ContainerShip/scripts/run-ci-e2e-tests.sh index de2b97edb5bb7a..aead257ffce6b4 100755 --- a/ContainerShip/scripts/run-ci-e2e-tests.sh +++ b/ContainerShip/scripts/run-ci-e2e-tests.sh @@ -1,4 +1,10 @@ #!/bin/bash +# +# 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. +# set -ex @@ -12,11 +18,12 @@ RUN_IOS=0 RUN_JS=0 RETRY_COUNT=${RETRY_COUNT:-2} -AVD_UUID=$(cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 8 | head -n 1) - +AVD_UUID=$(< /dev/urandom tr -dc 'a-zA-Z0-9' | fold -w 8 | head -n 1) ANDROID_NPM_DEPS="appium@1.5.1 mocha@2.4.5 wd@0.3.11 colors@1.0.3 pretty-data2@0.40.1" -CLI_PACKAGE=$ROOT/react-native-cli/react-native-cli-*.tgz -PACKAGE=$ROOT/react-native-*.tgz +CLI_PACKAGE="$ROOT/react-native-cli/react-native-cli-*.tgz" +PACKAGE="$ROOT/react-native-*.tgz" +# Version of react-native-dummy to test against +REACT_DUMMY_PLATFORM=react-native-dummy@0.1.0 # solve issue with max user watches limit echo 65536 | tee -a /proc/sys/fs/inotify/max_user_watches @@ -27,7 +34,7 @@ watchman shutdown-server # $2 -- command to run function retry() { local -r -i max_attempts="$1"; shift - local -r cmd="$@" + local -r cmd="$*" local -i attempt_num=1 until $cmd; do @@ -75,7 +82,7 @@ while :; do done function e2e_suite() { - cd $ROOT + cd "$ROOT" if [ $RUN_ANDROID -eq 0 ] && [ $RUN_IOS -eq 0 ] && [ $RUN_JS -eq 0 ]; then echo "No e2e tests specified!" @@ -88,8 +95,8 @@ function e2e_suite() { # To make sure we actually installed the local version # of react-native, we will create a temp file inside the template # and check that it exists after `react-native init - IOS_MARKER=$(mktemp $ROOT/local-cli/templates/HelloWorld/ios/HelloWorld/XXXXXXXX) - ANDROID_MARKER=$(mktemp ${ROOT}/local-cli/templates/HelloWorld/android/XXXXXXXX) + IOS_MARKER="$(mktemp "$ROOT"/local-cli/templates/HelloWorld/ios/HelloWorld/XXXXXXXX)" + ANDROID_MARKER="$(mktemp "$ROOT"/local-cli/templates/HelloWorld/android/XXXXXXXX)" # install CLI cd react-native-cli @@ -98,8 +105,8 @@ function e2e_suite() { # can skip cli install for non sudo mode if [ $RUN_CLI_INSTALL -ne 0 ]; then - npm install -g $CLI_PACKAGE - if [ $? -ne 0 ]; then + if ! npm install -g "$CLI_PACKAGE" + then echo "Could not install react-native-cli globally, please run in su mode" echo "Or with --skip-cli-install to skip this step" return 1 @@ -111,7 +118,7 @@ function e2e_suite() { # create virtual device if ! android list avd | grep "$AVD_UUID" > /dev/null; then - echo no | android create avd -n $AVD_UUID -f -t android-19 --abi default/armeabi-v7a + echo no | android create avd -n "$AVD_UUID" -f -t android-19 --abi default/armeabi-v7a fi # newline at end of adb devices call and first line is headers @@ -124,9 +131,10 @@ function e2e_suite() { fi # emulator setup - emulator64-arm -avd $AVD_UUID -no-skin -no-audio -no-window -no-boot-anim & + emulator64-arm -avd "$AVD_UUID" -no-skin -no-audio -no-window -no-boot-anim & bootanim="" + # shellcheck disable=SC2076 until [[ "$bootanim" =~ "stopped" ]]; do sleep 5 bootanim=$(adb -e shell getprop init.svc.bootanim 2>&1) @@ -135,23 +143,23 @@ function e2e_suite() { set -ex - ./gradlew :ReactAndroid:installArchives -Pjobs=1 -Dorg.gradle.jvmargs="-Xmx512m -XX:+HeapDumpOnOutOfMemoryError" - if [ $? -ne 0 ]; then + if ! ./gradlew :ReactAndroid:installArchives -Pjobs=1 -Dorg.gradle.jvmargs="-Xmx512m -XX:+HeapDumpOnOutOfMemoryError" + then echo "Failed to compile Android binaries" return 1 fi fi - npm pack - if [ $? -ne 0 ]; then + if ! npm pack + then echo "Failed to pack react-native" return 1 fi - cd $TEMP_DIR + cd "$TEMP_DIR" - retry $RETRY_COUNT react-native init EndToEndTest --version $PACKAGE --npm - if [ $? -ne 0 ]; then + if ! retry "$RETRY_COUNT" react-native init EndToEndTest --version "$PACKAGE" --npm + then echo "Failed to execute react-native init" echo "Most common reason is npm registry connectivity, try again" return 1 @@ -164,20 +172,21 @@ function e2e_suite() { echo "Running an Android e2e test" echo "Installing e2e framework" - retry $RETRY_COUNT npm install --save-dev $ANDROID_NPM_DEPS --silent >> /dev/null - if [ $? -ne 0 ]; then + if ! retry "$RETRY_COUNT" npm install --save-dev "$ANDROID_NPM_DEPS" --silent >> /dev/null + then echo "Failed to install appium" echo "Most common reason is npm registry connectivity, try again" return 1 fi - cp $SCRIPTS/android-e2e-test.js android-e2e-test.js + cp "$SCRIPTS/android-e2e-test.js" android-e2e-test.js - cd android + ( + cd android || exit echo "Downloading Maven deps" ./gradlew :app:copyDownloadableDepsToLibs + ) - cd .. keytool -genkey -v -keystore android/keystores/debug.keystore -storepass android -alias androiddebugkey -keypass android -dname "CN=Android Debug,O=Android,C=US" node ./node_modules/.bin/appium >> /dev/null & @@ -188,9 +197,8 @@ function e2e_suite() { buck build android/app # hack to get node unhung (kill buckd) - kill -9 $(pgrep java) - - if [ $? -ne 0 ]; then + if ! kill -9 "$(pgrep java)" + then echo "could not execute Buck build, is it installed and in PATH?" return 1 fi @@ -201,23 +209,23 @@ function e2e_suite() { sleep 15 echo "Executing android e2e test" - retry $RETRY_COUNT node node_modules/.bin/_mocha android-e2e-test.js - if [ $? -ne 0 ]; then + if ! retry "$RETRY_COUNT" node node_modules/.bin/_mocha android-e2e-test.js + then echo "Failed to run Android e2e tests" echo "Most likely the code is broken" return 1 fi # kill packager process - if kill -0 $SERVER_PID; then + if kill -0 "$SERVER_PID"; then echo "Killing packager $SERVER_PID" - kill -9 $SERVER_PID + kill -9 "$SERVER_PID" fi # kill appium process - if kill -0 $APPIUM_PID; then + if kill -0 "$APPIUM_PID"; then echo "Killing appium $APPIUM_PID" - kill -9 $APPIUM_PID + kill -9 "$APPIUM_PID" fi fi @@ -230,24 +238,37 @@ function e2e_suite() { # js tests if [ $RUN_JS -ne 0 ]; then # Check the packager produces a bundle (doesn't throw an error) - react-native bundle --max-workers 1 --platform android --dev true --entry-file index.js --bundle-output android-bundle.js - if [ $? -ne 0 ]; then + if ! react-native bundle --max-workers 1 --platform android --dev true --entry-file index.js --bundle-output android-bundle.js + then echo "Could not build android bundle" return 1 fi - react-native bundle --max-workers 1 --platform ios --dev true --entry-file index.js --bundle-output ios-bundle.js - if [ $? -ne 0 ]; then + if ! react-native bundle --max-workers 1 --platform ios --dev true --entry-file index.js --bundle-output ios-bundle.js + then echo "Could not build iOS bundle" return 1 fi + + if ! retry "$RETRY_COUNT" npm install --save "$REACT_DUMMY_PLATFORM" --silent >> /dev/null + then + echo "Failed to install react-native-dummy" + echo "Most common reason is npm registry connectivity, try again" + return 1 + fi + + if ! react-native bundle --max-workers 1 --platform dummy --dev true --entry-file index.js --bundle-output dummy-bundle.js + then + echo "Could not build dummy bundle" + return 1 + fi fi # directory cleanup - rm $IOS_MARKER - rm $ANDROID_MARKER + rm "$IOS_MARKER" + rm "$ANDROID_MARKER" return 0 } -retry $RETRY_COUNT e2e_suite +retry "$RETRY_COUNT" e2e_suite diff --git a/ContainerShip/scripts/run-instrumentation-tests-via-adb-shell.sh b/ContainerShip/scripts/run-instrumentation-tests-via-adb-shell.sh index 5a9a976a97da4e..d2b4b9ee275a12 100755 --- a/ContainerShip/scripts/run-instrumentation-tests-via-adb-shell.sh +++ b/ContainerShip/scripts/run-instrumentation-tests-via-adb-shell.sh @@ -1,5 +1,12 @@ #!/bin/bash +# +# 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. +# +# shellcheck disable=SC1117 # Python script to run instrumentation tests, copied from https://github.com/circleci/circle-dummy-android # Example: ./scripts/run-android-instrumentation-tests.sh com.facebook.react.tests com.facebook.react.tests.ReactPickerTestCase # @@ -9,7 +16,7 @@ export PATH="$ANDROID_HOME/platform-tools:$ANDROID_HOME/tools:$PATH" adb logcat -c # run tests and check output -python - $1 $2 << END +python - "$1" "$2" << END import re import subprocess as sp @@ -24,7 +31,7 @@ test_class = None if len(sys.argv) > 2: test_class = sys.argv[2] - + def update(): # prevent CircleCI from killing the process for inactivity while not done: @@ -38,10 +45,10 @@ t.start() def run(): sp.Popen(['adb', 'wait-for-device']).communicate() if (test_class != None): - p = sp.Popen('adb shell am instrument -w -e class %s %s/android.support.test.runner.AndroidJUnitRunner' + p = sp.Popen('adb shell am instrument -w -e class %s %s/android.support.test.runner.AndroidJUnitRunner' % (test_class, test_app), shell=True, stdout=sp.PIPE, stderr=sp.PIPE, stdin=sp.PIPE) else : - p = sp.Popen('adb shell am instrument -w %s/android.support.test.runner.AndroidJUnitRunner' + p = sp.Popen('adb shell am instrument -w %s/android.support.test.runner.AndroidJUnitRunner' % (test_app), shell=True, stdout=sp.PIPE, stderr=sp.PIPE, stdin=sp.PIPE) return p.communicate() diff --git a/DockerTests.md b/DockerTests.md index f1714db87a0a05..429e312ceb31be 100644 --- a/DockerTests.md +++ b/DockerTests.md @@ -12,9 +12,9 @@ See for more information on how t We have added a number of default run scripts to the `package.json` file to simplify building and running your tests. -`npm run test-android-setup` - Pulls down the base android docker image used for running the tests +`npm run docker-setup-android` - Pulls down the base android docker image used for running the tests -`npm run test-android-build` - Builds the docker image used to run the tests +`npm run docker-build-android` - Builds the docker image used to run the tests `npm run test-android-run-unit` - Runs all the unit tests that have been built in the latest react/android docker image (note: you need to run test-android-build before executing this, if the image does not exist it will fail) diff --git a/IntegrationTests/AccessibilityManagerTest.js b/IntegrationTests/AccessibilityManagerTest.js index 50c2c1c2c301e5..0a059d99c27c24 100644 --- a/IntegrationTests/AccessibilityManagerTest.js +++ b/IntegrationTests/AccessibilityManagerTest.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. diff --git a/IntegrationTests/AppEventsTest.js b/IntegrationTests/AppEventsTest.js index 90da0bd87c1ac2..e88e97909d35e9 100644 --- a/IntegrationTests/AppEventsTest.js +++ b/IntegrationTests/AppEventsTest.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. diff --git a/IntegrationTests/AsyncStorageTest.js b/IntegrationTests/AsyncStorageTest.js index cc001bc54dea8b..3e3fc02343d2cc 100644 --- a/IntegrationTests/AsyncStorageTest.js +++ b/IntegrationTests/AsyncStorageTest.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. @@ -12,7 +12,7 @@ const React = require('react'); const ReactNative = require('react-native'); -const {AsyncStorage, Text, View} = ReactNative; +const {AsyncStorage, Text, View, StyleSheet} = ReactNative; const {TestModule} = ReactNative.NativeModules; const deepDiffer = require('deepDiffer'); @@ -196,7 +196,7 @@ class AsyncStorageTest extends React.Component<{}, $FlowFixMeState> { render() { return ( - + {/* $FlowFixMe(>=0.54.0 site=react_native_fb,react_native_oss) This * comment suppresses an error found when Flow v0.54 was deployed. @@ -210,6 +210,13 @@ class AsyncStorageTest extends React.Component<{}, $FlowFixMeState> { } } +const styles = StyleSheet.create({ + container: { + backgroundColor: 'white', + padding: 40, + }, +}); + AsyncStorageTest.displayName = 'AsyncStorageTest'; module.exports = AsyncStorageTest; diff --git a/IntegrationTests/ImageCachePolicyTest.js b/IntegrationTests/ImageCachePolicyTest.js index 52d1be1d03ea03..0dae9812cf6e24 100644 --- a/IntegrationTests/ImageCachePolicyTest.js +++ b/IntegrationTests/ImageCachePolicyTest.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. @@ -58,7 +58,7 @@ class ImageCachePolicyTest extends React.Component { render() { return ( - + Hello { } const styles = StyleSheet.create({ + container: { + flex: 1, + }, base: { width: 100, height: 100, diff --git a/IntegrationTests/ImageSnapshotTest.js b/IntegrationTests/ImageSnapshotTest.js index 0da33f62718a3f..c4ffaae51c2ec4 100644 --- a/IntegrationTests/ImageSnapshotTest.js +++ b/IntegrationTests/ImageSnapshotTest.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. @@ -12,7 +12,7 @@ const React = require('react'); const ReactNative = require('react-native'); -const {Image, View} = ReactNative; +const {Image} = ReactNative; const {TestModule} = ReactNative.NativeModules; class ImageSnapshotTest extends React.Component<{}> { diff --git a/IntegrationTests/IntegrationTestHarnessTest.js b/IntegrationTests/IntegrationTestHarnessTest.js index 045d2e7e1eae1e..efe6cd4cd2f643 100644 --- a/IntegrationTests/IntegrationTestHarnessTest.js +++ b/IntegrationTests/IntegrationTestHarnessTest.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. @@ -10,28 +10,22 @@ 'use strict'; -/* $FlowFixMe(>=0.54.0 site=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. */ const requestAnimationFrame = require('fbjs/lib/requestAnimationFrame'); const React = require('react'); -const PropTypes = require('prop-types'); const ReactNative = require('react-native'); -const {Text, View} = ReactNative; +const {Text, View, StyleSheet} = ReactNative; const {TestModule} = ReactNative.NativeModules; -class IntegrationTestHarnessTest extends React.Component< - { - shouldThrow?: boolean, - waitOneFrame?: boolean, - }, - $FlowFixMeState, -> { - static propTypes = { - shouldThrow: PropTypes.bool, - waitOneFrame: PropTypes.bool, - }; +type Props = $ReadOnly<{| + shouldThrow?: boolean, + waitOneFrame?: boolean, +|}>; + +type State = {| + done: boolean, +|}; +class IntegrationTestHarnessTest extends React.Component { state = { done: false, }; @@ -60,7 +54,7 @@ class IntegrationTestHarnessTest extends React.Component< render() { return ( - + {/* $FlowFixMe(>=0.54.0 site=react_native_fb,react_native_oss) This * comment suppresses an error found when Flow v0.54 was deployed. @@ -73,6 +67,13 @@ class IntegrationTestHarnessTest extends React.Component< } } +const styles = StyleSheet.create({ + container: { + backgroundColor: 'white', + padding: 40, + }, +}); + IntegrationTestHarnessTest.displayName = 'IntegrationTestHarnessTest'; module.exports = IntegrationTestHarnessTest; diff --git a/IntegrationTests/IntegrationTestsApp.js b/IntegrationTests/IntegrationTestsApp.js index 421b4f6abe2b19..348d0867e73e97 100644 --- a/IntegrationTests/IntegrationTestsApp.js +++ b/IntegrationTests/IntegrationTestsApp.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. diff --git a/IntegrationTests/LayoutEventsTest.js b/IntegrationTests/LayoutEventsTest.js index b51d5dc06cee42..af828d6f122ae7 100644 --- a/IntegrationTests/LayoutEventsTest.js +++ b/IntegrationTests/LayoutEventsTest.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. @@ -12,11 +12,12 @@ const Platform = require('Platform'); const React = require('react'); -const createReactClass = require('create-react-class'); const ReactNative = require('react-native'); const {Image, LayoutAnimation, StyleSheet, Text, View} = ReactNative; const {TestModule} = ReactNative.NativeModules; +import type {ViewStyleProp} from 'StyleSheet'; + const deepDiffer = require('deepDiffer'); function debug(...args) { @@ -24,14 +25,8 @@ function debug(...args) { } import type {Layout, LayoutEvent} from 'CoreEventTypes'; -type Style = { - margin?: number, - padding?: number, - borderColor?: string, - borderWidth?: number, - backgroundColor?: string, - width?: number, -}; + +type Props = $ReadOnly<{||}>; type State = { didAnimation: boolean, @@ -39,18 +34,20 @@ type State = { imageLayout?: Layout, textLayout?: Layout, viewLayout?: Layout, - viewStyle?: Style, - containerStyle?: Style, + viewStyle?: ViewStyleProp, + containerStyle?: ViewStyleProp, }; -const LayoutEventsTest = createReactClass({ - displayName: 'LayoutEventsTest', - getInitialState(): State { - return { - didAnimation: false, - }; - }, - animateViewLayout: function() { +class LayoutEventsTest extends React.Component { + _view: ?React.ElementRef; + _img: ?React.ElementRef; + _txt: ?React.ElementRef; + + state: State = { + didAnimation: false, + }; + + animateViewLayout() { debug('animateViewLayout invoked'); LayoutAnimation.configureNext( Platform.OS === 'macos' @@ -62,26 +59,38 @@ const LayoutEventsTest = createReactClass({ }, ); this.setState({viewStyle: {margin: 60}}); - }, - addWrapText: function() { + } + + addWrapText = () => { debug('addWrapText invoked'); this.setState( {extraText: ' And a bunch more text to wrap around a few lines.'}, () => this.checkLayout(this.changeContainer), ); - }, - changeContainer: function() { + }; + + changeContainer = () => { debug('changeContainer invoked'); this.setState({containerStyle: {width: 280}}, () => this.checkLayout(TestModule.markTestCompleted), ); - }, - checkLayout: function(next?: ?Function) { - if (!this.isMounted()) { + }; + + checkLayout = (next?: ?() => void) => { + const view = this._view; + const txt = this._txt; + const img = this._img; + + if (view == null || txt == null || img == null) { return; } - this.refs.view.measure((x, y, width, height) => { - this.compare('view', {x, y, width, height}, this.state.viewLayout); + + view.measure((x, y, width, height) => { + this.compare( + 'view', + {x, y, width, height}, + this.state.viewLayout || null, + ); if (typeof next === 'function') { next(); } else if (!this.state.didAnimation) { @@ -90,14 +99,17 @@ const LayoutEventsTest = createReactClass({ this.state.didAnimation = true; } }); - this.refs.txt.measure((x, y, width, height) => { + + txt.measure((x, y, width, height) => { this.compare('txt', {x, y, width, height}, this.state.textLayout); }); - this.refs.img.measure((x, y, width, height) => { + + img.measure((x, y, width, height) => { this.compare('img', {x, y, width, height}, this.state.imageLayout); }); - }, - compare: function(node: string, measured: any, onLayout: any): void { + }; + + compare(node: string, measured: Layout, onLayout?: ?Layout): void { if (deepDiffer(measured, onLayout)) { const data = {measured, onLayout}; throw new Error( @@ -106,34 +118,50 @@ const LayoutEventsTest = createReactClass({ JSON.stringify(data, null, ' '), ); } - }, - onViewLayout: function(e: LayoutEvent) { + } + + onViewLayout = (e: LayoutEvent) => { debug('received view layout event\n', e.nativeEvent); this.setState({viewLayout: e.nativeEvent.layout}, this.checkLayout); - }, - onTextLayout: function(e: LayoutEvent) { + }; + + onTextLayout = (e: LayoutEvent) => { debug('received text layout event\n', e.nativeEvent); this.setState({textLayout: e.nativeEvent.layout}, this.checkLayout); - }, - onImageLayout: function(e: LayoutEvent) { + }; + + onImageLayout = (e: LayoutEvent) => { debug('received image layout event\n', e.nativeEvent); this.setState({imageLayout: e.nativeEvent.layout}, this.checkLayout); - }, - render: function() { + }; + + render() { const viewStyle = [styles.view, this.state.viewStyle]; const textLayout = this.state.textLayout || {width: '?', height: '?'}; const imageLayout = this.state.imageLayout || {x: '?', y: '?'}; debug('viewLayout', this.state.viewLayout); return ( - + { + this._view = ref; + }} + onLayout={this.onViewLayout} + style={viewStyle}> { + this._img = ref; + }} onLayout={this.onImageLayout} style={styles.image} source={{uri: 'uie_thumb_big.png'}} /> - + { + this._txt = ref; + }} + onLayout={this.onTextLayout} + style={styles.text}> A simple piece of text.{this.state.extraText} @@ -144,8 +172,8 @@ const LayoutEventsTest = createReactClass({ ); - }, -}); + } +} const styles = StyleSheet.create({ container: { @@ -171,6 +199,4 @@ const styles = StyleSheet.create({ }, }); -LayoutEventsTest.displayName = 'LayoutEventsTest'; - module.exports = LayoutEventsTest; diff --git a/IntegrationTests/LoggingTestModule.js b/IntegrationTests/LoggingTestModule.js index 905abee400828d..32a049f8866265 100644 --- a/IntegrationTests/LoggingTestModule.js +++ b/IntegrationTests/LoggingTestModule.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. diff --git a/IntegrationTests/PromiseTest.js b/IntegrationTests/PromiseTest.js index facf8b45cdc746..c36d3beb017b69 100644 --- a/IntegrationTests/PromiseTest.js +++ b/IntegrationTests/PromiseTest.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. diff --git a/IntegrationTests/PropertiesUpdateTest.js b/IntegrationTests/PropertiesUpdateTest.js index 33d17da5e5c442..8c61685bf8848e 100644 --- a/IntegrationTests/PropertiesUpdateTest.js +++ b/IntegrationTests/PropertiesUpdateTest.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. diff --git a/IntegrationTests/RCTRootViewIntegrationTestApp.js b/IntegrationTests/RCTRootViewIntegrationTestApp.js index 6afda59cd688c1..2466b6378586eb 100644 --- a/IntegrationTests/RCTRootViewIntegrationTestApp.js +++ b/IntegrationTests/RCTRootViewIntegrationTestApp.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. @@ -9,8 +9,6 @@ 'use strict'; -require('regenerator-runtime/runtime'); - const React = require('react'); const ReactNative = require('react-native'); diff --git a/IntegrationTests/ReactContentSizeUpdateTest.js b/IntegrationTests/ReactContentSizeUpdateTest.js index be0b06b6abf56b..707abc6cb727e3 100644 --- a/IntegrationTests/ReactContentSizeUpdateTest.js +++ b/IntegrationTests/ReactContentSizeUpdateTest.js @@ -1,78 +1,89 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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'; const React = require('react'); -const createReactClass = require('create-react-class'); const ReactNative = require('react-native'); const RCTNativeAppEventEmitter = require('RCTNativeAppEventEmitter'); -const Subscribable = require('Subscribable'); -const TimerMixin = require('react-timer-mixin'); const {View} = ReactNative; const {TestModule} = ReactNative.NativeModules; +import type EmitterSubscription from 'EmitterSubscription'; const reactViewWidth = 101; const reactViewHeight = 102; const newReactViewWidth = 201; const newReactViewHeight = 202; -const ReactContentSizeUpdateTest = createReactClass({ - displayName: 'ReactContentSizeUpdateTest', - mixins: [Subscribable.Mixin, TimerMixin], +type Props = {||}; - UNSAFE_componentWillMount: function() { - this.addListenerOn( - RCTNativeAppEventEmitter, +type State = {| + height: number, + width: number, +|}; + +class ReactContentSizeUpdateTest extends React.Component { + _timeoutID: ?TimeoutID = null; + _subscription: ?EmitterSubscription = null; + + state = { + height: reactViewHeight, + width: reactViewWidth, + }; + + UNSAFE_componentWillMount() { + this._subscription = RCTNativeAppEventEmitter.addListener( 'rootViewDidChangeIntrinsicSize', this.rootViewDidChangeIntrinsicSize, ); - }, + } - getInitialState: function() { - return { - height: reactViewHeight, - width: reactViewWidth, - }; - }, + componentDidMount() { + this._timeoutID = setTimeout(() => { + this.updateViewSize(); + }, 1000); + } + + componentWillUnmount() { + if (this._timeoutID != null) { + clearTimeout(this._timeoutID); + } - updateViewSize: function() { + if (this._subscription != null) { + this._subscription.remove(); + } + } + + updateViewSize() { this.setState({ height: newReactViewHeight, width: newReactViewWidth, }); - }, - - componentDidMount: function() { - this.setTimeout(() => { - this.updateViewSize(); - }, 1000); - }, + } - rootViewDidChangeIntrinsicSize: function(intrinsicSize) { + rootViewDidChangeIntrinsicSize = (intrinsicSize: State) => { if ( intrinsicSize.height === newReactViewHeight && intrinsicSize.width === newReactViewWidth ) { TestModule.markTestPassed(true); } - }, + }; render() { return ( ); - }, -}); - -ReactContentSizeUpdateTest.displayName = 'ReactContentSizeUpdateTest'; + } +} module.exports = ReactContentSizeUpdateTest; diff --git a/IntegrationTests/SimpleSnapshotTest.js b/IntegrationTests/SimpleSnapshotTest.js index 2857f3f41b492a..fef8377373d0f6 100644 --- a/IntegrationTests/SimpleSnapshotTest.js +++ b/IntegrationTests/SimpleSnapshotTest.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. @@ -34,7 +34,7 @@ class SimpleSnapshotTest extends React.Component<{}> { render() { return ( - + @@ -43,6 +43,10 @@ class SimpleSnapshotTest extends React.Component<{}> { } const styles = StyleSheet.create({ + container: { + backgroundColor: 'white', + padding: 100, + }, box1: { width: 80, height: 50, diff --git a/IntegrationTests/SizeFlexibilityUpdateTest.js b/IntegrationTests/SizeFlexibilityUpdateTest.js index 0d0ebd4bfc20f3..42ce5bf5fb8173 100644 --- a/IntegrationTests/SizeFlexibilityUpdateTest.js +++ b/IntegrationTests/SizeFlexibilityUpdateTest.js @@ -1,46 +1,60 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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'; const React = require('react'); -const createReactClass = require('create-react-class'); const ReactNative = require('react-native'); const RCTNativeAppEventEmitter = require('RCTNativeAppEventEmitter'); -const Subscribable = require('Subscribable'); const {View} = ReactNative; const {TestModule} = ReactNative.NativeModules; +import type EmitterSubscription from 'EmitterSubscription'; const reactViewWidth = 111; const reactViewHeight = 222; let finalState = false; -const SizeFlexibilityUpdateTest = createReactClass({ - displayName: 'SizeFlexibilityUpdateTest', - mixins: [Subscribable.Mixin], +type Props = $ReadOnly<{| + width: boolean, + height: boolean, + both: boolean, + none: boolean, +|}>; - UNSAFE_componentWillMount: function() { - this.addListenerOn( - RCTNativeAppEventEmitter, +class SizeFlexibilityUpdateTest extends React.Component { + _subscription: ?EmitterSubscription = null; + + UNSAFE_componentWillMount() { + this._subscription = RCTNativeAppEventEmitter.addListener( 'rootViewDidChangeIntrinsicSize', this.rootViewDidChangeIntrinsicSize, ); - }, + } + + componentWillUnmount() { + if (this._subscription != null) { + this._subscription.remove(); + } + } - markPassed: function() { + markPassed = () => { TestModule.markTestPassed(true); finalState = true; - }, + }; - rootViewDidChangeIntrinsicSize: function(intrinsicSize) { + rootViewDidChangeIntrinsicSize = (intrinsicSize: { + width: number, + height: number, + }) => { if (finalState) { // If a test reaches its final state, it is not expected to do anything more TestModule.markTestPassed(false); @@ -83,13 +97,11 @@ const SizeFlexibilityUpdateTest = createReactClass({ return; } } - }, + }; render() { return ; - }, -}); - -SizeFlexibilityUpdateTest.displayName = 'SizeFlexibilityUpdateTest'; + } +} module.exports = SizeFlexibilityUpdateTest; diff --git a/IntegrationTests/SyncMethodTest.js b/IntegrationTests/SyncMethodTest.js index 0b912396813027..d618ced4761585 100644 --- a/IntegrationTests/SyncMethodTest.js +++ b/IntegrationTests/SyncMethodTest.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. diff --git a/IntegrationTests/TimersTest.js b/IntegrationTests/TimersTest.js index 15d42c4c852a1c..c7eefb915333c3 100644 --- a/IntegrationTests/TimersTest.js +++ b/IntegrationTests/TimersTest.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. @@ -11,75 +11,136 @@ 'use strict'; const React = require('react'); -const createReactClass = require('create-react-class'); const ReactNative = require('react-native'); -/* $FlowFixMe(>=0.54.0 site=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. */ -const TimerMixin = require('react-timer-mixin'); - const {StyleSheet, Text, View} = ReactNative; const {TestModule} = ReactNative.NativeModules; -const TimersTest = createReactClass({ - displayName: 'TimersTest', - mixins: [TimerMixin], +type Props = $ReadOnly<{||}>; - _nextTest: () => {}, - _interval: -1, +type State = {| + count: number, + done: boolean, +|}; - getInitialState() { - return { - count: 0, - done: false, - }; - }, +type ImmediateID = Object; + +class TimersTest extends React.Component { + _nextTest = () => {}; + _interval: ?IntervalID = null; + + _timeoutIDs: Set = new Set(); + _intervalIDs: Set = new Set(); + _immediateIDs: Set = new Set(); + _animationFrameIDs: Set = new Set(); + + state = { + count: 0, + done: false, + }; + + setTimeout(fn: () => void, time: number): TimeoutID { + const id = setTimeout(() => { + this._timeoutIDs.delete(id); + fn(); + }, time); + + this._timeoutIDs.add(id); + + return id; + } + + clearTimeout(id: TimeoutID) { + this._timeoutIDs.delete(id); + clearTimeout(id); + } + + setInterval(fn: () => void, time: number): IntervalID { + const id = setInterval(() => { + fn(); + }, time); + + this._intervalIDs.add(id); + + return id; + } + + clearInterval(id: IntervalID) { + this._intervalIDs.delete(id); + clearInterval(id); + } + + setImmediate(fn: () => void): ImmediateID { + const id = setImmediate(() => { + this._immediateIDs.delete(id); + fn(); + }); + + this._immediateIDs.add(id); + + return id; + } + + requestAnimationFrame(fn: () => void): AnimationFrameID { + const id = requestAnimationFrame(() => { + this._animationFrameIDs.delete(id); + fn(); + }); + + this._animationFrameIDs.add(id); + + return id; + } + + cancelAnimationFrame(id: AnimationFrameID): void { + this._animationFrameIDs.delete(id); + cancelAnimationFrame(id); + } componentDidMount() { this.setTimeout(this.testSetTimeout0, 1000); - }, + } testSetTimeout0() { this.setTimeout(this.testSetTimeout1, 0); - }, + } testSetTimeout1() { this.setTimeout(this.testSetTimeout50, 1); - }, + } testSetTimeout50() { this.setTimeout(this.testRequestAnimationFrame, 50); - }, + } testRequestAnimationFrame() { this.requestAnimationFrame(this.testSetInterval0); - }, + } testSetInterval0() { this._nextTest = this.testSetInterval20; this._interval = this.setInterval(this._incrementInterval, 0); - }, + } testSetInterval20() { this._nextTest = this.testSetImmediate; this._interval = this.setInterval(this._incrementInterval, 20); - }, + } testSetImmediate() { this.setImmediate(this.testClearTimeout0); - }, + } testClearTimeout0() { const timeout = this.setTimeout(() => this._fail('testClearTimeout0'), 0); this.clearTimeout(timeout); this.testClearTimeout30(); - }, + } testClearTimeout30() { const timeout = this.setTimeout(() => this._fail('testClearTimeout30'), 30); this.clearTimeout(timeout); this.setTimeout(this.testClearMulti, 50); - }, + } testClearMulti() { const fails = []; @@ -96,7 +157,7 @@ const TimersTest = createReactClass({ this.setTimeout(() => this.clearTimeout(delayClear), 20); this.setTimeout(this.testOrdering, 50); - }, + } testOrdering() { // Clear timers are set first because it's more likely to uncover bugs. @@ -131,42 +192,73 @@ const TimersTest = createReactClass({ 25, ); this.setTimeout(this.done, 50); - }, + } done() { this.setState({done: true}, () => { TestModule.markTestCompleted(); }); - }, + } + + componentWillUnmount() { + for (const timeoutID of this._timeoutIDs) { + clearTimeout(timeoutID); + } + + for (const intervalID of this._intervalIDs) { + clearInterval(intervalID); + } + + for (const requestAnimationFrameID of this._animationFrameIDs) { + cancelAnimationFrame(requestAnimationFrameID); + } + + for (const immediateID of this._immediateIDs) { + clearImmediate(immediateID); + } + + this._timeoutIDs = new Set(); + this._intervalIDs = new Set(); + this._animationFrameIDs = new Set(); + this._immediateIDs = new Set(); + + if (this._interval != null) { + clearInterval(this._interval); + this._interval = null; + } + } render() { return ( - {this.constructor.displayName + ': \n'} + {this.constructor.name + ': \n'} Intervals: {this.state.count + '\n'} {this.state.done ? 'Done' : 'Testing...'} ); - }, + } _incrementInterval() { if (this.state.count > 3) { throw new Error('interval incremented past end.'); } if (this.state.count === 3) { - this.clearInterval(this._interval); + if (this._interval != null) { + this.clearInterval(this._interval); + this._interval = null; + } this.setState({count: 0}, this._nextTest); return; } this.setState({count: this.state.count + 1}); - }, + } _fail(caller: string): void { throw new Error('_fail called by ' + caller); - }, -}); + } +} const styles = StyleSheet.create({ container: { @@ -175,6 +267,4 @@ const styles = StyleSheet.create({ }, }); -TimersTest.displayName = 'TimersTest'; - module.exports = TimersTest; diff --git a/IntegrationTests/WebSocketTest.js b/IntegrationTests/WebSocketTest.js index f2478cbcb68539..0d2cd5e0b4d9e7 100644 --- a/IntegrationTests/WebSocketTest.js +++ b/IntegrationTests/WebSocketTest.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. @@ -18,12 +18,6 @@ const {TestModule} = ReactNative.NativeModules; const DEFAULT_WS_URL = 'ws://localhost:5555/'; const WS_EVENTS = ['close', 'error', 'message', 'open']; -const WS_STATES = [ - /* 0 */ 'CONNECTING', - /* 1 */ 'OPEN', - /* 2 */ 'CLOSING', - /* 3 */ 'CLOSED', -]; type State = { url: string, @@ -50,7 +44,6 @@ class WebSocketTest extends React.Component<{}, State> { _waitFor = (condition: any, timeout: any, callback: any) => { let remaining = timeout; - let t; const timeoutFunction = function() { if (condition()) { callback(true); @@ -60,10 +53,10 @@ class WebSocketTest extends React.Component<{}, State> { if (remaining === 0) { callback(false); } else { - t = setTimeout(timeoutFunction, 1000); + setTimeout(timeoutFunction, 1000); } }; - t = setTimeout(timeoutFunction, 1000); + setTimeout(timeoutFunction, 1000); }; _connect = () => { @@ -121,39 +114,30 @@ class WebSocketTest extends React.Component<{}, State> { } testConnect = () => { - const component = this; - component._connect(); - component._waitFor(component._socketIsConnected, 5, function( - connectSucceeded, - ) { + this._connect(); + this._waitFor(this._socketIsConnected, 5, connectSucceeded => { if (!connectSucceeded) { TestModule.markTestPassed(false); return; } - component.testSendAndReceive(); + this.testSendAndReceive(); }); }; testSendAndReceive = () => { - const component = this; - component._sendTestMessage(); - component._waitFor(component._receivedTestExpectedResponse, 5, function( - messageReceived, - ) { + this._sendTestMessage(); + this._waitFor(this._receivedTestExpectedResponse, 5, messageReceived => { if (!messageReceived) { TestModule.markTestPassed(false); return; } - component.testDisconnect(); + this.testDisconnect(); }); }; testDisconnect = () => { - const component = this; - component._disconnect(); - component._waitFor(component._socketIsDisconnected, 5, function( - disconnectSucceeded, - ) { + this._disconnect(); + this._waitFor(this._socketIsDisconnected, 5, disconnectSucceeded => { TestModule.markTestPassed(disconnectSucceeded); }); }; diff --git a/IntegrationTests/WebViewTest.js b/IntegrationTests/WebViewTest.js index 74dbeddec6b5ce..269b9d24bdee81 100644 --- a/IntegrationTests/WebViewTest.js +++ b/IntegrationTests/WebViewTest.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. diff --git a/IntegrationTests/launchWebSocketServer.command b/IntegrationTests/launchWebSocketServer.command index 1155f28946a284..a7c7ef25c9b487 100755 --- a/IntegrationTests/launchWebSocketServer.command +++ b/IntegrationTests/launchWebSocketServer.command @@ -1,6 +1,6 @@ #!/bin/bash -# Copyright (c) 2015-present, Facebook, Inc. +# 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. diff --git a/IntegrationTests/websocket_integration_test_server.js b/IntegrationTests/websocket_integration_test_server.js index 2044c4de9da37a..75c799515d726f 100755 --- a/IntegrationTests/websocket_integration_test_server.js +++ b/IntegrationTests/websocket_integration_test_server.js @@ -1,7 +1,7 @@ #!/usr/bin/env node /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. diff --git a/LICENSE b/LICENSE index 9e051010d82dc6..b96dcb0480a0b0 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2015-present, Facebook, Inc. +Copyright (c) Facebook, Inc. and its affiliates. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/Libraries/ART/ARTCGFloatArray.h b/Libraries/ART/ARTCGFloatArray.h index 72286a50527e84..a607904e0be1ed 100644 --- a/Libraries/ART/ARTCGFloatArray.h +++ b/Libraries/ART/ARTCGFloatArray.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. diff --git a/Libraries/ART/ARTContainer.h b/Libraries/ART/ARTContainer.h index 532145825bd74b..5439d9fb1d2176 100644 --- a/Libraries/ART/ARTContainer.h +++ b/Libraries/ART/ARTContainer.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. diff --git a/Libraries/ART/ARTGroup.h b/Libraries/ART/ARTGroup.h index d9dcb48c87b180..31edddde7b664f 100644 --- a/Libraries/ART/ARTGroup.h +++ b/Libraries/ART/ARTGroup.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. diff --git a/Libraries/ART/ARTGroup.m b/Libraries/ART/ARTGroup.m index 1bc70725c030e8..56699114f4a3f2 100644 --- a/Libraries/ART/ARTGroup.m +++ b/Libraries/ART/ARTGroup.m @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. diff --git a/Libraries/ART/ARTNode.h b/Libraries/ART/ARTNode.h index 8b66c205ef2440..9f381115a7646e 100644 --- a/Libraries/ART/ARTNode.h +++ b/Libraries/ART/ARTNode.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. diff --git a/Libraries/ART/ARTNode.m b/Libraries/ART/ARTNode.m index b27b014b9e7d0e..ae1a152a7d7626 100644 --- a/Libraries/ART/ARTNode.m +++ b/Libraries/ART/ARTNode.m @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. diff --git a/Libraries/ART/ARTRenderable.h b/Libraries/ART/ARTRenderable.h index e5735a1fbd81ef..077d47ec2c6c32 100644 --- a/Libraries/ART/ARTRenderable.h +++ b/Libraries/ART/ARTRenderable.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. diff --git a/Libraries/ART/ARTRenderable.m b/Libraries/ART/ARTRenderable.m index d7a3115586f3dd..88349f8296e7b0 100644 --- a/Libraries/ART/ARTRenderable.m +++ b/Libraries/ART/ARTRenderable.m @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. diff --git a/Libraries/ART/ARTSerializablePath.js b/Libraries/ART/ARTSerializablePath.js index 9c2d98e033fcc3..aafb74c45d065c 100644 --- a/Libraries/ART/ARTSerializablePath.js +++ b/Libraries/ART/ARTSerializablePath.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. diff --git a/Libraries/ART/ARTShape.h b/Libraries/ART/ARTShape.h index ce685c564b06be..1a1fd429a8bf1a 100644 --- a/Libraries/ART/ARTShape.h +++ b/Libraries/ART/ARTShape.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. diff --git a/Libraries/ART/ARTShape.m b/Libraries/ART/ARTShape.m index 935c8894994a2b..8a1a7d6979f3e9 100644 --- a/Libraries/ART/ARTShape.m +++ b/Libraries/ART/ARTShape.m @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. diff --git a/Libraries/ART/ARTSurfaceView.h b/Libraries/ART/ARTSurfaceView.h index 9420ed07fbf107..e9bcd50293de84 100644 --- a/Libraries/ART/ARTSurfaceView.h +++ b/Libraries/ART/ARTSurfaceView.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. diff --git a/Libraries/ART/ARTSurfaceView.m b/Libraries/ART/ARTSurfaceView.m index 2d45083caea7c6..a5a2ff9135c5e3 100644 --- a/Libraries/ART/ARTSurfaceView.m +++ b/Libraries/ART/ARTSurfaceView.m @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. diff --git a/Libraries/ART/ARTText.h b/Libraries/ART/ARTText.h index cdf8393a137629..1431fc5e181c5e 100644 --- a/Libraries/ART/ARTText.h +++ b/Libraries/ART/ARTText.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. diff --git a/Libraries/ART/ARTText.m b/Libraries/ART/ARTText.m index 0953c850dc293e..5bcebdf5559942 100644 --- a/Libraries/ART/ARTText.m +++ b/Libraries/ART/ARTText.m @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. diff --git a/Libraries/ART/ARTTextFrame.h b/Libraries/ART/ARTTextFrame.h index 8ad06e0a01baed..1c02d3e04260b0 100644 --- a/Libraries/ART/ARTTextFrame.h +++ b/Libraries/ART/ARTTextFrame.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. diff --git a/Libraries/ART/Brushes/ARTBrush.h b/Libraries/ART/Brushes/ARTBrush.h index 95709e65f19bc9..f6e39e861f737c 100644 --- a/Libraries/ART/Brushes/ARTBrush.h +++ b/Libraries/ART/Brushes/ARTBrush.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. diff --git a/Libraries/ART/Brushes/ARTBrush.m b/Libraries/ART/Brushes/ARTBrush.m index 4ade2c221143f7..969ad5d7edb363 100644 --- a/Libraries/ART/Brushes/ARTBrush.m +++ b/Libraries/ART/Brushes/ARTBrush.m @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. diff --git a/Libraries/ART/Brushes/ARTLinearGradient.h b/Libraries/ART/Brushes/ARTLinearGradient.h index 8e6abbc5fbbfde..d289b192a51b1e 100644 --- a/Libraries/ART/Brushes/ARTLinearGradient.h +++ b/Libraries/ART/Brushes/ARTLinearGradient.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. diff --git a/Libraries/ART/Brushes/ARTLinearGradient.m b/Libraries/ART/Brushes/ARTLinearGradient.m index 1415a6ffcbc80f..20bd1af6233b4e 100644 --- a/Libraries/ART/Brushes/ARTLinearGradient.m +++ b/Libraries/ART/Brushes/ARTLinearGradient.m @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. diff --git a/Libraries/ART/Brushes/ARTPattern.h b/Libraries/ART/Brushes/ARTPattern.h index ce1767cc9b0bc8..11fa9354de29d0 100644 --- a/Libraries/ART/Brushes/ARTPattern.h +++ b/Libraries/ART/Brushes/ARTPattern.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. diff --git a/Libraries/ART/Brushes/ARTPattern.m b/Libraries/ART/Brushes/ARTPattern.m index 5c43586452d198..70e0bd25f367b7 100644 --- a/Libraries/ART/Brushes/ARTPattern.m +++ b/Libraries/ART/Brushes/ARTPattern.m @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. diff --git a/Libraries/ART/Brushes/ARTRadialGradient.h b/Libraries/ART/Brushes/ARTRadialGradient.h index d7895f8b74d084..98bec026385014 100644 --- a/Libraries/ART/Brushes/ARTRadialGradient.h +++ b/Libraries/ART/Brushes/ARTRadialGradient.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. diff --git a/Libraries/ART/Brushes/ARTRadialGradient.m b/Libraries/ART/Brushes/ARTRadialGradient.m index 19db9cb97b567a..c36f6ce57fc1fc 100644 --- a/Libraries/ART/Brushes/ARTRadialGradient.m +++ b/Libraries/ART/Brushes/ARTRadialGradient.m @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. diff --git a/Libraries/ART/Brushes/ARTSolidColor.h b/Libraries/ART/Brushes/ARTSolidColor.h index a16c2b915c72f8..9880cfd61675ff 100644 --- a/Libraries/ART/Brushes/ARTSolidColor.h +++ b/Libraries/ART/Brushes/ARTSolidColor.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. diff --git a/Libraries/ART/Brushes/ARTSolidColor.m b/Libraries/ART/Brushes/ARTSolidColor.m index 096c4e043ed429..2ef02d43d98592 100644 --- a/Libraries/ART/Brushes/ARTSolidColor.m +++ b/Libraries/ART/Brushes/ARTSolidColor.m @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. diff --git a/Libraries/ART/RCTConvert+ART.h b/Libraries/ART/RCTConvert+ART.h index 1deb3c600176ab..ffc1deafe4e6e7 100644 --- a/Libraries/ART/RCTConvert+ART.h +++ b/Libraries/ART/RCTConvert+ART.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. diff --git a/Libraries/ART/RCTConvert+ART.m b/Libraries/ART/RCTConvert+ART.m index ea22d5426f18f9..3312e319436369 100644 --- a/Libraries/ART/RCTConvert+ART.m +++ b/Libraries/ART/RCTConvert+ART.m @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. diff --git a/Libraries/ART/ReactNativeART.js b/Libraries/ART/ReactNativeART.js index 5a08e748c8382c..ae2d0e58a377ee 100644 --- a/Libraries/ART/ReactNativeART.js +++ b/Libraries/ART/ReactNativeART.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. @@ -399,7 +399,19 @@ function extractStrokeJoin(strokeJoin) { // Note: ART has a notion of width and height on Shape but AFAIK it's a noop in // ReactART. -class Shape extends React.Component { +export type ShapeProps = {| + fill?: mixed, + stroke?: mixed, + strokeCap?: mixed, + strokeDash?: mixed, + strokeJoin?: mixed, + strokeWidth?: mixed, + x?: number, + y?: number, + opacity?: mixed, +|}; + +class Shape extends React.Component { render() { const props = this.props; const path = props.d || childrenAsString(props.children); diff --git a/Libraries/ART/ViewManagers/ARTGroupManager.h b/Libraries/ART/ViewManagers/ARTGroupManager.h index a35e09481be639..f518cf0efbdbb3 100644 --- a/Libraries/ART/ViewManagers/ARTGroupManager.h +++ b/Libraries/ART/ViewManagers/ARTGroupManager.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. diff --git a/Libraries/ART/ViewManagers/ARTGroupManager.m b/Libraries/ART/ViewManagers/ARTGroupManager.m index 2de0d0e5688739..9fb45d71bbdf4d 100644 --- a/Libraries/ART/ViewManagers/ARTGroupManager.m +++ b/Libraries/ART/ViewManagers/ARTGroupManager.m @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. diff --git a/Libraries/ART/ViewManagers/ARTNodeManager.h b/Libraries/ART/ViewManagers/ARTNodeManager.h index 3a8f99e7abdc7a..84ef8fb01cf3d4 100644 --- a/Libraries/ART/ViewManagers/ARTNodeManager.h +++ b/Libraries/ART/ViewManagers/ARTNodeManager.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. diff --git a/Libraries/ART/ViewManagers/ARTNodeManager.m b/Libraries/ART/ViewManagers/ARTNodeManager.m index 8e568ce6d8efd4..62680975ba1033 100644 --- a/Libraries/ART/ViewManagers/ARTNodeManager.m +++ b/Libraries/ART/ViewManagers/ARTNodeManager.m @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. diff --git a/Libraries/ART/ViewManagers/ARTRenderableManager.h b/Libraries/ART/ViewManagers/ARTRenderableManager.h index 1e4b554f0f79f7..781ed32f8f574d 100644 --- a/Libraries/ART/ViewManagers/ARTRenderableManager.h +++ b/Libraries/ART/ViewManagers/ARTRenderableManager.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. diff --git a/Libraries/ART/ViewManagers/ARTRenderableManager.m b/Libraries/ART/ViewManagers/ARTRenderableManager.m index a30841b50c1046..ad0264965391e5 100644 --- a/Libraries/ART/ViewManagers/ARTRenderableManager.m +++ b/Libraries/ART/ViewManagers/ARTRenderableManager.m @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. diff --git a/Libraries/ART/ViewManagers/ARTShapeManager.h b/Libraries/ART/ViewManagers/ARTShapeManager.h index 2f31b23a0eab10..cc514b159ee192 100644 --- a/Libraries/ART/ViewManagers/ARTShapeManager.h +++ b/Libraries/ART/ViewManagers/ARTShapeManager.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. diff --git a/Libraries/ART/ViewManagers/ARTShapeManager.m b/Libraries/ART/ViewManagers/ARTShapeManager.m index 57b603ca1a16b6..cb056e5d268877 100644 --- a/Libraries/ART/ViewManagers/ARTShapeManager.m +++ b/Libraries/ART/ViewManagers/ARTShapeManager.m @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. diff --git a/Libraries/ART/ViewManagers/ARTSurfaceViewManager.h b/Libraries/ART/ViewManagers/ARTSurfaceViewManager.h index 5915536bd6f917..36d5949a90ab4d 100644 --- a/Libraries/ART/ViewManagers/ARTSurfaceViewManager.h +++ b/Libraries/ART/ViewManagers/ARTSurfaceViewManager.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. diff --git a/Libraries/ART/ViewManagers/ARTSurfaceViewManager.m b/Libraries/ART/ViewManagers/ARTSurfaceViewManager.m index 54052a331d4585..1a03897937e860 100644 --- a/Libraries/ART/ViewManagers/ARTSurfaceViewManager.m +++ b/Libraries/ART/ViewManagers/ARTSurfaceViewManager.m @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. diff --git a/Libraries/ART/ViewManagers/ARTTextManager.h b/Libraries/ART/ViewManagers/ARTTextManager.h index c7d5304da3a3eb..343e669af7553c 100644 --- a/Libraries/ART/ViewManagers/ARTTextManager.h +++ b/Libraries/ART/ViewManagers/ARTTextManager.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. diff --git a/Libraries/ART/ViewManagers/ARTTextManager.m b/Libraries/ART/ViewManagers/ARTTextManager.m index ac6688c3d925b9..35c53811fd9509 100644 --- a/Libraries/ART/ViewManagers/ARTTextManager.m +++ b/Libraries/ART/ViewManagers/ARTTextManager.m @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. diff --git a/Libraries/ActionSheetIOS/ActionSheetIOS.js b/Libraries/ActionSheetIOS/ActionSheetIOS.js index b135a23e5fc998..ea2e01f9dd9b8a 100644 --- a/Libraries/ActionSheetIOS/ActionSheetIOS.js +++ b/Libraries/ActionSheetIOS/ActionSheetIOS.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. diff --git a/Libraries/ActionSheetIOS/RCTActionSheetManager.h b/Libraries/ActionSheetIOS/RCTActionSheetManager.h index 097a663f07f21b..96028ee549ab15 100644 --- a/Libraries/ActionSheetIOS/RCTActionSheetManager.h +++ b/Libraries/ActionSheetIOS/RCTActionSheetManager.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. diff --git a/Libraries/ActionSheetIOS/RCTActionSheetManager.m b/Libraries/ActionSheetIOS/RCTActionSheetManager.m index 958d1b2062a016..2376557c338016 100644 --- a/Libraries/ActionSheetIOS/RCTActionSheetManager.m +++ b/Libraries/ActionSheetIOS/RCTActionSheetManager.m @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. diff --git a/Libraries/Alert/Alert.js b/Libraries/Alert/Alert.js index aafeaa7ea33d59..d002145b9b6067 100644 --- a/Libraries/Alert/Alert.js +++ b/Libraries/Alert/Alert.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. diff --git a/Libraries/Alert/AlertIOS.js b/Libraries/Alert/AlertIOS.js index 1998865b2d597c..b7e1a0d73b7b59 100644 --- a/Libraries/Alert/AlertIOS.js +++ b/Libraries/Alert/AlertIOS.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. diff --git a/Libraries/Alert/RCTAlertManager.android.js b/Libraries/Alert/RCTAlertManager.android.js index 2e510add8ddaca..b16298f01ff3f2 100644 --- a/Libraries/Alert/RCTAlertManager.android.js +++ b/Libraries/Alert/RCTAlertManager.android.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2013-present, Facebook, Inc. + * 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. diff --git a/Libraries/Alert/RCTAlertManager.ios.js b/Libraries/Alert/RCTAlertManager.ios.js index dd561eec3a13f7..a300de65521d97 100644 --- a/Libraries/Alert/RCTAlertManager.ios.js +++ b/Libraries/Alert/RCTAlertManager.ios.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. diff --git a/Libraries/Animated/examples/style.css b/Libraries/Animated/examples/style.css index c188ad79b07fd2..24191a56b985ca 100644 --- a/Libraries/Animated/examples/style.css +++ b/Libraries/Animated/examples/style.css @@ -1,3 +1,10 @@ +/** + * 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. + */ + html, h1, h2 { font-family: 'Roboto', sans-serif; font-weight: 300; diff --git a/Libraries/Animated/release/.gitignore b/Libraries/Animated/release/.gitignore new file mode 100644 index 00000000000000..4c422f3bc92283 --- /dev/null +++ b/Libraries/Animated/release/.gitignore @@ -0,0 +1,3 @@ +/lib/ +/dist/ +/node_modules/ diff --git a/Libraries/Animated/release/gulpfile.js b/Libraries/Animated/release/gulpfile.js index b5599e9365fef3..291f3236303d87 100644 --- a/Libraries/Animated/release/gulpfile.js +++ b/Libraries/Animated/release/gulpfile.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2013-present, Facebook, Inc. + * 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. diff --git a/Libraries/Animated/release/package.json b/Libraries/Animated/release/package.json index 49f6a2081ffd14..cccaf09d35f896 100644 --- a/Libraries/Animated/release/package.json +++ b/Libraries/Animated/release/package.json @@ -10,7 +10,7 @@ "license": "MIT", "main": "Animated.js", "dependencies": { - "fbjs": "0.8.17" + "fbjs": "^1.0.0" }, "scripts": { "build": "gulp" @@ -19,7 +19,7 @@ "babel-core": "^5.8.25", "babel-loader": "^5.3.2", "del": "^1.2.0", - "fbjs-scripts": "^0.2.0", + "fbjs-scripts": "^1.0.0", "gulp": "^3.9.0", "gulp-babel": "^5.1.0", "gulp-derequire": "^2.1.0", diff --git a/Libraries/Animated/src/Animated.js b/Libraries/Animated/src/Animated.js index 1c60f253f903de..f07432c03ce159 100644 --- a/Libraries/Animated/src/Animated.js +++ b/Libraries/Animated/src/Animated.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. @@ -11,19 +11,25 @@ 'use strict'; const AnimatedImplementation = require('AnimatedImplementation'); -const FlatList = require('FlatList'); -const Image = require('Image'); -const ScrollView = require('ScrollView'); -const SectionList = require('SectionList'); -const Text = require('Text'); -const View = require('View'); module.exports = { + get FlatList() { + return require('AnimatedFlatList'); + }, + get Image() { + return require('AnimatedImage'); + }, + get ScrollView() { + return require('AnimatedScrollView'); + }, + get SectionList() { + return require('AnimatedSectionList'); + }, + get Text() { + return require('AnimatedText'); + }, + get View() { + return require('AnimatedView'); + }, ...AnimatedImplementation, - View: AnimatedImplementation.createAnimatedComponent(View), - Text: AnimatedImplementation.createAnimatedComponent(Text), - Image: AnimatedImplementation.createAnimatedComponent(Image), - ScrollView: AnimatedImplementation.createAnimatedComponent(ScrollView), - FlatList: AnimatedImplementation.createAnimatedComponent(FlatList), - SectionList: AnimatedImplementation.createAnimatedComponent(SectionList), }; diff --git a/Libraries/Animated/src/AnimatedEvent.js b/Libraries/Animated/src/AnimatedEvent.js index 084632737c661d..c4d1b88290e5cb 100644 --- a/Libraries/Animated/src/AnimatedEvent.js +++ b/Libraries/Animated/src/AnimatedEvent.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. diff --git a/Libraries/Animated/src/AnimatedImplementation.js b/Libraries/Animated/src/AnimatedImplementation.js index 2c1ce431d10686..57e34ce6e9eee3 100644 --- a/Libraries/Animated/src/AnimatedImplementation.js +++ b/Libraries/Animated/src/AnimatedImplementation.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. diff --git a/Libraries/Animated/src/AnimatedWeb.js b/Libraries/Animated/src/AnimatedWeb.js index 5bf1fdb0e184a0..cf105d4af58a6c 100644 --- a/Libraries/Animated/src/AnimatedWeb.js +++ b/Libraries/Animated/src/AnimatedWeb.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. diff --git a/Libraries/Animated/src/Easing.js b/Libraries/Animated/src/Easing.js index 94fb865882c040..9932038e6329fd 100644 --- a/Libraries/Animated/src/Easing.js +++ b/Libraries/Animated/src/Easing.js @@ -1,11 +1,11 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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 + * @flow strict */ 'use strict'; @@ -175,10 +175,7 @@ class Easing { * * - http://tiny.cc/back_default (s = 1.70158, default) */ - static back(s: number): (t: number) => number { - if (s === undefined) { - s = 1.70158; - } + static back(s: number = 1.70158): (t: number) => number { return t => t * t * ((s + 1) * t - s); } @@ -193,17 +190,17 @@ class Easing { } if (t < 2 / 2.75) { - t -= 1.5 / 2.75; - return 7.5625 * t * t + 0.75; + const t2 = t - 1.5 / 2.75; + return 7.5625 * t2 * t2 + 0.75; } if (t < 2.5 / 2.75) { - t -= 2.25 / 2.75; - return 7.5625 * t * t + 0.9375; + const t2 = t - 2.25 / 2.75; + return 7.5625 * t2 * t2 + 0.9375; } - t -= 2.625 / 2.75; - return 7.5625 * t * t + 0.984375; + const t2 = t - 2.625 / 2.75; + return 7.5625 * t2 * t2 + 0.984375; } /** diff --git a/Libraries/Animated/src/NativeAnimatedHelper.js b/Libraries/Animated/src/NativeAnimatedHelper.js index 3142ea24c084d1..ad4ede6f46567d 100644 --- a/Libraries/Animated/src/NativeAnimatedHelper.js +++ b/Libraries/Animated/src/NativeAnimatedHelper.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. @@ -153,6 +153,7 @@ const STYLES_WHITELIST = { borderTopLeftRadius: true, borderTopRightRadius: true, borderTopStartRadius: true, + elevation: true, /* ios styles */ shadowOpacity: true, shadowRadius: true, @@ -259,6 +260,22 @@ function shouldUseNativeDriver(config: AnimationConfig | EventConfig): boolean { return config.useNativeDriver || false; } +function transformDataType(value: any): number { + // Change the string type to number type so we can reuse the same logic in + // iOS and Android platform + if (typeof value !== 'string') { + return value; + } + if (/deg$/.test(value)) { + const degrees = parseFloat(value) || 0; + const radians = (degrees * Math.PI) / 180.0; + return radians; + } else { + // Assume radians + return parseFloat(value) || 0; + } +} + module.exports = { API, addWhitelistedStyleProp, @@ -271,6 +288,7 @@ module.exports = { generateNewAnimationId, assertNativeAnimatedModule, shouldUseNativeDriver, + transformDataType, get nativeEventEmitter() { if (!nativeEventEmitter) { nativeEventEmitter = new NativeEventEmitter(NativeAnimatedModule); diff --git a/Libraries/Animated/src/SpringConfig.js b/Libraries/Animated/src/SpringConfig.js index 456af9c40ec1ae..e226a3173a1902 100644 --- a/Libraries/Animated/src/SpringConfig.js +++ b/Libraries/Animated/src/SpringConfig.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. diff --git a/Libraries/Animated/src/__tests__/Animated-test.js b/Libraries/Animated/src/__tests__/Animated-test.js index 7dddf157d0dea0..930d8a020f2bff 100644 --- a/Libraries/Animated/src/__tests__/Animated-test.js +++ b/Libraries/Animated/src/__tests__/Animated-test.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. diff --git a/Libraries/Animated/src/__tests__/AnimatedNative-test.js b/Libraries/Animated/src/__tests__/AnimatedNative-test.js index f9f3836835fc47..fb6257f15d8183 100644 --- a/Libraries/Animated/src/__tests__/AnimatedNative-test.js +++ b/Libraries/Animated/src/__tests__/AnimatedNative-test.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. diff --git a/Libraries/Animated/src/__tests__/Easing-test.js b/Libraries/Animated/src/__tests__/Easing-test.js index 0284f3f0b697ef..1cb6152538fec2 100644 --- a/Libraries/Animated/src/__tests__/Easing-test.js +++ b/Libraries/Animated/src/__tests__/Easing-test.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. diff --git a/Libraries/Animated/src/__tests__/Interpolation-test.js b/Libraries/Animated/src/__tests__/Interpolation-test.js index 5515f09bacd0bc..6b77584b00d8ab 100644 --- a/Libraries/Animated/src/__tests__/Interpolation-test.js +++ b/Libraries/Animated/src/__tests__/Interpolation-test.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. diff --git a/Libraries/Animated/src/__tests__/bezier-test.js b/Libraries/Animated/src/__tests__/bezier-test.js index e9f00a7d214878..360d6262f91144 100644 --- a/Libraries/Animated/src/__tests__/bezier-test.js +++ b/Libraries/Animated/src/__tests__/bezier-test.js @@ -1,4 +1,9 @@ /** + * 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. + * * BezierEasing - use bezier curve for transition easing function * https://github.com/gre/bezier-easing * diff --git a/Libraries/Animated/src/animations/Animation.js b/Libraries/Animated/src/animations/Animation.js index b4e38016dba557..b34ac9555a1eca 100644 --- a/Libraries/Animated/src/animations/Animation.js +++ b/Libraries/Animated/src/animations/Animation.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. diff --git a/Libraries/Animated/src/animations/DecayAnimation.js b/Libraries/Animated/src/animations/DecayAnimation.js index a6fe05bb3f6343..0e09b6144d30e1 100644 --- a/Libraries/Animated/src/animations/DecayAnimation.js +++ b/Libraries/Animated/src/animations/DecayAnimation.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. diff --git a/Libraries/Animated/src/animations/SpringAnimation.js b/Libraries/Animated/src/animations/SpringAnimation.js index a0f38d3b024e5c..a44c181eb25dfe 100644 --- a/Libraries/Animated/src/animations/SpringAnimation.js +++ b/Libraries/Animated/src/animations/SpringAnimation.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. diff --git a/Libraries/Animated/src/animations/TimingAnimation.js b/Libraries/Animated/src/animations/TimingAnimation.js index 694a52c0a39f7b..61ad74e9e1f5f0 100644 --- a/Libraries/Animated/src/animations/TimingAnimation.js +++ b/Libraries/Animated/src/animations/TimingAnimation.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. diff --git a/Libraries/Animated/src/bezier.js b/Libraries/Animated/src/bezier.js index 15f8e2dc1b686f..727872b848aacd 100644 --- a/Libraries/Animated/src/bezier.js +++ b/Libraries/Animated/src/bezier.js @@ -1,8 +1,13 @@ /** + * 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. + * * BezierEasing - use bezier curve for transition easing function * https://github.com/gre/bezier-easing * - * @flow + * @flow strict * @format * @copyright 2014-2015 Gaëtan Renaudeau. MIT License. */ @@ -40,10 +45,12 @@ function getSlope(aT, aA1, aA2) { return 3.0 * A(aA1, aA2) * aT * aT + 2.0 * B(aA1, aA2) * aT + C(aA1); } -function binarySubdivide(aX, aA, aB, mX1, mX2) { +function binarySubdivide(aX, _aA, _aB, mX1, mX2) { let currentX, currentT, - i = 0; + i = 0, + aA = _aA, + aB = _aB; do { currentT = aA + (aB - aA) / 2.0; currentX = calcBezier(currentT, mX1, mX2) - aX; @@ -59,7 +66,8 @@ function binarySubdivide(aX, aA, aB, mX1, mX2) { return currentT; } -function newtonRaphsonIterate(aX, aGuessT, mX1, mX2) { +function newtonRaphsonIterate(aX, _aGuessT, mX1, mX2) { + let aGuessT = _aGuessT; for (let i = 0; i < NEWTON_ITERATIONS; ++i) { const currentSlope = getSlope(aGuessT, mX1, mX2); if (currentSlope === 0.0) { @@ -77,7 +85,7 @@ module.exports = function bezier( mX2: number, mY2: number, ) { - if (!(0 <= mX1 && mX1 <= 1 && 0 <= mX2 && mX2 <= 1)) { + if (!(mX1 >= 0 && mX1 <= 1 && mX2 >= 0 && mX2 <= 1)) { throw new Error('bezier x values must be in [0, 1] range'); } diff --git a/Libraries/Animated/src/components/AnimatedFlatList.js b/Libraries/Animated/src/components/AnimatedFlatList.js new file mode 100644 index 00000000000000..af69ff3674769e --- /dev/null +++ b/Libraries/Animated/src/components/AnimatedFlatList.js @@ -0,0 +1,17 @@ +/** + * 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. + * + * @flow strict-local + * @format + */ + +'use strict'; + +const FlatList = require('FlatList'); + +const createAnimatedComponent = require('createAnimatedComponent'); + +module.exports = createAnimatedComponent(FlatList); diff --git a/Libraries/Animated/src/components/AnimatedImage.js b/Libraries/Animated/src/components/AnimatedImage.js new file mode 100644 index 00000000000000..e7d0bc4429513a --- /dev/null +++ b/Libraries/Animated/src/components/AnimatedImage.js @@ -0,0 +1,17 @@ +/** + * 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. + * + * @flow strict-local + * @format + */ + +'use strict'; + +const Image = require('Image'); + +const createAnimatedComponent = require('createAnimatedComponent'); + +module.exports = createAnimatedComponent(Image); diff --git a/Libraries/Animated/src/components/AnimatedScrollView.js b/Libraries/Animated/src/components/AnimatedScrollView.js new file mode 100644 index 00000000000000..195f17b7005ad7 --- /dev/null +++ b/Libraries/Animated/src/components/AnimatedScrollView.js @@ -0,0 +1,17 @@ +/** + * 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. + * + * @flow strict-local + * @format + */ + +'use strict'; + +const ScrollView = require('ScrollView'); + +const createAnimatedComponent = require('createAnimatedComponent'); + +module.exports = createAnimatedComponent(ScrollView); diff --git a/Libraries/Animated/src/components/AnimatedSectionList.js b/Libraries/Animated/src/components/AnimatedSectionList.js new file mode 100644 index 00000000000000..482e203abac637 --- /dev/null +++ b/Libraries/Animated/src/components/AnimatedSectionList.js @@ -0,0 +1,17 @@ +/** + * 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. + * + * @flow strict-local + * @format + */ + +'use strict'; + +const SectionList = require('SectionList'); + +const createAnimatedComponent = require('createAnimatedComponent'); + +module.exports = createAnimatedComponent(SectionList); diff --git a/Libraries/Animated/src/components/AnimatedText.js b/Libraries/Animated/src/components/AnimatedText.js new file mode 100644 index 00000000000000..870ba144b10207 --- /dev/null +++ b/Libraries/Animated/src/components/AnimatedText.js @@ -0,0 +1,17 @@ +/** + * 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. + * + * @flow strict-local + * @format + */ + +'use strict'; + +const Text = require('Text'); + +const createAnimatedComponent = require('createAnimatedComponent'); + +module.exports = createAnimatedComponent(Text); diff --git a/Libraries/Animated/src/components/AnimatedView.js b/Libraries/Animated/src/components/AnimatedView.js new file mode 100644 index 00000000000000..396760d999485f --- /dev/null +++ b/Libraries/Animated/src/components/AnimatedView.js @@ -0,0 +1,17 @@ +/** + * 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. + * + * @flow strict-local + * @format + */ + +'use strict'; + +const View = require('View'); + +const createAnimatedComponent = require('createAnimatedComponent'); + +module.exports = createAnimatedComponent(View); diff --git a/Libraries/Animated/src/createAnimatedComponent.js b/Libraries/Animated/src/createAnimatedComponent.js index a4177d65be0e40..d705d6eebaa8be 100644 --- a/Libraries/Animated/src/createAnimatedComponent.js +++ b/Libraries/Animated/src/createAnimatedComponent.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. @@ -12,7 +12,7 @@ const {AnimatedEvent} = require('./AnimatedEvent'); const AnimatedProps = require('./nodes/AnimatedProps'); const React = require('React'); -const ViewStylePropTypes = require('ViewStylePropTypes'); +const DeprecatedViewStylePropTypes = require('DeprecatedViewStylePropTypes'); const invariant = require('fbjs/lib/invariant'); @@ -184,7 +184,7 @@ function createAnimatedComponent(Component: any): any { return; } - for (const key in ViewStylePropTypes) { + for (const key in DeprecatedViewStylePropTypes) { if (!propTypes[key] && props[key] !== undefined) { console.warn( 'You are setting the style `{ ' + diff --git a/Libraries/Animated/src/nodes/AnimatedAddition.js b/Libraries/Animated/src/nodes/AnimatedAddition.js index 60713da500213c..f3d6b55167f404 100644 --- a/Libraries/Animated/src/nodes/AnimatedAddition.js +++ b/Libraries/Animated/src/nodes/AnimatedAddition.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. diff --git a/Libraries/Animated/src/nodes/AnimatedDiffClamp.js b/Libraries/Animated/src/nodes/AnimatedDiffClamp.js index 4219eccfb377ff..3b657ef75ee23f 100644 --- a/Libraries/Animated/src/nodes/AnimatedDiffClamp.js +++ b/Libraries/Animated/src/nodes/AnimatedDiffClamp.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. diff --git a/Libraries/Animated/src/nodes/AnimatedDivision.js b/Libraries/Animated/src/nodes/AnimatedDivision.js index 3498d322211f64..9efb4214dfa41f 100644 --- a/Libraries/Animated/src/nodes/AnimatedDivision.js +++ b/Libraries/Animated/src/nodes/AnimatedDivision.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. diff --git a/Libraries/Animated/src/nodes/AnimatedInterpolation.js b/Libraries/Animated/src/nodes/AnimatedInterpolation.js index c332f864f2fac6..1f94ee71c78441 100644 --- a/Libraries/Animated/src/nodes/AnimatedInterpolation.js +++ b/Libraries/Animated/src/nodes/AnimatedInterpolation.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. @@ -350,24 +350,7 @@ class AnimatedInterpolation extends AnimatedWithChildren { } __transformDataType(range: Array) { - // Change the string array type to number array - // So we can reuse the same logic in iOS and Android platform - /* $FlowFixMe(>=0.70.0 site=react_native_fb) This comment suppresses an - * error found when Flow v0.70 was deployed. To see the error delete this - * comment and run Flow. */ - return range.map(function(value) { - if (typeof value !== 'string') { - return value; - } - if (/deg$/.test(value)) { - const degrees = parseFloat(value) || 0; - const radians = (degrees * Math.PI) / 180.0; - return radians; - } else { - // Assume radians - return parseFloat(value) || 0; - } - }); + return range.map(NativeAnimatedHelper.transformDataType); } __getNativeConfig(): any { diff --git a/Libraries/Animated/src/nodes/AnimatedModulo.js b/Libraries/Animated/src/nodes/AnimatedModulo.js index a3968566e9a2c4..a0cad545101ccb 100644 --- a/Libraries/Animated/src/nodes/AnimatedModulo.js +++ b/Libraries/Animated/src/nodes/AnimatedModulo.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. diff --git a/Libraries/Animated/src/nodes/AnimatedMultiplication.js b/Libraries/Animated/src/nodes/AnimatedMultiplication.js index 889f530c76baee..b031ba613dc805 100644 --- a/Libraries/Animated/src/nodes/AnimatedMultiplication.js +++ b/Libraries/Animated/src/nodes/AnimatedMultiplication.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. diff --git a/Libraries/Animated/src/nodes/AnimatedNode.js b/Libraries/Animated/src/nodes/AnimatedNode.js index 34e010a62f8c45..94532087d201eb 100644 --- a/Libraries/Animated/src/nodes/AnimatedNode.js +++ b/Libraries/Animated/src/nodes/AnimatedNode.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. diff --git a/Libraries/Animated/src/nodes/AnimatedProps.js b/Libraries/Animated/src/nodes/AnimatedProps.js index 75c9c25487135a..92c5012075fc85 100644 --- a/Libraries/Animated/src/nodes/AnimatedProps.js +++ b/Libraries/Animated/src/nodes/AnimatedProps.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. diff --git a/Libraries/Animated/src/nodes/AnimatedStyle.js b/Libraries/Animated/src/nodes/AnimatedStyle.js index 89d959f487dfcd..e1f3d332a2280f 100644 --- a/Libraries/Animated/src/nodes/AnimatedStyle.js +++ b/Libraries/Animated/src/nodes/AnimatedStyle.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. diff --git a/Libraries/Animated/src/nodes/AnimatedSubtraction.js b/Libraries/Animated/src/nodes/AnimatedSubtraction.js index 3fe8bbb6920703..c79860a4095074 100644 --- a/Libraries/Animated/src/nodes/AnimatedSubtraction.js +++ b/Libraries/Animated/src/nodes/AnimatedSubtraction.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. diff --git a/Libraries/Animated/src/nodes/AnimatedTracking.js b/Libraries/Animated/src/nodes/AnimatedTracking.js index 699da167c7b2c7..284d5b39af7a0b 100644 --- a/Libraries/Animated/src/nodes/AnimatedTracking.js +++ b/Libraries/Animated/src/nodes/AnimatedTracking.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. diff --git a/Libraries/Animated/src/nodes/AnimatedTransform.js b/Libraries/Animated/src/nodes/AnimatedTransform.js index 537326e58ff7c5..e3b3034675055c 100644 --- a/Libraries/Animated/src/nodes/AnimatedTransform.js +++ b/Libraries/Animated/src/nodes/AnimatedTransform.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. @@ -103,7 +103,7 @@ class AnimatedTransform extends AnimatedWithChildren { transConfigs.push({ type: 'static', property: key, - value, + value: NativeAnimatedHelper.transformDataType(value), }); } } diff --git a/Libraries/Animated/src/nodes/AnimatedValue.js b/Libraries/Animated/src/nodes/AnimatedValue.js index a3fb3a325b838e..e896f660000ab2 100644 --- a/Libraries/Animated/src/nodes/AnimatedValue.js +++ b/Libraries/Animated/src/nodes/AnimatedValue.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. @@ -10,7 +10,6 @@ 'use strict'; const AnimatedInterpolation = require('./AnimatedInterpolation'); -const AnimatedNode = require('./AnimatedNode'); const AnimatedWithChildren = require('./AnimatedWithChildren'); const InteractionManager = require('InteractionManager'); const NativeAnimatedHelper = require('../NativeAnimatedHelper'); diff --git a/Libraries/Animated/src/nodes/AnimatedValueXY.js b/Libraries/Animated/src/nodes/AnimatedValueXY.js index 3de5bbaf9d3a04..a8168c591039ad 100644 --- a/Libraries/Animated/src/nodes/AnimatedValueXY.js +++ b/Libraries/Animated/src/nodes/AnimatedValueXY.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. diff --git a/Libraries/Animated/src/nodes/AnimatedWithChildren.js b/Libraries/Animated/src/nodes/AnimatedWithChildren.js index 01189a482fae52..3940c4ae206082 100644 --- a/Libraries/Animated/src/nodes/AnimatedWithChildren.js +++ b/Libraries/Animated/src/nodes/AnimatedWithChildren.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. diff --git a/Libraries/Animated/src/polyfills/InteractionManager.js b/Libraries/Animated/src/polyfills/InteractionManager.js index 5e82aaaa544cdb..c2247c762a3da0 100644 --- a/Libraries/Animated/src/polyfills/InteractionManager.js +++ b/Libraries/Animated/src/polyfills/InteractionManager.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. diff --git a/Libraries/Animated/src/polyfills/Set.js b/Libraries/Animated/src/polyfills/Set.js index c88278bda1cb38..39205b8f9f9920 100644 --- a/Libraries/Animated/src/polyfills/Set.js +++ b/Libraries/Animated/src/polyfills/Set.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. diff --git a/Libraries/Animated/src/polyfills/flattenStyle.js b/Libraries/Animated/src/polyfills/flattenStyle.js index 21907b235f97f5..b50057af28435f 100644 --- a/Libraries/Animated/src/polyfills/flattenStyle.js +++ b/Libraries/Animated/src/polyfills/flattenStyle.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. diff --git a/Libraries/AppState/AppState.js b/Libraries/AppState/AppState.js index 554689f11ad680..8918225ec92365 100644 --- a/Libraries/AppState/AppState.js +++ b/Libraries/AppState/AppState.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. diff --git a/Libraries/BatchedBridge/BatchedBridge.js b/Libraries/BatchedBridge/BatchedBridge.js index 1c5bb4f4c8f516..663b0051457e24 100644 --- a/Libraries/BatchedBridge/BatchedBridge.js +++ b/Libraries/BatchedBridge/BatchedBridge.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. diff --git a/Libraries/BatchedBridge/MessageQueue.js b/Libraries/BatchedBridge/MessageQueue.js index c9b750df9efdc8..a7f1f5a3a5aacd 100644 --- a/Libraries/BatchedBridge/MessageQueue.js +++ b/Libraries/BatchedBridge/MessageQueue.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. @@ -60,7 +60,7 @@ class MessageQueue { this._failureCallbacks = {}; this._callID = 0; this._lastFlush = 0; - this._eventLoopStartTime = new Date().getTime(); + this._eventLoopStartTime = Date.now(); this._immediatesCallback = null; if (__DEV__) { @@ -141,7 +141,7 @@ class MessageQueue { } getEventLoopRunningTime() { - return new Date().getTime() - this._eventLoopStartTime; + return Date.now() - this._eventLoopStartTime; } registerCallableModule(name: string, module: Object) { @@ -213,11 +213,13 @@ class MessageQueue { t === 'undefined' || t === 'null' || t === 'boolean' || - t === 'number' || t === 'string' ) { return true; } + if (t === 'number') { + return isFinite(val); + } if (t === 'function' || t !== 'object') { return false; } @@ -232,10 +234,25 @@ class MessageQueue { return true; }; + // 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 t = typeof val; + if (t === 'function') { + return '<>'; + } else if (t === 'number' && !isFinite(val)) { + return '<<' + val.toString() + '>>'; + } else { + return val; + } + }; + + // Note that JSON.stringify invariant( isValidArgument(params), '%s is not usable as a native method argument', - params, + JSON.stringify(params, replacer), ); // The params object should not be mutated after being queued @@ -243,7 +260,7 @@ class MessageQueue { } this._queue[PARAMS].push(params); - const now = new Date().getTime(); + const now = Date.now(); if ( global.nativeFlushQueueImmediate && now - this._lastFlush >= MIN_TIME_BETWEEN_FLUSHES_MS @@ -323,7 +340,7 @@ class MessageQueue { } __callFunction(module: string, method: string, args: any[]): any { - this._lastFlush = new Date().getTime(); + this._lastFlush = Date.now(); this._eventLoopStartTime = this._lastFlush; if (__DEV__ || this.__spy) { Systrace.beginEvent(`${module}.${method}(${stringifySafe(args)})`); @@ -352,7 +369,7 @@ class MessageQueue { } __invokeCallback(cbID: number, args: any[]) { - this._lastFlush = new Date().getTime(); + this._lastFlush = Date.now(); this._eventLoopStartTime = this._lastFlush; // The rightmost bit of cbID indicates fail (0) or success (1), the other bits are the callID shifted left. diff --git a/Libraries/BatchedBridge/NativeModules.js b/Libraries/BatchedBridge/NativeModules.js index 61dd5bff1e61df..203cce932e0bae 100644 --- a/Libraries/BatchedBridge/NativeModules.js +++ b/Libraries/BatchedBridge/NativeModules.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. diff --git a/Libraries/BatchedBridge/__mocks__/MessageQueueTestConfig.js b/Libraries/BatchedBridge/__mocks__/MessageQueueTestConfig.js index 3f9ae5f0a4855c..bb50f5d2fa7b50 100644 --- a/Libraries/BatchedBridge/__mocks__/MessageQueueTestConfig.js +++ b/Libraries/BatchedBridge/__mocks__/MessageQueueTestConfig.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2013-present, Facebook, Inc. + * 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. diff --git a/Libraries/BatchedBridge/__mocks__/MessageQueueTestModule.js b/Libraries/BatchedBridge/__mocks__/MessageQueueTestModule.js index 05168a6b570094..37425cd7652706 100644 --- a/Libraries/BatchedBridge/__mocks__/MessageQueueTestModule.js +++ b/Libraries/BatchedBridge/__mocks__/MessageQueueTestModule.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2013-present, Facebook, Inc. + * 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. diff --git a/Libraries/BatchedBridge/__tests__/MessageQueue-test.js b/Libraries/BatchedBridge/__tests__/MessageQueue-test.js index 555a9e2053be33..77cd6948124487 100644 --- a/Libraries/BatchedBridge/__tests__/MessageQueue-test.js +++ b/Libraries/BatchedBridge/__tests__/MessageQueue-test.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2013-present, Facebook, Inc. + * 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. diff --git a/Libraries/BatchedBridge/__tests__/NativeModules-test.js b/Libraries/BatchedBridge/__tests__/NativeModules-test.js index 9702146b719090..821c3261a4169a 100644 --- a/Libraries/BatchedBridge/__tests__/NativeModules-test.js +++ b/Libraries/BatchedBridge/__tests__/NativeModules-test.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2013-present, Facebook, Inc. + * 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. @@ -10,12 +10,7 @@ 'use strict'; -jest - .enableAutomock() - .unmock('BatchedBridge') - .unmock('defineLazyObjectProperty') - .unmock('MessageQueue') - .unmock('NativeModules'); +jest.unmock('NativeModules'); let BatchedBridge; let NativeModules; diff --git a/Libraries/Blob/Blob.js b/Libraries/Blob/Blob.js index 0e36b07f7f4e5a..c7e013dfa0b530 100644 --- a/Libraries/Blob/Blob.js +++ b/Libraries/Blob/Blob.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2013-present, Facebook, Inc. + * 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. diff --git a/Libraries/Blob/BlobManager.js b/Libraries/Blob/BlobManager.js index 6677019411aeac..460980bb5b21ef 100644 --- a/Libraries/Blob/BlobManager.js +++ b/Libraries/Blob/BlobManager.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2013-present, Facebook, Inc. + * 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. diff --git a/Libraries/Blob/BlobRegistry.js b/Libraries/Blob/BlobRegistry.js index 445fe6bb855835..cfd0475a53ea07 100644 --- a/Libraries/Blob/BlobRegistry.js +++ b/Libraries/Blob/BlobRegistry.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2013-present, Facebook, Inc. + * 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. diff --git a/Libraries/Blob/BlobTypes.js b/Libraries/Blob/BlobTypes.js index 2e5be53e19615f..de105d2a6904d3 100644 --- a/Libraries/Blob/BlobTypes.js +++ b/Libraries/Blob/BlobTypes.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2013-present, Facebook, Inc. + * 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. diff --git a/Libraries/Blob/File.js b/Libraries/Blob/File.js index 2f57183cdb3f19..fcad0d0bc1415c 100644 --- a/Libraries/Blob/File.js +++ b/Libraries/Blob/File.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2013-present, Facebook, Inc. + * 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. diff --git a/Libraries/Blob/FileReader.js b/Libraries/Blob/FileReader.js index 309e4577a455f8..b9181ed9aaa34b 100644 --- a/Libraries/Blob/FileReader.js +++ b/Libraries/Blob/FileReader.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. diff --git a/Libraries/Blob/RCTBlobManager.h b/Libraries/Blob/RCTBlobManager.h index 24b589ef987ae5..1d5750799e3d29 100755 --- a/Libraries/Blob/RCTBlobManager.h +++ b/Libraries/Blob/RCTBlobManager.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. diff --git a/Libraries/Blob/RCTBlobManager.mm b/Libraries/Blob/RCTBlobManager.mm index 7c0cbb8673f064..99084d9aba3b53 100755 --- a/Libraries/Blob/RCTBlobManager.mm +++ b/Libraries/Blob/RCTBlobManager.mm @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. diff --git a/Libraries/Blob/RCTFileReaderModule.h b/Libraries/Blob/RCTFileReaderModule.h index 72d224b0d968cb..89c018381bcd32 100644 --- a/Libraries/Blob/RCTFileReaderModule.h +++ b/Libraries/Blob/RCTFileReaderModule.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. diff --git a/Libraries/Blob/RCTFileReaderModule.m b/Libraries/Blob/RCTFileReaderModule.m index 5059e0b84180ee..26b33f63e471a9 100644 --- a/Libraries/Blob/RCTFileReaderModule.m +++ b/Libraries/Blob/RCTFileReaderModule.m @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. diff --git a/Libraries/Blob/URL.js b/Libraries/Blob/URL.js index de59323c784071..36dbe0ffa02b50 100644 --- a/Libraries/Blob/URL.js +++ b/Libraries/Blob/URL.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2013-present, Facebook, Inc. + * 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. diff --git a/Libraries/Blob/__mocks__/BlobModule.js b/Libraries/Blob/__mocks__/BlobModule.js index e904d2929dd74b..3a1cb8eda6174b 100644 --- a/Libraries/Blob/__mocks__/BlobModule.js +++ b/Libraries/Blob/__mocks__/BlobModule.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. diff --git a/Libraries/Blob/__mocks__/FileReaderModule.js b/Libraries/Blob/__mocks__/FileReaderModule.js index 0f35aa89ace07e..da687eca470b1d 100644 --- a/Libraries/Blob/__mocks__/FileReaderModule.js +++ b/Libraries/Blob/__mocks__/FileReaderModule.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. diff --git a/Libraries/Blob/__tests__/Blob-test.js b/Libraries/Blob/__tests__/Blob-test.js index 47bf5fee7c1361..7600c0c967825c 100644 --- a/Libraries/Blob/__tests__/Blob-test.js +++ b/Libraries/Blob/__tests__/Blob-test.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. diff --git a/Libraries/Blob/__tests__/BlobManager-test.js b/Libraries/Blob/__tests__/BlobManager-test.js index c141d42f16334c..73ad2a9de1103f 100644 --- a/Libraries/Blob/__tests__/BlobManager-test.js +++ b/Libraries/Blob/__tests__/BlobManager-test.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. diff --git a/Libraries/Blob/__tests__/File-test.js b/Libraries/Blob/__tests__/File-test.js index c10f90c18766ae..11b25116809a5d 100644 --- a/Libraries/Blob/__tests__/File-test.js +++ b/Libraries/Blob/__tests__/File-test.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. diff --git a/Libraries/Blob/__tests__/FileReader-test.js b/Libraries/Blob/__tests__/FileReader-test.js index b2237550bf7184..a375c3ef374710 100644 --- a/Libraries/Blob/__tests__/FileReader-test.js +++ b/Libraries/Blob/__tests__/FileReader-test.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. diff --git a/Libraries/BugReporting/BugReporting.js b/Libraries/BugReporting/BugReporting.js index 6c63b6a1eebf98..1623b71741f059 100644 --- a/Libraries/BugReporting/BugReporting.js +++ b/Libraries/BugReporting/BugReporting.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2013-present, Facebook, Inc. + * 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. @@ -11,7 +11,6 @@ 'use strict'; const RCTDeviceEventEmitter = require('RCTDeviceEventEmitter'); -const Map = require('Map'); const infoLog = require('infoLog'); import type EmitterSubscription from 'EmitterSubscription'; diff --git a/Libraries/BugReporting/dumpReactTree.js b/Libraries/BugReporting/dumpReactTree.js index ead8f4bdd76c32..2ef17ecf034784 100644 --- a/Libraries/BugReporting/dumpReactTree.js +++ b/Libraries/BugReporting/dumpReactTree.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2013-present, Facebook, Inc. + * 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. diff --git a/Libraries/BugReporting/getReactData.js b/Libraries/BugReporting/getReactData.js index b4d1c4a32fd557..cc9bc55f0cc394 100644 --- a/Libraries/BugReporting/getReactData.js +++ b/Libraries/BugReporting/getReactData.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. diff --git a/Libraries/CameraRoll/CameraRoll.js b/Libraries/CameraRoll/CameraRoll.js index f2a4f65aa80933..ad8db27937aa46 100644 --- a/Libraries/CameraRoll/CameraRoll.js +++ b/Libraries/CameraRoll/CameraRoll.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. @@ -13,7 +13,7 @@ const PropTypes = require('prop-types'); const {checkPropTypes} = PropTypes; const RCTCameraRollManager = require('NativeModules').CameraRollManager; -const createStrictShapeTypeChecker = require('createStrictShapeTypeChecker'); +const deprecatedCreateStrictShapeTypeChecker = require('deprecatedCreateStrictShapeTypeChecker'); const invariant = require('fbjs/lib/invariant'); const GROUP_TYPES_OPTIONS = { @@ -32,10 +32,12 @@ const ASSET_TYPE_OPTIONS = { Photos: 'Photos', }; -type GetPhotosParams = { +export type GroupTypes = $Keys; + +export type GetPhotosParams = { first: number, after?: string, - groupTypes?: $Keys, + groupTypes?: GroupTypes, groupName?: string, assetType?: $Keys, mimeTypes?: Array, @@ -44,7 +46,7 @@ type GetPhotosParams = { /** * Shape of the param arg for the `getPhotos` function. */ -const getPhotosParamChecker = createStrictShapeTypeChecker({ +const getPhotosParamChecker = deprecatedCreateStrictShapeTypeChecker({ /** * The number of photos wanted in reverse order of the photo application * (i.e. most recent first for SavedPhotos). @@ -79,48 +81,51 @@ const getPhotosParamChecker = createStrictShapeTypeChecker({ mimeTypes: PropTypes.arrayOf(PropTypes.string), }); -type GetPhotosReturn = Promise<{ - edges: Array<{ - node: { - type: string, - group_name: string, - image: { - uri: string, - height: number, - width: number, - isStored?: boolean, - playableDuration: number, - }, - timestamp: number, - location?: { - latitude?: number, - longitude?: number, - altitude?: number, - heading?: number, - speed?: number, - }, +export type PhotoIdentifier = { + node: { + type: string, + group_name: string, + image: { + filename: string, + uri: string, + height: number, + width: number, + isStored?: boolean, + playableDuration: number, + }, + timestamp: number, + location?: { + latitude?: number, + longitude?: number, + altitude?: number, + heading?: number, + speed?: number, }, - }>, + }, +}; + +export type PhotoIdentifiersPage = { + edges: Array, page_info: { has_next_page: boolean, start_cursor?: string, end_cursor?: string, }, -}>; +}; /** * Shape of the return value of the `getPhotos` function. */ -const getPhotosReturnChecker = createStrictShapeTypeChecker({ +const getPhotosReturnChecker = deprecatedCreateStrictShapeTypeChecker({ edges: PropTypes.arrayOf( /* $FlowFixMe(>=0.66.0 site=react_native_fb) This comment suppresses an * error found when Flow v0.66 was deployed. To see the error delete this * comment and run Flow. */ - createStrictShapeTypeChecker({ - node: createStrictShapeTypeChecker({ + deprecatedCreateStrictShapeTypeChecker({ + node: deprecatedCreateStrictShapeTypeChecker({ type: PropTypes.string.isRequired, group_name: PropTypes.string.isRequired, - image: createStrictShapeTypeChecker({ + image: deprecatedCreateStrictShapeTypeChecker({ uri: PropTypes.string.isRequired, height: PropTypes.number.isRequired, width: PropTypes.number.isRequired, @@ -128,7 +133,7 @@ const getPhotosReturnChecker = createStrictShapeTypeChecker({ playableDuration: PropTypes.number.isRequired, }).isRequired, timestamp: PropTypes.number.isRequired, - location: createStrictShapeTypeChecker({ + location: deprecatedCreateStrictShapeTypeChecker({ latitude: PropTypes.number, longitude: PropTypes.number, altitude: PropTypes.number, @@ -138,7 +143,7 @@ const getPhotosReturnChecker = createStrictShapeTypeChecker({ }).isRequired, }), ).isRequired, - page_info: createStrictShapeTypeChecker({ + page_info: deprecatedCreateStrictShapeTypeChecker({ has_next_page: PropTypes.bool.isRequired, start_cursor: PropTypes.string, end_cursor: PropTypes.string, @@ -151,8 +156,8 @@ const getPhotosReturnChecker = createStrictShapeTypeChecker({ * See https://facebook.github.io/react-native/docs/cameraroll.html */ class CameraRoll { - static GroupTypesOptions: Object = GROUP_TYPES_OPTIONS; - static AssetTypeOptions: Object = ASSET_TYPE_OPTIONS; + static GroupTypesOptions = GROUP_TYPES_OPTIONS; + static AssetTypeOptions = ASSET_TYPE_OPTIONS; /** * `CameraRoll.saveImageWithTag()` is deprecated. Use `CameraRoll.saveToCameraRoll()` instead. @@ -204,7 +209,7 @@ class CameraRoll { * * See https://facebook.github.io/react-native/docs/cameraroll.html#getphotos */ - static getPhotos(params: GetPhotosParams): GetPhotosReturn { + static getPhotos(params: GetPhotosParams): Promise { if (__DEV__) { checkPropTypes( {params: getPhotosParamChecker}, diff --git a/Libraries/CameraRoll/ImagePickerIOS.js b/Libraries/CameraRoll/ImagePickerIOS.js index 785f4b57cb6b56..9c783339835f88 100644 --- a/Libraries/CameraRoll/ImagePickerIOS.js +++ b/Libraries/CameraRoll/ImagePickerIOS.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. diff --git a/Libraries/CameraRoll/RCTAssetsLibraryRequestHandler.h b/Libraries/CameraRoll/RCTAssetsLibraryRequestHandler.h index 8189bb56e4ea8c..7ccba500f59f0b 100644 --- a/Libraries/CameraRoll/RCTAssetsLibraryRequestHandler.h +++ b/Libraries/CameraRoll/RCTAssetsLibraryRequestHandler.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. diff --git a/Libraries/CameraRoll/RCTAssetsLibraryRequestHandler.m b/Libraries/CameraRoll/RCTAssetsLibraryRequestHandler.m index 9721b392b80f78..663598ceaea0b7 100644 --- a/Libraries/CameraRoll/RCTAssetsLibraryRequestHandler.m +++ b/Libraries/CameraRoll/RCTAssetsLibraryRequestHandler.m @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. diff --git a/Libraries/CameraRoll/RCTCameraRollManager.h b/Libraries/CameraRoll/RCTCameraRollManager.h index b8b2c7d2ad63c7..3341c539b0e9dc 100644 --- a/Libraries/CameraRoll/RCTCameraRollManager.h +++ b/Libraries/CameraRoll/RCTCameraRollManager.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. diff --git a/Libraries/CameraRoll/RCTCameraRollManager.m b/Libraries/CameraRoll/RCTCameraRollManager.m index e6e397392bd159..96e117c16a3783 100644 --- a/Libraries/CameraRoll/RCTCameraRollManager.m +++ b/Libraries/CameraRoll/RCTCameraRollManager.m @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. diff --git a/Libraries/CameraRoll/RCTImagePickerManager.h b/Libraries/CameraRoll/RCTImagePickerManager.h index 825e7721a46c01..5f489191c3ffc2 100644 --- a/Libraries/CameraRoll/RCTImagePickerManager.h +++ b/Libraries/CameraRoll/RCTImagePickerManager.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013-present, Facebook, Inc. + * 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. diff --git a/Libraries/CameraRoll/RCTImagePickerManager.m b/Libraries/CameraRoll/RCTImagePickerManager.m index 6273d7bed9c321..b8e570cfcd7b77 100644 --- a/Libraries/CameraRoll/RCTImagePickerManager.m +++ b/Libraries/CameraRoll/RCTImagePickerManager.m @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013-present, Facebook, Inc. + * 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. @@ -16,6 +16,16 @@ #import #import +@interface RCTImagePickerController : UIImagePickerController + +@property (nonatomic, assign) BOOL unmirrorFrontFacingCamera; + +@end + +@implementation RCTImagePickerController + +@end + @interface RCTImagePickerManager () @end @@ -31,6 +41,22 @@ @implementation RCTImagePickerManager @synthesize bridge = _bridge; +- (id)init +{ + if (self = [super init]) { + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(cameraChanged:) + name:@"AVCaptureDeviceDidStartRunningNotification" + object:nil]; + } + return self; +} + +- (void)dealloc +{ + [[NSNotificationCenter defaultCenter] removeObserver:self name:@"AVCaptureDeviceDidStartRunningNotification" object:nil]; +} + - (dispatch_queue_t)methodQueue { return dispatch_get_main_queue(); @@ -56,9 +82,10 @@ - (dispatch_queue_t)methodQueue return; } - UIImagePickerController *imagePicker = [UIImagePickerController new]; + RCTImagePickerController *imagePicker = [RCTImagePickerController new]; imagePicker.delegate = self; imagePicker.sourceType = UIImagePickerControllerSourceTypeCamera; + imagePicker.unmirrorFrontFacingCamera = [RCTConvert BOOL:config[@"unmirrorFrontFacingCamera"]]; if ([RCTConvert BOOL:config[@"videoMode"]]) { imagePicker.cameraCaptureMode = UIImagePickerControllerCameraCaptureModeVideo; @@ -175,4 +202,17 @@ - (void)_dismissPicker:(UIImagePickerController *)picker args:(NSArray *)args } } +- (void)cameraChanged:(NSNotification *)notification +{ + for (UIImagePickerController *picker in _pickers) { + if ([picker isKindOfClass:[RCTImagePickerController class]] + && ((RCTImagePickerController *)picker).unmirrorFrontFacingCamera + && picker.cameraDevice == UIImagePickerControllerCameraDeviceFront) { + picker.cameraViewTransform = CGAffineTransformScale(CGAffineTransformIdentity, -1, 1); + } else { + picker.cameraViewTransform = CGAffineTransformIdentity; + } + } +} + @end diff --git a/Libraries/CameraRoll/RCTPhotoLibraryImageLoader.h b/Libraries/CameraRoll/RCTPhotoLibraryImageLoader.h index 0a45f184dab73c..d3b8dc646b3c6b 100644 --- a/Libraries/CameraRoll/RCTPhotoLibraryImageLoader.h +++ b/Libraries/CameraRoll/RCTPhotoLibraryImageLoader.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. diff --git a/Libraries/CameraRoll/RCTPhotoLibraryImageLoader.m b/Libraries/CameraRoll/RCTPhotoLibraryImageLoader.m index ac27231adc9e9a..e6c191e93b5099 100644 --- a/Libraries/CameraRoll/RCTPhotoLibraryImageLoader.m +++ b/Libraries/CameraRoll/RCTPhotoLibraryImageLoader.m @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. diff --git a/Libraries/Color/normalizeColor.js b/Libraries/Color/normalizeColor.js index f94dcaf8bc3fdc..83df4162017f46 100755 --- a/Libraries/Color/normalizeColor.js +++ b/Libraries/Color/normalizeColor.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. diff --git a/Libraries/Components/AccessibilityInfo/AccessibilityInfo.android.js b/Libraries/Components/AccessibilityInfo/AccessibilityInfo.android.js index f3bb359b70e37d..6cd0193eb42eca 100644 --- a/Libraries/Components/AccessibilityInfo/AccessibilityInfo.android.js +++ b/Libraries/Components/AccessibilityInfo/AccessibilityInfo.android.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. diff --git a/Libraries/Components/AccessibilityInfo/AccessibilityInfo.ios.js b/Libraries/Components/AccessibilityInfo/AccessibilityInfo.ios.js index da1f6e4f1610d1..5a1d64e9595e83 100644 --- a/Libraries/Components/AccessibilityInfo/AccessibilityInfo.ios.js +++ b/Libraries/Components/AccessibilityInfo/AccessibilityInfo.ios.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. diff --git a/Libraries/Components/ActivityIndicator/ActivityIndicator.js b/Libraries/Components/ActivityIndicator/ActivityIndicator.js index fd70c7e5d2a165..88d15f4dc32d0d 100644 --- a/Libraries/Components/ActivityIndicator/ActivityIndicator.js +++ b/Libraries/Components/ActivityIndicator/ActivityIndicator.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. @@ -113,6 +113,7 @@ const ActivityIndicator = ( // $FlowFixMe - TODO T29156721 `React.forwardRef` is not defined in Flow, yet. const ActivityIndicatorWithRef = React.forwardRef(ActivityIndicator); +ActivityIndicatorWithRef.displayName = 'ActivityIndicator'; ActivityIndicatorWithRef.defaultProps = { animating: true, diff --git a/Libraries/Components/ActivityIndicator/__tests__/ActivityIndicator-test.js b/Libraries/Components/ActivityIndicator/__tests__/ActivityIndicator-test.js new file mode 100644 index 00000000000000..ec97e8255c4f29 --- /dev/null +++ b/Libraries/Components/ActivityIndicator/__tests__/ActivityIndicator-test.js @@ -0,0 +1,54 @@ +/** + * 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 + * @emails oncall+react_native + * @flow + */ + +'use strict'; + +const React = require('React'); +const ActivityIndicator = require('ActivityIndicator'); +const render = require('../../../../jest/renderer'); + +describe('ActivityIndicator', () => { + it('should set displayName to prevent regressions', () => { + expect(ActivityIndicator.displayName).toBe('ActivityIndicator'); + }); + + it('should render as when mocked', () => { + const instance = render.create( + , + ); + expect(instance).toMatchSnapshot(); + }); + + it('should shallow render as when mocked', () => { + const output = render.shallow( + , + ); + expect(output).toMatchSnapshot(); + }); + + it('should shallow render as when not mocked', () => { + jest.dontMock('ActivityIndicator'); + + const output = render.shallow( + , + ); + expect(output).toMatchSnapshot(); + }); + + it('should render as when not mocked', () => { + jest.dontMock('ActivityIndicator'); + + const instance = render.create( + , + ); + expect(instance).toMatchSnapshot(); + }); +}); diff --git a/Libraries/Components/ActivityIndicator/__tests__/__snapshots__/ActivityIndicator-test.js.snap b/Libraries/Components/ActivityIndicator/__tests__/__snapshots__/ActivityIndicator-test.js.snap new file mode 100644 index 00000000000000..d8cbec0f26428f --- /dev/null +++ b/Libraries/Components/ActivityIndicator/__tests__/__snapshots__/ActivityIndicator-test.js.snap @@ -0,0 +1,54 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`ActivityIndicator should render as when mocked 1`] = ` + +`; + +exports[`ActivityIndicator should render as when not mocked 1`] = ` + + + +`; + +exports[`ActivityIndicator should shallow render as when mocked 1`] = ` + +`; + +exports[`ActivityIndicator should shallow render as when not mocked 1`] = ` + +`; diff --git a/Libraries/Components/AppleTV/TVEventHandler.js b/Libraries/Components/AppleTV/TVEventHandler.js index 567776b5d9bfa9..9b584de6bec581 100644 --- a/Libraries/Components/AppleTV/TVEventHandler.js +++ b/Libraries/Components/AppleTV/TVEventHandler.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. diff --git a/Libraries/Components/AppleTV/TVViewPropTypes.js b/Libraries/Components/AppleTV/TVViewPropTypes.js index 5bda1f618c5440..d7492967bc128b 100644 --- a/Libraries/Components/AppleTV/TVViewPropTypes.js +++ b/Libraries/Components/AppleTV/TVViewPropTypes.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. @@ -9,76 +9,100 @@ */ 'use strict'; -const PropTypes = require('prop-types'); + +export type TVParallaxPropertiesType = $ReadOnly<{| + /** + * If true, parallax effects are enabled. Defaults to true. + */ + enabled?: boolean, + + /** + * Defaults to 2.0. + */ + shiftDistanceX?: number, + + /** + * Defaults to 2.0. + */ + shiftDistanceY?: number, + + /** + * Defaults to 0.05. + */ + tiltAngle?: number, + + /** + * Defaults to 1.0 + */ + magnification?: number, + + /** + * Defaults to 1.0 + */ + pressMagnification?: number, + + /** + * Defaults to 0.3 + */ + pressDuration?: number, + + /** + * Defaults to 0.3 + */ + pressDelay?: number, +|}>; /** * Additional View properties for Apple TV */ -const TVViewPropTypes = { +export type TVViewProps = $ReadOnly<{| /** - * When set to true, this view will be focusable - * and navigable using the TV remote. + * *(Apple TV only)* When set to true, this view will be focusable + * and navigable using the Apple TV remote. + * + * @platform ios */ - isTVSelectable: PropTypes.bool, + isTVSelectable?: boolean, /** - * May be set to true to force the TV focus engine to move focus to this view. + * *(Apple TV only)* May be set to true to force the Apple TV focus engine to move focus to this view. + * + * @platform ios */ - hasTVPreferredFocus: PropTypes.bool, + hasTVPreferredFocus?: boolean, /** * *(Apple TV only)* Object with properties to control Apple TV parallax effects. * - * enabled: If true, parallax effects are enabled. Defaults to true. - * shiftDistanceX: Defaults to 2.0. - * shiftDistanceY: Defaults to 2.0. - * tiltAngle: Defaults to 0.05. - * magnification: Defaults to 1.0. - * pressMagnification: Defaults to 1.0. - * pressDuration: Defaults to 0.3. - * pressDelay: Defaults to 0.0. - * * @platform ios */ - tvParallaxProperties: PropTypes.object, + tvParallaxProperties?: TVParallaxPropertiesType, /** * *(Apple TV only)* May be used to change the appearance of the Apple TV parallax effect when this view goes in or out of focus. Defaults to 2.0. * * @platform ios */ - tvParallaxShiftDistanceX: PropTypes.number, + tvParallaxShiftDistanceX?: number, /** * *(Apple TV only)* May be used to change the appearance of the Apple TV parallax effect when this view goes in or out of focus. Defaults to 2.0. * * @platform ios */ - tvParallaxShiftDistanceY: PropTypes.number, + tvParallaxShiftDistanceY?: number, /** * *(Apple TV only)* May be used to change the appearance of the Apple TV parallax effect when this view goes in or out of focus. Defaults to 0.05. * * @platform ios */ - tvParallaxTiltAngle: PropTypes.number, + tvParallaxTiltAngle?: number, /** * *(Apple TV only)* May be used to change the appearance of the Apple TV parallax effect when this view goes in or out of focus. Defaults to 1.0. * * @platform ios */ - tvParallaxMagnification: PropTypes.number, -}; - -export type TVViewProps = $ReadOnly<{| - isTVSelectable?: boolean, - hasTVPreferredFocus?: boolean, - tvParallaxProperties?: Object, - tvParallaxShiftDistanceX?: number, - tvParallaxShiftDistanceY?: number, - tvParallaxTiltAngle?: number, tvParallaxMagnification?: number, |}>; - -module.exports = TVViewPropTypes; diff --git a/Libraries/Components/Button.js b/Libraries/Components/Button.js index 707d55f2c93798..b542dd481ab135 100644 --- a/Libraries/Components/Button.js +++ b/Libraries/Components/Button.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. @@ -10,10 +10,8 @@ 'use strict'; -const ColorPropType = require('ColorPropType'); const Platform = require('Platform'); const React = require('React'); -const PropTypes = require('prop-types'); const StyleSheet = require('StyleSheet'); const Text = require('Text'); const TouchableHighlight = require('TouchableHighlight'); // [TODO(windows ISS) @@ -23,6 +21,48 @@ const View = require('View'); const invariant = require('fbjs/lib/invariant'); +import type { PressEvent } from 'CoreEventTypes'; + +type ButtonProps = $ReadOnly<{| + /** + * Text to display inside the button + */ + title: string, + + /** + * Handler to be called when the user taps the button + */ + onPress: (event?: PressEvent) => mixed, + + /** + * Color of the text (iOS), or background color of the button (Android) + */ + color ?: ? string, + + /** + * TV preferred focus (see documentation for the View component). + */ + hasTVPreferredFocus ?: ? boolean, + + /** + * Text to display for blindness accessibility features + */ + accessibilityLabel ?: ? string, + /** + * Hint text to display blindness accessibility features + */ + accessibilityHint: PropTypes.string, // TODO(OSS Candidate ISS#2710739) + /** + * If true, disable all interactions for this component. + */ + disabled ?: ? boolean, + + /** + * Used to locate this view in end-to-end tests. + */ + testID ?: ? string, +|}>; + /** * A basic button component that should render nicely on any platform. Supports * a minimal level of customization. @@ -51,51 +91,7 @@ const invariant = require('fbjs/lib/invariant'); * */ -class Button extends React.Component<{ - title: string, - onPress: () => any, - color?: ?string, - hasTVPreferredFocus?: ?boolean, - accessibilityLabel?: ?string, - accessibilityHint?: string, // TODO(OSS Candidate ISS#2710739) - disabled?: ?boolean, - testID?: ?string, -}> { - static propTypes = { - /** - * Text to display inside the button - */ - title: PropTypes.string.isRequired, - /** - * Text to display for blindness accessibility features - */ - accessibilityLabel: PropTypes.string, - /** - * Hint text to display blindness accessibility features - */ - accessibilityHint: PropTypes.string, // TODO(OSS Candidate ISS#2710739) - /** - * Color of the text (iOS, macOS), or background color of the button (Android) - */ - color: ColorPropType, - /** - * If true, disable all interactions for this component. - */ - disabled: PropTypes.bool, - /** - * TV preferred focus (see documentation for the View component). - */ - hasTVPreferredFocus: PropTypes.bool, - /** - * Handler to be called when the user taps the button - */ - onPress: PropTypes.func.isRequired, - /** - * Used to locate this view in end-to-end tests. - */ - testID: PropTypes.string, - }; - +class Button extends React.Component { render() { const { accessibilityLabel, @@ -114,9 +110,9 @@ class Button extends React.Component<{ Platform.OS === 'ios' || Platform.OS === 'macos' /* TODO(macOS ISS#2323203) */ ) { - textStyles.push({color: color}); + textStyles.push({ color: color }); } else { - buttonStyles.push({backgroundColor: color}); + buttonStyles.push({ backgroundColor: color }); } } const accessibilityStates = []; @@ -174,36 +170,30 @@ const styles = StyleSheet.create({ }, windesktop: {}, // ]TODO(windows ISS) }), - text: Platform.select({ - ios: { - // iOS blue from https://developer.apple.com/ios/human-interface-guidelines/visual-design/color/ - color: '#007AFF', - textAlign: 'center', - padding: 8, - fontSize: 18, - }, - android: { - color: 'white', - textAlign: 'center', - padding: 8, - fontWeight: '500', - }, - macos: { - // [TODO(macOS ISS#2323203) - color: '#007AFF', - textAlign: 'center', - padding: 8, - fontSize: 18, - }, // ]TODO(macOS ISS#2323203) - uwp: { - // [TODO(windows ISS) - textAlign: 'center', - color: 'white', - padding: 8, - fontWeight: '500', - }, - windesktop: {}, // ]TODO(windows ISS) - }), + text: { + textAlign: 'center', + padding: 8, + ...Platform.select({ + ios: { + // iOS blue from https://developer.apple.com/ios/human-interface-guidelines/visual-design/color/ + color: '#007AFF', + fontSize: 18, + }, + android: { + color: 'white', + fontWeight: '500', + }, + macos: { // [TODO(macOS ISS#2323203) + color: '#007AFF', + fontSize: 18, + }, // ]TODO(macOS ISS#2323203) + uwp: { // [TODO(windows ISS) + color: 'white', + fontWeight: '500', + }, + windesktop: {}, // ]TODO(windows ISS) + }), + }, buttonDisabled: Platform.select({ ios: {}, android: { diff --git a/Libraries/Components/CheckBox/CheckBox.android.js b/Libraries/Components/CheckBox/CheckBox.android.js index 45a3e6f08ac0c4..fe5e23eafc5cf2 100644 --- a/Libraries/Components/CheckBox/CheckBox.android.js +++ b/Libraries/Components/CheckBox/CheckBox.android.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2017-present, Facebook, Inc. + * 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. @@ -9,21 +9,76 @@ */ 'use strict'; -const NativeMethodsMixin = require('NativeMethodsMixin'); -const PropTypes = require('prop-types'); const React = require('React'); const StyleSheet = require('StyleSheet'); -const ViewPropTypes = require('ViewPropTypes'); -const createReactClass = require('create-react-class'); const requireNativeComponent = require('requireNativeComponent'); +const nullthrows = require('nullthrows'); +const setAndForwardRef = require('setAndForwardRef'); -const RCTCheckBox = requireNativeComponent('AndroidCheckBox'); +import type {ViewProps} from 'ViewPropTypes'; +import type {SyntheticEvent} from 'CoreEventTypes'; +import type {NativeComponent} from 'ReactNative'; -type DefaultProps = { - value: boolean, - disabled: boolean, -}; +type CheckBoxEvent = SyntheticEvent< + $ReadOnly<{| + target: number, + value: boolean, + |}>, +>; + +type CommonProps = $ReadOnly<{| + ...ViewProps, + + /** + * Used in case the props change removes the component. + */ + onChange?: ?(event: CheckBoxEvent) => mixed, + + /** + * Invoked with the new value when the value changes. + */ + onValueChange?: ?(value: boolean) => mixed, + + /** + * Used to locate this view in end-to-end tests. + */ + testID?: ?string, +|}>; + +type NativeProps = $ReadOnly<{| + ...CommonProps, + + on?: ?boolean, + enabled?: boolean, +|}>; + +type CheckBoxNativeType = Class>; + +type Props = $ReadOnly<{| + ...CommonProps, + + /** + * The value of the checkbox. If true the checkbox will be turned on. + * Default value is false. + */ + value?: ?boolean, + + /** + * If true the user won't be able to toggle the checkbox. + * Default value is false. + */ + disabled?: ?boolean, + + /** + * Used to get the ref for the native checkbox + */ + forwardedRef?: ?React.Ref, +|}>; + +const RCTCheckBox = ((requireNativeComponent( + 'AndroidCheckBox', +): any): CheckBoxNativeType); /** * Renders a boolean input (Android only). @@ -80,85 +135,64 @@ type DefaultProps = { * @keyword checkbox * @keyword toggle */ -let CheckBox = createReactClass({ - displayName: 'CheckBox', - propTypes: { - ...ViewPropTypes, - /** - * The value of the checkbox. If true the checkbox will be turned on. - * Default value is false. - */ - value: PropTypes.bool, - /** - * If true the user won't be able to toggle the checkbox. - * Default value is false. - */ - disabled: PropTypes.bool, - /** - * Used in case the props change removes the component. - */ - onChange: PropTypes.func, - /** - * Invoked with the new value when the value changes. - */ - onValueChange: PropTypes.func, - /** - * Used to locate this view in end-to-end tests. - */ - testID: PropTypes.string, - }, +class CheckBox extends React.Component { + _nativeRef: ?React.ElementRef = null; + _setNativeRef = setAndForwardRef({ + getForwardedRef: () => this.props.forwardedRef, + setLocalRef: ref => { + this._nativeRef = ref; + }, + }); - getDefaultProps: function(): DefaultProps { - return { - value: false, - disabled: false, - }; - }, - - mixins: [NativeMethodsMixin], - - _rctCheckBox: {}, - _onChange: function(event: Object) { - this._rctCheckBox.setNativeProps({value: this.props.value}); + _onChange = (event: CheckBoxEvent) => { + const value = this.props.value ?? false; + nullthrows(this._nativeRef).setNativeProps({value: value}); // Change the props after the native props are set in case the props // change removes the component this.props.onChange && this.props.onChange(event); this.props.onValueChange && this.props.onValueChange(event.nativeEvent.value); - }, + }; - render: function() { - let props = {...this.props}; - props.onStartShouldSetResponder = () => true; - props.onResponderTerminationRequest = () => false; - /* $FlowFixMe(>=0.78.0 site=react_native_android_fb) This issue was found - * when making Flow check .android.js files. */ - props.enabled = !this.props.disabled; - /* $FlowFixMe(>=0.78.0 site=react_native_android_fb) This issue was found - * when making Flow check .android.js files. */ - props.on = this.props.value; - props.style = [styles.rctCheckBox, this.props.style]; + render() { + const {disabled: _, value: __, style, forwardedRef, ...props} = this.props; + const disabled = this.props.disabled ?? false; + const value = this.props.value ?? false; + + const nativeProps = { + ...props, + onStartShouldSetResponder: () => true, + onResponderTerminationRequest: () => false, + enabled: !disabled, + on: value, + style: [styles.rctCheckBox, style], + }; return ( { - /* $FlowFixMe(>=0.53.0 site=react_native_fb,react_native_oss) This - * comment suppresses an error when upgrading Flow's support for - * React. To see the error delete this comment and run Flow. */ - this._rctCheckBox = ref; - }} + {...nativeProps} + ref={this._setNativeRef} onChange={this._onChange} /> ); - }, -}); + } +} -let styles = StyleSheet.create({ +const styles = StyleSheet.create({ rctCheckBox: { height: 32, width: 32, }, }); -module.exports = CheckBox; +/** + * Can't use CheckBoxNativeType because it has different props + */ +type CheckBoxType = Class>; + +// $FlowFixMe - TODO T29156721 `React.forwardRef` is not defined in Flow, yet. +const CheckBoxWithRef = React.forwardRef(function CheckBoxWithRef(props, ref) { + return ; +}); + +module.exports = (CheckBoxWithRef: CheckBoxType); diff --git a/Libraries/Components/CheckBox/CheckBox.ios.js b/Libraries/Components/CheckBox/CheckBox.ios.js index 11252120daa166..8bc431d610e066 100644 --- a/Libraries/Components/CheckBox/CheckBox.ios.js +++ b/Libraries/Components/CheckBox/CheckBox.ios.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2017-present, Facebook, Inc. + * 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. diff --git a/Libraries/Components/Clipboard/Clipboard.js b/Libraries/Components/Clipboard/Clipboard.js index a8096b26a0770b..d9eddb6cd0548e 100644 --- a/Libraries/Components/Clipboard/Clipboard.js +++ b/Libraries/Components/Clipboard/Clipboard.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. diff --git a/Libraries/Components/DatePicker/DatePickerIOS.android.js b/Libraries/Components/DatePicker/DatePickerIOS.android.js index 585be6e297673d..c532f212d6080b 100644 --- a/Libraries/Components/DatePicker/DatePickerIOS.android.js +++ b/Libraries/Components/DatePicker/DatePickerIOS.android.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. diff --git a/Libraries/Components/DatePicker/DatePickerIOS.ios.js b/Libraries/Components/DatePicker/DatePickerIOS.ios.js index 1202364665fc94..0affc99de40653 100644 --- a/Libraries/Components/DatePicker/DatePickerIOS.ios.js +++ b/Libraries/Components/DatePicker/DatePickerIOS.ios.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. @@ -8,7 +8,7 @@ * This is a controlled component version of RCTDatePickerIOS * * @format - * @flow + * @flow strict-local */ 'use strict'; @@ -21,10 +21,15 @@ const View = require('View'); const requireNativeComponent = require('requireNativeComponent'); import type {ViewProps} from 'ViewPropTypes'; +import type {SyntheticEvent} from 'CoreEventTypes'; const RCTDatePickerIOS = requireNativeComponent('RCTDatePicker'); -type Event = Object; +type Event = SyntheticEvent< + $ReadOnly<{| + timestamp: number, + |}>, +>; type Props = $ReadOnly<{| ...ViewProps, @@ -143,6 +148,7 @@ class DatePickerIOS extends React.Component { return ( { this._picker = picker; }} @@ -154,7 +160,11 @@ class DatePickerIOS extends React.Component { ? props.initialDate.getTime() : undefined } - locale={props.locale ? props.locale : undefined} + locale={ + props.locale != null && props.locale !== '' + ? props.locale + : undefined + } maximumDate={ props.maximumDate ? props.maximumDate.getTime() : undefined } diff --git a/Libraries/Components/DatePickerAndroid/DatePickerAndroid.android.js b/Libraries/Components/DatePickerAndroid/DatePickerAndroid.android.js index bd91263a8f9b49..734a59abf72cf4 100644 --- a/Libraries/Components/DatePickerAndroid/DatePickerAndroid.android.js +++ b/Libraries/Components/DatePickerAndroid/DatePickerAndroid.android.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. diff --git a/Libraries/Components/DatePickerAndroid/DatePickerAndroid.ios.js b/Libraries/Components/DatePickerAndroid/DatePickerAndroid.ios.js index a158f035c303d3..bb6442b5262c79 100644 --- a/Libraries/Components/DatePickerAndroid/DatePickerAndroid.ios.js +++ b/Libraries/Components/DatePickerAndroid/DatePickerAndroid.ios.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. diff --git a/Libraries/Components/DrawerAndroid/DrawerLayoutAndroid.android.js b/Libraries/Components/DrawerAndroid/DrawerLayoutAndroid.android.js index d4b3fa9f7f63d0..e41c4e5cc4d979 100644 --- a/Libraries/Components/DrawerAndroid/DrawerLayoutAndroid.android.js +++ b/Libraries/Components/DrawerAndroid/DrawerLayoutAndroid.android.js @@ -1,37 +1,153 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. * + * @flow * @format */ 'use strict'; -const ColorPropType = require('ColorPropType'); -const NativeMethodsMixin = require('NativeMethodsMixin'); const Platform = require('Platform'); const React = require('React'); -const PropTypes = require('prop-types'); const ReactNative = require('ReactNative'); const StatusBar = require('StatusBar'); const StyleSheet = require('StyleSheet'); const UIManager = require('UIManager'); const View = require('View'); -const ViewPropTypes = require('ViewPropTypes'); +const nullthrows = require('nullthrows'); -const DrawerConsts = UIManager.AndroidDrawerLayout.Constants; +const DrawerConsts = UIManager.getViewManagerConfig('AndroidDrawerLayout') + .Constants; -const createReactClass = require('create-react-class'); const dismissKeyboard = require('dismissKeyboard'); const requireNativeComponent = require('requireNativeComponent'); -const RK_DRAWER_REF = 'drawerlayout'; -const INNERVIEW_REF = 'innerView'; - const DRAWER_STATES = ['Idle', 'Dragging', 'Settling']; +import type {ViewStyleProp} from 'StyleSheet'; +import type {ColorValue} from 'StyleSheetTypes'; +import type {SyntheticEvent} from 'CoreEventTypes'; +import type { + MeasureOnSuccessCallback, + MeasureInWindowOnSuccessCallback, + MeasureLayoutOnSuccessCallback, +} from 'ReactNativeTypes'; + +type DrawerStates = 'Idle' | 'Dragging' | 'Settling'; + +type DrawerStateEvent = SyntheticEvent< + $ReadOnly<{| + drawerState: number, + |}>, +>; + +type DrawerSlideEvent = SyntheticEvent< + $ReadOnly<{| + offset: number, + |}>, +>; + +type Props = $ReadOnly<{| + /** + * Determines whether the keyboard gets dismissed in response to a drag. + * - 'none' (the default), drags do not dismiss the keyboard. + * - 'on-drag', the keyboard is dismissed when a drag begins. + */ + keyboardDismissMode?: ?('none' | 'on-drag'), + + /** + * Specifies the background color of the drawer. The default value is white. + * If you want to set the opacity of the drawer, use rgba. Example: + * + * ``` + * return ( + * + * + * ); + * ``` + */ + drawerBackgroundColor: ColorValue, + + /** + * Specifies the side of the screen from which the drawer will slide in. + */ + drawerPosition: ?number, + + /** + * Specifies the width of the drawer, more precisely the width of the view that be pulled in + * from the edge of the window. + */ + drawerWidth?: ?number, + + /** + * Specifies the lock mode of the drawer. The drawer can be locked in 3 states: + * - unlocked (default), meaning that the drawer will respond (open/close) to touch gestures. + * - locked-closed, meaning that the drawer will stay closed and not respond to gestures. + * - locked-open, meaning that the drawer will stay opened and not respond to gestures. + * The drawer may still be opened and closed programmatically (`openDrawer`/`closeDrawer`). + */ + drawerLockMode?: ?('unlocked' | 'locked-closed' | 'locked-open'), + + /** + * Function called whenever there is an interaction with the navigation view. + */ + onDrawerSlide?: ?(event: DrawerSlideEvent) => mixed, + + /** + * Function called when the drawer state has changed. The drawer can be in 3 states: + * - Idle, meaning there is no interaction with the navigation view happening at the time + * - Dragging, meaning there is currently an interaction with the navigation view + * - Settling, meaning that there was an interaction with the navigation view, and the + * navigation view is now finishing its closing or opening animation + */ + onDrawerStateChanged?: ?(state: DrawerStates) => mixed, + + /** + * Function called whenever the navigation view has been opened. + */ + onDrawerOpen?: ?() => mixed, + + /** + * Function called whenever the navigation view has been closed. + */ + onDrawerClose?: ?() => mixed, + + /** + * The navigation view that will be rendered to the side of the screen and can be pulled in. + */ + renderNavigationView: () => React.Element, + + /** + * Make the drawer take the entire screen and draw the background of the + * status bar to allow it to open over the status bar. It will only have an + * effect on API 21+. + */ + statusBarBackgroundColor?: ?ColorValue, + + children?: React.Node, + style?: ?ViewStyleProp, +|}>; + +type NativeProps = $ReadOnly<{| + ...$Diff< + Props, + $ReadOnly<{onDrawerStateChanged?: ?(state: DrawerStates) => mixed}>, + >, + onDrawerStateChanged?: ?(state: DrawerStateEvent) => mixed, +|}>; + +type State = {| + statusBarBackgroundColor: ColorValue, +|}; + +// The View that contains both the actual drawer and the main view +const AndroidDrawerLayout = ((requireNativeComponent( + 'AndroidDrawerLayout', +): any): Class>); + /** * React component that wraps the platform `DrawerLayout` (Android only). The * Drawer (typically used for navigation) is rendered with `renderNavigationView` @@ -63,109 +179,20 @@ const DRAWER_STATES = ['Idle', 'Dragging', 'Settling']; * }, * ``` */ -const DrawerLayoutAndroid = createReactClass({ - displayName: 'DrawerLayoutAndroid', - statics: { - positions: DrawerConsts.DrawerPosition, - }, - - propTypes: { - ...ViewPropTypes, - /** - * Determines whether the keyboard gets dismissed in response to a drag. - * - 'none' (the default), drags do not dismiss the keyboard. - * - 'on-drag', the keyboard is dismissed when a drag begins. - */ - keyboardDismissMode: PropTypes.oneOf([ - 'none', // default - 'on-drag', - ]), - /** - * Specifies the background color of the drawer. The default value is white. - * If you want to set the opacity of the drawer, use rgba. Example: - * - * ``` - * return ( - * - * - * ); - * ``` - */ - drawerBackgroundColor: ColorPropType, - /** - * Specifies the side of the screen from which the drawer will slide in. - */ - drawerPosition: PropTypes.oneOf([ - DrawerConsts.DrawerPosition.Left, - DrawerConsts.DrawerPosition.Right, - ]), - /** - * Specifies the width of the drawer, more precisely the width of the view that be pulled in - * from the edge of the window. - */ - drawerWidth: PropTypes.number, - /** - * Specifies the lock mode of the drawer. The drawer can be locked in 3 states: - * - unlocked (default), meaning that the drawer will respond (open/close) to touch gestures. - * - locked-closed, meaning that the drawer will stay closed and not respond to gestures. - * - locked-open, meaning that the drawer will stay opened and not respond to gestures. - * The drawer may still be opened and closed programmatically (`openDrawer`/`closeDrawer`). - */ - drawerLockMode: PropTypes.oneOf([ - 'unlocked', - 'locked-closed', - 'locked-open', - ]), - /** - * Function called whenever there is an interaction with the navigation view. - */ - onDrawerSlide: PropTypes.func, - /** - * Function called when the drawer state has changed. The drawer can be in 3 states: - * - idle, meaning there is no interaction with the navigation view happening at the time - * - dragging, meaning there is currently an interaction with the navigation view - * - settling, meaning that there was an interaction with the navigation view, and the - * navigation view is now finishing its closing or opening animation - */ - onDrawerStateChanged: PropTypes.func, - /** - * Function called whenever the navigation view has been opened. - */ - onDrawerOpen: PropTypes.func, - /** - * Function called whenever the navigation view has been closed. - */ - onDrawerClose: PropTypes.func, - /** - * The navigation view that will be rendered to the side of the screen and can be pulled in. - */ - renderNavigationView: PropTypes.func.isRequired, - - /** - * Make the drawer take the entire screen and draw the background of the - * status bar to allow it to open over the status bar. It will only have an - * effect on API 21+. - */ - statusBarBackgroundColor: ColorPropType, - }, +class DrawerLayoutAndroid extends React.Component { + static positions = DrawerConsts.DrawerPosition; + static defaultProps = { + drawerBackgroundColor: 'white', + }; - mixins: [NativeMethodsMixin], + _nativeRef = React.createRef< + Class>, + >(); - getDefaultProps: function(): Object { - return { - drawerBackgroundColor: 'white', - }; - }, + state = {statusBarBackgroundColor: null}; - getInitialState: function() { - return {statusBarBackgroundColor: undefined}; - }, - - getInnerViewNode: function() { - return this.refs[INNERVIEW_REF].getInnerViewNode(); - }, - - render: function() { + render() { + const {onDrawerStateChanged, ...props} = this.props; const drawStatusBar = Platform.Version >= 21 && this.props.statusBarBackgroundColor; const drawerViewWrapper = ( @@ -183,7 +210,7 @@ const DrawerLayoutAndroid = createReactClass({ ); const childrenWrapper = ( - + {drawStatusBar && ( ); - }, + } - _onDrawerSlide: function(event) { + _onDrawerSlide = (event: DrawerSlideEvent) => { if (this.props.onDrawerSlide) { this.props.onDrawerSlide(event); } if (this.props.keyboardDismissMode === 'on-drag') { dismissKeyboard(); } - }, + }; - _onDrawerOpen: function() { + _onDrawerOpen = () => { if (this.props.onDrawerOpen) { this.props.onDrawerOpen(); } - }, + }; - _onDrawerClose: function() { + _onDrawerClose = () => { if (this.props.onDrawerClose) { this.props.onDrawerClose(); } - }, + }; - _onDrawerStateChanged: function(event) { + _onDrawerStateChanged = (event: DrawerStateEvent) => { if (this.props.onDrawerStateChanged) { this.props.onDrawerStateChanged( DRAWER_STATES[event.nativeEvent.drawerState], ); } - }, + }; /** * Opens the drawer. */ - openDrawer: function() { + openDrawer() { UIManager.dispatchViewManagerCommand( this._getDrawerLayoutHandle(), - UIManager.AndroidDrawerLayout.Commands.openDrawer, + UIManager.getViewManagerConfig('AndroidDrawerLayout').Commands.openDrawer, null, ); - }, + } /** * Closes the drawer. */ - closeDrawer: function() { + closeDrawer() { UIManager.dispatchViewManagerCommand( this._getDrawerLayoutHandle(), - UIManager.AndroidDrawerLayout.Commands.closeDrawer, + UIManager.getViewManagerConfig('AndroidDrawerLayout').Commands + .closeDrawer, null, ); - }, + } + /** * Closing and opening example * Note: To access the drawer you have to give it a ref. Refs do not work on stateless components @@ -285,10 +314,45 @@ const DrawerLayoutAndroid = createReactClass({ * ) * } */ - _getDrawerLayoutHandle: function() { - return ReactNative.findNodeHandle(this.refs[RK_DRAWER_REF]); - }, -}); + _getDrawerLayoutHandle() { + return ReactNative.findNodeHandle(this._nativeRef.current); + } + + /** + * Native methods + */ + blur() { + nullthrows(this._nativeRef.current).blur(); + } + + focus() { + nullthrows(this._nativeRef.current).focus(); + } + + measure(callback: MeasureOnSuccessCallback) { + nullthrows(this._nativeRef.current).measure(callback); + } + + measureInWindow(callback: MeasureInWindowOnSuccessCallback) { + nullthrows(this._nativeRef.current).measureInWindow(callback); + } + + measureLayout( + relativeToNativeNode: number, + onSuccess: MeasureLayoutOnSuccessCallback, + onFail?: () => void, + ) { + nullthrows(this._nativeRef.current).measureLayout( + relativeToNativeNode, + onSuccess, + onFail, + ); + } + + setNativeProps(nativeProps: Object) { + nullthrows(this._nativeRef.current).setNativeProps(nativeProps); + } +} const styles = StyleSheet.create({ base: { @@ -320,7 +384,4 @@ const styles = StyleSheet.create({ }, }); -// The View that contains both the actual drawer and the main view -const AndroidDrawerLayout = requireNativeComponent('AndroidDrawerLayout'); - module.exports = DrawerLayoutAndroid; diff --git a/Libraries/Components/DrawerAndroid/DrawerLayoutAndroid.ios.js b/Libraries/Components/DrawerAndroid/DrawerLayoutAndroid.ios.js index 260d559929796f..7a00b6636cf664 100644 --- a/Libraries/Components/DrawerAndroid/DrawerLayoutAndroid.ios.js +++ b/Libraries/Components/DrawerAndroid/DrawerLayoutAndroid.ios.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. diff --git a/Libraries/Components/Keyboard/Keyboard.js b/Libraries/Components/Keyboard/Keyboard.js index feeb4a4ec2ce70..c95ed6586e98bf 100644 --- a/Libraries/Components/Keyboard/Keyboard.js +++ b/Libraries/Components/Keyboard/Keyboard.js @@ -1,11 +1,11 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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 + * @flow strict-local */ 'use strict'; @@ -121,7 +121,10 @@ let Keyboard = { * @param {string} eventName The `nativeEvent` is the string that identifies the event you're listening for. * @param {function} callback function to be called when the event fires. */ - removeListener(eventName: KeyboardEventName, callback: Function) { + removeListener( + eventName: KeyboardEventName, + callback: KeyboardEventListener, + ) { invariant(false, 'Dummy method used for documentation'); }, @@ -155,12 +158,12 @@ Keyboard = KeyboardEventEmitter; Keyboard.dismiss = dismissKeyboard; Keyboard.scheduleLayoutAnimation = function(event: KeyboardEvent) { const {duration, easing} = event; - if (duration) { + if (duration != null && duration !== 0) { LayoutAnimation.configureNext({ duration: duration, update: { duration: duration, - type: (easing && LayoutAnimation.Types[easing]) || 'keyboard', + type: (easing != null && LayoutAnimation.Types[easing]) || 'keyboard', }, }); } diff --git a/Libraries/Components/Keyboard/KeyboardAvoidingView.js b/Libraries/Components/Keyboard/KeyboardAvoidingView.js index 4973fd4a0a3805..f8c620d9a495ae 100644 --- a/Libraries/Components/Keyboard/KeyboardAvoidingView.js +++ b/Libraries/Components/Keyboard/KeyboardAvoidingView.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. @@ -150,7 +150,7 @@ class KeyboardAvoidingView extends React.Component { children, contentContainerStyle, enabled, - keyboardVerticalOffset, // eslint-disable-line no-unused-vars + keyboardVerticalOffset, style, ...props } = this.props; diff --git a/Libraries/Components/MaskedView/MaskedViewIOS.android.js b/Libraries/Components/MaskedView/MaskedViewIOS.android.js index 49d44e1541dcd5..95d93f156b29cd 100644 --- a/Libraries/Components/MaskedView/MaskedViewIOS.android.js +++ b/Libraries/Components/MaskedView/MaskedViewIOS.android.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. diff --git a/Libraries/Components/MaskedView/MaskedViewIOS.ios.js b/Libraries/Components/MaskedView/MaskedViewIOS.ios.js index c65822a64b2d30..ce860ac2eeab40 100644 --- a/Libraries/Components/MaskedView/MaskedViewIOS.ios.js +++ b/Libraries/Components/MaskedView/MaskedViewIOS.ios.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. @@ -8,27 +8,26 @@ * @flow */ -const PropTypes = require('prop-types'); const React = require('React'); const StyleSheet = require('StyleSheet'); const View = require('View'); -const ViewPropTypes = require('ViewPropTypes'); + const requireNativeComponent = require('requireNativeComponent'); import type {ViewProps} from 'ViewPropTypes'; const RCTMaskedView = requireNativeComponent('RCTMaskedView'); -type Props = { +type Props = $ReadOnly<{| ...ViewProps, - children: any, + children: React.Node, /** * Should be a React element to be rendered and applied as the * mask for the child element. */ maskElement: React.Element, -}; +|}>; /** * Renders the child view with a mask specified in the `maskElement` prop. @@ -67,11 +66,6 @@ type Props = { * */ class MaskedViewIOS extends React.Component { - static propTypes = { - ...ViewPropTypes, - maskElement: PropTypes.element.isRequired, - }; - _hasWarnedInvalidRenderMask = false; render() { diff --git a/Libraries/Components/Navigation/NavigatorIOS.android.js b/Libraries/Components/Navigation/NavigatorIOS.android.js deleted file mode 100644 index 260d559929796f..00000000000000 --- a/Libraries/Components/Navigation/NavigatorIOS.android.js +++ /dev/null @@ -1,12 +0,0 @@ -/** - * Copyright (c) 2015-present, Facebook, Inc. - * - * 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'; - -module.exports = require('UnimplementedView'); diff --git a/Libraries/Components/Navigation/NavigatorIOS.ios.js b/Libraries/Components/Navigation/NavigatorIOS.ios.js deleted file mode 100644 index 8f28d79147fe77..00000000000000 --- a/Libraries/Components/Navigation/NavigatorIOS.ios.js +++ /dev/null @@ -1,932 +0,0 @@ -/** - * Copyright (c) 2015-present, Facebook, Inc. - * - * 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 EventEmitter = require('EventEmitter'); -const Image = require('Image'); -const RCTNavigatorManager = require('NativeModules').NavigatorManager; -const React = require('React'); -const PropTypes = require('prop-types'); -const ReactNative = require('ReactNative'); -const StaticContainer = require('StaticContainer.react'); -const StyleSheet = require('StyleSheet'); -const TVEventHandler = require('TVEventHandler'); -const View = require('View'); -const ViewPropTypes = require('ViewPropTypes'); - -const createReactClass = require('create-react-class'); -const invariant = require('fbjs/lib/invariant'); -const requireNativeComponent = require('requireNativeComponent'); - -/* $FlowFixMe(>=0.54.0 site=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. */ -const keyMirror = require('fbjs/lib/keyMirror'); - -const TRANSITIONER_REF = 'transitionerRef'; - -let __uid = 0; -function getuid() { - return __uid++; -} - -class NavigatorTransitionerIOS extends React.Component<$FlowFixMeProps> { - requestSchedulingNavigation(cb) { - RCTNavigatorManager.requestSchedulingJavaScriptNavigation( - ReactNative.findNodeHandle(this), - cb, - ); - } - - render() { - return ; - } -} - -const SystemIconLabels = { - done: true, - cancel: true, - edit: true, - save: true, - add: true, - compose: true, - reply: true, - action: true, - organize: true, - bookmarks: true, - search: true, - refresh: true, - stop: true, - camera: true, - trash: true, - play: true, - pause: true, - rewind: true, - 'fast-forward': true, - undo: true, - redo: true, - 'page-curl': true, -}; -const SystemIcons = keyMirror(SystemIconLabels); - -type SystemButtonType = $Enum; - -type Route = { - component: Function, - title: string, - titleImage?: Object, - passProps?: Object, - backButtonTitle?: string, - backButtonIcon?: Object, - leftButtonTitle?: string, - leftButtonIcon?: Object, - leftButtonSystemIcon?: SystemButtonType, - onLeftButtonPress?: Function, - rightButtonTitle?: string, - rightButtonIcon?: Object, - rightButtonSystemIcon?: SystemButtonType, - onRightButtonPress?: Function, - wrapperStyle?: any, -}; - -type State = { - idStack: Array, - routeStack: Array, - requestedTopOfStack: number, - observedTopOfStack: number, - progress: number, - fromIndex: number, - toIndex: number, - makingNavigatorRequest: boolean, - updatingAllIndicesAtOrBeyond: ?number, -}; - -type Event = Object; - -/** - * Think of `` as simply a component that renders an - * `RCTNavigator`, and moves the `RCTNavigator`'s `requestedTopOfStack` pointer - * forward and backward. The `RCTNavigator` interprets changes in - * `requestedTopOfStack` to be pushes and pops of children that are rendered. - * `` always ensures that whenever the `requestedTopOfStack` - * pointer is moved, that we've also rendered enough children so that the - * `RCTNavigator` can carry out the push/pop with those children. - * `` also removes children that will no longer be needed - * (after the pop of a child has been fully completed/animated out). - */ - -/** - * `NavigatorIOS` is a wrapper around - * [`UINavigationController`](https://developer.apple.com/library/ios/documentation/UIKit/Reference/UINavigationController_Class/), - * enabling you to implement a navigation stack. It works exactly the same as it - * would on a native app using `UINavigationController`, providing the same - * animations and behavior from UIKit. - * - * As the name implies, it is only available on iOS. Take a look at - * [`React Navigation`](https://reactnavigation.org/) for a cross-platform - * solution in JavaScript, or check out either of these components for native - * solutions: [native-navigation](http://airbnb.io/native-navigation/), - * [react-native-navigation](https://github.com/wix/react-native-navigation). - * - * To set up the navigator, provide the `initialRoute` prop with a route - * object. A route object is used to describe each scene that your app - * navigates to. `initialRoute` represents the first route in your navigator. - * - * ``` - * import PropTypes from 'prop-types'; - * import React, { Component } from 'react'; - * import { NavigatorIOS, Text } from 'react-native'; - * - * export default class NavigatorIOSApp extends Component { - * render() { - * return ( - * - * ); - * } - * } - * - * class MyScene extends Component { - * static propTypes = { - * title: PropTypes.string.isRequired, - * navigator: PropTypes.object.isRequired, - * } - * - * _onForward = () => { - * this.props.navigator.push({ - * title: 'Scene ' + nextIndex, - * }); - * } - * - * render() { - * return ( - * - * Current Scene: { this.props.title } - * - * Tap me to load the next scene - * - * - * ) - * } - * } - * ``` - * - * In this code, the navigator renders the component specified in initialRoute, - * which in this case is `MyScene`. This component will receive a `route` prop - * and a `navigator` prop representing the navigator. The navigator's navigation - * bar will render the title for the current scene, "My Initial Scene". - * - * You can optionally pass in a `passProps` property to your `initialRoute`. - * `NavigatorIOS` passes this in as props to the rendered component: - * - * ``` - * initialRoute={{ - * component: MyScene, - * title: 'My Initial Scene', - * passProps: { myProp: 'foo' } - * }} - * ``` - * - * You can then access the props passed in via `{this.props.myProp}`. - * - * #### Handling Navigation - * - * To trigger navigation functionality such as pushing or popping a view, you - * have access to a `navigator` object. The object is passed in as a prop to any - * component that is rendered by `NavigatorIOS`. You can then call the - * relevant methods to perform the navigation action you need: - * - * ``` - * class MyView extends Component { - * _handleBackPress() { - * this.props.navigator.pop(); - * } - * - * _handleNextPress(nextRoute) { - * this.props.navigator.push(nextRoute); - * } - * - * render() { - * const nextRoute = { - * component: MyView, - * title: 'Bar That', - * passProps: { myProp: 'bar' } - * }; - * return( - * this._handleNextPress(nextRoute)}> - * - * See you on the other nav {this.props.myProp}! - * - * - * ); - * } - * } - * ``` - * - * You can also trigger navigator functionality from the `NavigatorIOS` - * component: - * - * ``` - * class NavvyIOS extends Component { - * _handleNavigationRequest() { - * this.refs.nav.push({ - * component: MyView, - * title: 'Genius', - * passProps: { myProp: 'genius' }, - * }); - * } - * - * render() { - * return ( - * this._handleNavigationRequest(), - * }} - * style={{flex: 1}} - * /> - * ); - * } - * } - * ``` - * - * The code above adds a `_handleNavigationRequest` private method that is - * invoked from the `NavigatorIOS` component when the right navigation bar item - * is pressed. To get access to the navigator functionality, a reference to it - * is saved in the `ref` prop and later referenced to push a new scene into the - * navigation stack. - * - * #### Navigation Bar Configuration - * - * Props passed to `NavigatorIOS` will set the default configuration - * for the navigation bar. Props passed as properties to a route object will set - * the configuration for that route's navigation bar, overriding any props - * passed to the `NavigatorIOS` component. - * - * ``` - * _handleNavigationRequest() { - * this.refs.nav.push({ - * //... - * passProps: { myProp: 'genius' }, - * barTintColor: '#996699', - * }); - * } - * - * render() { - * return ( - * - * ); - * } - * ``` - * - * In the example above the navigation bar color is changed when the new route - * is pushed. - * - */ -const NavigatorIOS = createReactClass({ - displayName: 'NavigatorIOS', - - propTypes: { - /** - * NavigatorIOS uses `route` objects to identify child views, their props, - * and navigation bar configuration. Navigation operations such as push - * operations expect routes to look like this the `initialRoute`. - */ - initialRoute: PropTypes.shape({ - /** - * The React Class to render for this route - */ - component: PropTypes.func.isRequired, - - /** - * The title displayed in the navigation bar and the back button for this - * route. - */ - title: PropTypes.string.isRequired, - - /** - * If set, a title image will appear instead of the text title. - */ - titleImage: Image.propTypes.source, - - /** - * Use this to specify additional props to pass to the rendered - * component. `NavigatorIOS` will automatically pass in `route` and - * `navigator` props to the component. - */ - passProps: PropTypes.object, - - /** - * If set, the left navigation button image will be displayed using this - * source. Note that this doesn't apply to the header of the current - * view, but to those views that are subsequently pushed. - */ - backButtonIcon: Image.propTypes.source, - - /** - * If set, the left navigation button text will be set to this. Note that - * this doesn't apply to the left button of the current view, but to - * those views that are subsequently pushed - */ - backButtonTitle: PropTypes.string, - - /** - * If set, the left navigation button image will be displayed using - * this source. - */ - leftButtonIcon: Image.propTypes.source, - - /** - * If set, the left navigation button will display this text. - */ - leftButtonTitle: PropTypes.string, - - /** - * If set, the left header button will appear with this system icon - * - * Supported icons are `done`, `cancel`, `edit`, `save`, `add`, - * `compose`, `reply`, `action`, `organize`, `bookmarks`, `search`, - * `refresh`, `stop`, `camera`, `trash`, `play`, `pause`, `rewind`, - * `fast-forward`, `undo`, `redo`, and `page-curl` - */ - leftButtonSystemIcon: PropTypes.oneOf(Object.keys(SystemIcons)), - - /** - * This function will be invoked when the left navigation bar item is - * pressed. - */ - onLeftButtonPress: PropTypes.func, - - /** - * If set, the right navigation button image will be displayed using - * this source. - */ - rightButtonIcon: Image.propTypes.source, - - /** - * If set, the right navigation button will display this text. - */ - rightButtonTitle: PropTypes.string, - - /** - * If set, the right header button will appear with this system icon - * - * See leftButtonSystemIcon for supported icons - */ - rightButtonSystemIcon: PropTypes.oneOf(Object.keys(SystemIcons)), - - /** - * This function will be invoked when the right navigation bar item is - * pressed. - */ - onRightButtonPress: PropTypes.func, - - /** - * Styles for the navigation item containing the component. - */ - wrapperStyle: ViewPropTypes.style, - - /** - * Boolean value that indicates whether the navigation bar is hidden. - */ - navigationBarHidden: PropTypes.bool, - - /** - * Boolean value that indicates whether to hide the 1px hairline - * shadow. - */ - shadowHidden: PropTypes.bool, - - /** - * The color used for the buttons in the navigation bar. - */ - tintColor: PropTypes.string, - - /** - * The background color of the navigation bar. - */ - barTintColor: PropTypes.string, - - /** - * The style of the navigation bar. Supported values are 'default', 'black'. - * Use 'black' instead of setting `barTintColor` to black. This produces - * a navigation bar with the native iOS style with higher translucency. - */ - barStyle: PropTypes.oneOf(['default', 'black']), - - /** - * The text color of the navigation bar title. - */ - titleTextColor: PropTypes.string, - - /** - * Boolean value that indicates whether the navigation bar is - * translucent. - */ - translucent: PropTypes.bool, - }).isRequired, - - /** - * Boolean value that indicates whether the navigation bar is hidden - * by default. - */ - navigationBarHidden: PropTypes.bool, - - /** - * Boolean value that indicates whether to hide the 1px hairline shadow - * by default. - */ - shadowHidden: PropTypes.bool, - - /** - * The default wrapper style for components in the navigator. - * A common use case is to set the `backgroundColor` for every scene. - */ - itemWrapperStyle: ViewPropTypes.style, - - /** - * The default color used for the buttons in the navigation bar. - */ - tintColor: PropTypes.string, - - /** - * The default background color of the navigation bar. - */ - barTintColor: PropTypes.string, - - /** - * The style of the navigation bar. Supported values are 'default', 'black'. - * Use 'black' instead of setting `barTintColor` to black. This produces - * a navigation bar with the native iOS style with higher translucency. - */ - barStyle: PropTypes.oneOf(['default', 'black']), - - /** - * The default text color of the navigation bar title. - */ - titleTextColor: PropTypes.string, - - /** - * Boolean value that indicates whether the navigation bar is - * translucent by default - */ - translucent: PropTypes.bool, - - /** - * Boolean value that indicates whether the interactive pop gesture is - * enabled. This is useful for enabling/disabling the back swipe navigation - * gesture. - * - * If this prop is not provided, the default behavior is for the back swipe - * gesture to be enabled when the navigation bar is shown and disabled when - * the navigation bar is hidden. Once you've provided the - * `interactivePopGestureEnabled` prop, you can never restore the default - * behavior. - */ - interactivePopGestureEnabled: PropTypes.bool, - }, - - navigator: (undefined: ?Object), - - UNSAFE_componentWillMount: function() { - // Precompute a pack of callbacks that's frequently generated and passed to - // instances. - this.navigator = { - push: this.push, - pop: this.pop, - popN: this.popN, - replace: this.replace, - replaceAtIndex: this.replaceAtIndex, - replacePrevious: this.replacePrevious, - replacePreviousAndPop: this.replacePreviousAndPop, - resetTo: this.resetTo, - popToRoute: this.popToRoute, - popToTop: this.popToTop, - }; - }, - - componentDidMount: function() { - this._enableTVEventHandler(); - }, - - componentWillUnmount: function() { - this._disableTVEventHandler(); - }, - - getDefaultProps: function(): Object { - return { - translucent: true, - }; - }, - - getInitialState: function(): State { - return { - idStack: [getuid()], - routeStack: [this.props.initialRoute], - // The navigation index that we wish to push/pop to. - requestedTopOfStack: 0, - // The last index that native has sent confirmation of completed push/pop - // for. At this point, we can discard any views that are beyond the - // `requestedTopOfStack`. A value of `null` means we have not received - // any confirmation, ever. We may receive an `observedTopOfStack` without - // ever requesting it - native can instigate pops of its own with the - // backswipe gesture. - observedTopOfStack: 0, - progress: 1, - fromIndex: 0, - toIndex: 0, - // Whether or not we are making a navigator request to push/pop. (Used - // for performance optimization). - makingNavigatorRequest: false, - // Whether or not we are updating children of navigator and if so (not - // `null`) which index marks the beginning of all updates. Used for - // performance optimization. - updatingAllIndicesAtOrBeyond: 0, - }; - }, - - _toFocusOnNavigationComplete: (undefined: any), - - _handleFocusRequest: function(item: any) { - if (this.state.makingNavigatorRequest) { - this._toFocusOnNavigationComplete = item; - } else { - this._getFocusEmitter().emit('focus', item); - } - }, - - _focusEmitter: (undefined: ?EventEmitter), - - _getFocusEmitter: function(): EventEmitter { - // Flow not yet tracking assignments to instance fields. - let focusEmitter = this._focusEmitter; - if (!focusEmitter) { - focusEmitter = new EventEmitter(); - this._focusEmitter = focusEmitter; - } - return focusEmitter; - }, - - getChildContext: function(): { - onFocusRequested: Function, - focusEmitter: EventEmitter, - } { - return { - onFocusRequested: this._handleFocusRequest, - focusEmitter: this._getFocusEmitter(), - }; - }, - - childContextTypes: { - onFocusRequested: PropTypes.func, - focusEmitter: PropTypes.instanceOf(EventEmitter), - }, - - _tryLockNavigator: function(cb: () => void) { - this.refs[TRANSITIONER_REF].requestSchedulingNavigation( - acquiredLock => acquiredLock && cb(), - ); - }, - - _handleNavigatorStackChanged: function(e: Event) { - const newObservedTopOfStack = e.nativeEvent.stackLength - 1; - - invariant( - newObservedTopOfStack <= this.state.requestedTopOfStack, - 'No navigator item should be pushed without JS knowing about it %s %s', - newObservedTopOfStack, - this.state.requestedTopOfStack, - ); - const wasWaitingForConfirmation = - this.state.requestedTopOfStack !== this.state.observedTopOfStack; - if (wasWaitingForConfirmation) { - invariant( - newObservedTopOfStack === this.state.requestedTopOfStack, - 'If waiting for observedTopOfStack to reach requestedTopOfStack, ' + - 'the only valid observedTopOfStack should be requestedTopOfStack.', - ); - } - // Mark the most recent observation regardless of if we can lock the - // navigator. `observedTopOfStack` merely represents what we've observed - // and this first `setState` is only executed to update debugging - // overlays/navigation bar. - // Also reset progress, toIndex, and fromIndex as they might not end - // in the correct states for a two possible reasons: - // Progress isn't always 0 or 1 at the end, the system rounds - // If the Navigator is offscreen these values won't be updated - // TOOD: Revisit this decision when no longer relying on native navigator. - const nextState = { - observedTopOfStack: newObservedTopOfStack, - makingNavigatorRequest: false, - updatingAllIndicesAtOrBeyond: null, - progress: 1, - toIndex: newObservedTopOfStack, - fromIndex: newObservedTopOfStack, - }; - this.setState(nextState, this._eliminateUnneededChildren); - }, - - _eliminateUnneededChildren: function() { - // Updating the indices that we're deleting and that's all. (Truth: Nothing - // even uses the indices in this case, but let's make this describe the - // truth anyways). - const updatingAllIndicesAtOrBeyond = - this.state.routeStack.length > this.state.observedTopOfStack + 1 - ? this.state.observedTopOfStack + 1 - : null; - this.setState({ - idStack: this.state.idStack.slice(0, this.state.observedTopOfStack + 1), - routeStack: this.state.routeStack.slice( - 0, - this.state.observedTopOfStack + 1, - ), - // Now we rerequest the top of stack that we observed. - requestedTopOfStack: this.state.observedTopOfStack, - makingNavigatorRequest: true, - updatingAllIndicesAtOrBeyond: updatingAllIndicesAtOrBeyond, - }); - }, - - /** - * Navigate forward to a new route. - * @param route The new route to navigate to. - */ - push: function(route: Route) { - invariant(!!route, 'Must supply route to push'); - // Make sure all previous requests are caught up first. Otherwise reject. - if (this.state.requestedTopOfStack === this.state.observedTopOfStack) { - this._tryLockNavigator(() => { - const nextStack = this.state.routeStack.concat([route]); - const nextIDStack = this.state.idStack.concat([getuid()]); - this.setState({ - // We have to make sure that we've also supplied enough views to - // satisfy our request to adjust the `requestedTopOfStack`. - idStack: nextIDStack, - routeStack: nextStack, - requestedTopOfStack: nextStack.length - 1, - makingNavigatorRequest: true, - updatingAllIndicesAtOrBeyond: nextStack.length - 1, - }); - }); - } - }, - - /** - * Go back N scenes at once. When N=1, behavior matches `pop()`. - * @param n The number of scenes to pop. - */ - popN: function(n: number) { - if (n === 0) { - return; - } - // Make sure all previous requests are caught up first. Otherwise reject. - if (this.state.requestedTopOfStack === this.state.observedTopOfStack) { - if (this.state.requestedTopOfStack > 0) { - this._tryLockNavigator(() => { - const newRequestedTopOfStack = this.state.requestedTopOfStack - n; - invariant(newRequestedTopOfStack >= 0, 'Cannot pop below 0'); - this.setState({ - requestedTopOfStack: newRequestedTopOfStack, - makingNavigatorRequest: true, - updatingAllIndicesAtOrBeyond: this.state.requestedTopOfStack - n, - }); - }); - } - } - }, - - /** - * Pop back to the previous scene. - */ - pop: function() { - this.popN(1); - }, - - /** - * Replace a route in the navigation stack. - * - * @param route The new route that will replace the specified one. - * @param index The route into the stack that should be replaced. - * If it is negative, it counts from the back of the stack. - */ - replaceAtIndex: function(route: Route, index: number) { - invariant(!!route, 'Must supply route to replace'); - if (index < 0) { - index += this.state.routeStack.length; - } - - if (this.state.routeStack.length <= index) { - return; - } - - // I don't believe we need to lock for a replace since there's no - // navigation actually happening - const nextIDStack = this.state.idStack.slice(); - const nextRouteStack = this.state.routeStack.slice(); - nextIDStack[index] = getuid(); - nextRouteStack[index] = route; - - this.setState({ - idStack: nextIDStack, - routeStack: nextRouteStack, - makingNavigatorRequest: false, - updatingAllIndicesAtOrBeyond: index, - }); - }, - - /** - * Replace the route for the current scene and immediately - * load the view for the new route. - * @param route The new route to navigate to. - */ - replace: function(route: Route) { - this.replaceAtIndex(route, -1); - }, - - /** - * Replace the route/view for the previous scene. - * @param route The new route to will replace the previous scene. - */ - replacePrevious: function(route: Route) { - this.replaceAtIndex(route, -2); - }, - - /** - * Go back to the topmost item in the navigation stack. - */ - popToTop: function() { - this.popToRoute(this.state.routeStack[0]); - }, - - /** - * Go back to the item for a particular route object. - * @param route The new route to navigate to. - */ - popToRoute: function(route: Route) { - const indexOfRoute = this.state.routeStack.indexOf(route); - invariant( - indexOfRoute !== -1, - "Calling pop to route for a route that doesn't exist!", - ); - const numToPop = this.state.routeStack.length - indexOfRoute - 1; - this.popN(numToPop); - }, - - /** - * Replaces the previous route/view and transitions back to it. - * @param route The new route that replaces the previous scene. - */ - replacePreviousAndPop: function(route: Route) { - // Make sure all previous requests are caught up first. Otherwise reject. - if (this.state.requestedTopOfStack !== this.state.observedTopOfStack) { - return; - } - if (this.state.routeStack.length < 2) { - return; - } - this._tryLockNavigator(() => { - this.replacePrevious(route); - this.setState({ - requestedTopOfStack: this.state.requestedTopOfStack - 1, - makingNavigatorRequest: true, - }); - }); - }, - - /** - * Replaces the top item and pop to it. - * @param route The new route that will replace the topmost item. - */ - resetTo: function(route: Route) { - invariant(!!route, 'Must supply route to push'); - // Make sure all previous requests are caught up first. Otherwise reject. - if (this.state.requestedTopOfStack !== this.state.observedTopOfStack) { - return; - } - this.replaceAtIndex(route, 0); - this.popToRoute(route); - }, - - _handleNavigationComplete: function(e: Event) { - // Don't propagate to other NavigatorIOS instances this is nested in: - e.stopPropagation(); - - if (this._toFocusOnNavigationComplete) { - this._getFocusEmitter().emit('focus', this._toFocusOnNavigationComplete); - this._toFocusOnNavigationComplete = null; - } - this._handleNavigatorStackChanged(e); - }, - - _routeToStackItem: function(routeArg: Route, i: number) { - const {component, wrapperStyle, passProps, ...route} = routeArg; - const {itemWrapperStyle, ...props} = this.props; - const shouldUpdateChild = - this.state.updatingAllIndicesAtOrBeyond != null && - this.state.updatingAllIndicesAtOrBeyond >= i; - const Component = component; - return ( - - - - - - ); - }, - - _renderNavigationStackItems: function() { - const shouldRecurseToNavigator = - this.state.makingNavigatorRequest || - this.state.updatingAllIndicesAtOrBeyond !== null; - // If not recursing update to navigator at all, may as well avoid - // computation of navigator children. - const items = shouldRecurseToNavigator - ? this.state.routeStack.map(this._routeToStackItem) - : null; - return ( - - =0.41.0) - vertical={this.props.vertical} - requestedTopOfStack={this.state.requestedTopOfStack} - onNavigationComplete={this._handleNavigationComplete} - interactivePopGestureEnabled={ - this.props.interactivePopGestureEnabled - }> - {items} - - - ); - }, - - _tvEventHandler: (undefined: ?TVEventHandler), - - _enableTVEventHandler: function() { - this._tvEventHandler = new TVEventHandler(); - this._tvEventHandler.enable(this, function(cmp, evt) { - if (evt && evt.eventType === 'menu') { - cmp.pop(); - } - }); - }, - - _disableTVEventHandler: function() { - if (this._tvEventHandler) { - this._tvEventHandler.disable(); - delete this._tvEventHandler; - } - }, - - render: function() { - return ( - // $FlowFixMe(>=0.41.0) - {this._renderNavigationStackItems()} - ); - }, -}); - -const styles = StyleSheet.create({ - stackItem: { - backgroundColor: 'white', - overflow: 'hidden', - position: 'absolute', - top: 0, - left: 0, - right: 0, - bottom: 0, - }, - transitioner: { - flex: 1, - }, -}); - -const RCTNavigator = requireNativeComponent('RCTNavigator'); -const RCTNavigatorItem = requireNativeComponent('RCTNavItem'); - -module.exports = NavigatorIOS; diff --git a/Libraries/Components/Picker/Picker.js b/Libraries/Components/Picker/Picker.js index 7518793c0c8c19..6dd532d7e625e3 100644 --- a/Libraries/Components/Picker/Picker.js +++ b/Libraries/Components/Picker/Picker.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. @@ -10,64 +10,103 @@ 'use strict'; -const ColorPropType = require('ColorPropType'); -const PickerIOS = require('PickerIOS'); const PickerAndroid = require('PickerAndroid'); +const PickerIOS = require('PickerIOS'); const Platform = require('Platform'); const React = require('React'); -const PropTypes = require('prop-types'); -const StyleSheetPropType = require('StyleSheetPropType'); -const TextStylePropTypes = require('TextStylePropTypes'); const UnimplementedView = require('UnimplementedView'); -const ViewPropTypes = require('ViewPropTypes'); -const ViewStylePropTypes = require('ViewStylePropTypes'); - -const itemStylePropType = StyleSheetPropType(TextStylePropTypes); -const pickerStyleType = StyleSheetPropType({ - ...ViewStylePropTypes, - color: ColorPropType, -}); +import type {TextStyleProp} from 'StyleSheet'; +import type {ColorValue} from 'StyleSheetTypes'; const MODE_DIALOG = 'dialog'; const MODE_DROPDOWN = 'dropdown'; -/** - * Individual selectable item in a Picker. - */ -class PickerItem extends React.Component<{ +type PickerItemProps = $ReadOnly<{| + /** + * Text to display for this item. + */ label: string, + + /** + * The value to be passed to picker's `onValueChange` callback when + * this item is selected. Can be a string or an integer. + */ value?: any, - color?: ColorPropType, + + /** + * Color of this item's text. + * @platform android + */ + color?: ColorValue, + + /** + * Used to locate the item in end-to-end tests. + */ testID?: string, -}> { - static propTypes = { - /** - * Text to display for this item. - */ - label: PropTypes.string.isRequired, - /** - * The value to be passed to picker's `onValueChange` callback when - * this item is selected. Can be a string or an integer. - */ - value: PropTypes.any, - /** - * Color of this item's text. - * @platform android - */ - color: ColorPropType, - /** - * Used to locate the item in end-to-end tests. - */ - testID: PropTypes.string, - }; +|}>; +/** + * Individual selectable item in a Picker. + */ +class PickerItem extends React.Component { render() { // The items are not rendered directly throw null; } } +type PickerProps = $ReadOnly<{| + children?: React.Node, + style?: ?TextStyleProp, + + /** + * Value matching value of one of the items. Can be a string or an integer. + */ + selectedValue?: any, + + /** + * Callback for when an item is selected. This is called with the following parameters: + * - `itemValue`: the `value` prop of the item that was selected + * - `itemPosition`: the index of the selected item in this picker + */ + onValueChange?: ?(newValue: any, newIndex: number) => mixed, + + /** + * If set to false, the picker will be disabled, i.e. the user will not be able to make a + * selection. + * @platform android + */ + enabled?: ?boolean, + + /** + * On Android, specifies how to display the selection items when the user taps on the picker: + * + * - 'dialog': Show a modal dialog. This is the default. + * - 'dropdown': Shows a dropdown anchored to the picker view + * + * @platform android + */ + mode?: ?('dialog' | 'dropdown'), + + /** + * Style to apply to each of the item labels. + * @platform ios + */ + itemStyle?: ?TextStyleProp, + + /** + * Prompt string for this picker, used on Android in dialog mode as the title of the dialog. + * @platform android + */ + prompt?: ?string, + + /** + * Used to locate this view in end-to-end tests. + */ + testID?: ?string, +|}>; + /** * Renders the native picker component on iOS and Android. Example: * @@ -78,16 +117,7 @@ class PickerItem extends React.Component<{ * * */ -class Picker extends React.Component<{ - style?: $FlowFixMe, - selectedValue?: any, - onValueChange?: Function, - enabled?: boolean, - mode?: 'dialog' | 'dropdown', - itemStyle?: $FlowFixMe, - prompt?: string, - testID?: string, -}> { +class Picker extends React.Component { /** * On Android, display the options in a dialog. */ @@ -104,61 +134,18 @@ class Picker extends React.Component<{ mode: MODE_DIALOG, }; - // $FlowFixMe(>=0.41.0) - static propTypes = { - ...ViewPropTypes, - style: pickerStyleType, - /** - * Value matching value of one of the items. Can be a string or an integer. - */ - selectedValue: PropTypes.any, - /** - * Callback for when an item is selected. This is called with the following parameters: - * - `itemValue`: the `value` prop of the item that was selected - * - `itemPosition`: the index of the selected item in this picker - */ - onValueChange: PropTypes.func, - /** - * If set to false, the picker will be disabled, i.e. the user will not be able to make a - * selection. - * @platform android - */ - enabled: PropTypes.bool, - /** - * On Android, specifies how to display the selection items when the user taps on the picker: - * - * - 'dialog': Show a modal dialog. This is the default. - * - 'dropdown': Shows a dropdown anchored to the picker view - * - * @platform android - */ - mode: PropTypes.oneOf(['dialog', 'dropdown']), - /** - * Style to apply to each of the item labels. - * @platform ios - */ - itemStyle: itemStylePropType, - /** - * Prompt string for this picker, used on Android in dialog mode as the title of the dialog. - * @platform android - */ - prompt: PropTypes.string, - /** - * Used to locate this view in end-to-end tests. - */ - testID: PropTypes.string, - }; - render() { if ( Platform.OS === 'ios' || Platform.OS === 'macos' /* TODO(macOS ISS#2323203) */ ) { - // $FlowFixMe found when converting React.createClass to ES6 + /* $FlowFixMe(>=0.81.0 site=react_native_ios_fb) This suppression was + * added when renaming suppression sites. */ return {this.props.children}; } else if (Platform.OS === 'android') { return ( - // $FlowFixMe found when converting React.createClass to ES6 + /* $FlowFixMe(>=0.81.0 site=react_native_android_fb) This suppression + * was added when renaming suppression sites. */ {this.props.children} ); } else { diff --git a/Libraries/Components/Picker/PickerAndroid.android.js b/Libraries/Components/Picker/PickerAndroid.android.js index 7066b942ad222c..19d9b7d1921bb1 100644 --- a/Libraries/Components/Picker/PickerAndroid.android.js +++ b/Libraries/Components/Picker/PickerAndroid.android.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. @@ -10,13 +10,8 @@ 'use strict'; -const ColorPropType = require('ColorPropType'); const React = require('React'); -const ReactPropTypes = require('prop-types'); const StyleSheet = require('StyleSheet'); -const StyleSheetPropType = require('StyleSheetPropType'); -const ViewPropTypes = require('ViewPropTypes'); -const ViewStylePropTypes = require('ViewStylePropTypes'); const processColor = require('processColor'); const requireNativeComponent = require('requireNativeComponent'); @@ -27,41 +22,30 @@ const DialogPicker = requireNativeComponent('AndroidDialogPicker'); const REF_PICKER = 'picker'; const MODE_DROPDOWN = 'dropdown'; -const pickerStyleType = StyleSheetPropType({ - ...ViewStylePropTypes, - color: ColorPropType, -}); - -type Event = Object; +import type {SyntheticEvent} from 'CoreEventTypes'; +import type {TextStyleProp} from 'StyleSheet'; + +type PickerAndroidChangeEvent = SyntheticEvent< + $ReadOnly<{| + position: number, + |}>, +>; + +type PickerAndroidProps = $ReadOnly<{| + children?: React.Node, + style?: ?TextStyleProp, + selectedValue?: any, + enabled?: ?boolean, + mode?: ?('dialog' | 'dropdown'), + onValueChange?: ?(newValue: any, newIndex: number) => mixed, + prompt?: ?string, + testID?: string, +|}>; /** * Not exposed as a public API - use instead. */ -class PickerAndroid extends React.Component< - { - style?: $FlowFixMe, - selectedValue?: any, - enabled?: boolean, - mode?: 'dialog' | 'dropdown', - onValueChange?: Function, - prompt?: string, - testID?: string, - }, - *, -> { - /* $FlowFixMe(>=0.78.0 site=react_native_android_fb) This issue was found - * when making Flow check .android.js files. */ - static propTypes = { - ...ViewPropTypes, - style: pickerStyleType, - selectedValue: ReactPropTypes.any, - enabled: ReactPropTypes.bool, - mode: ReactPropTypes.oneOf(['dialog', 'dropdown']), - onValueChange: ReactPropTypes.func, - prompt: ReactPropTypes.string, - testID: ReactPropTypes.string, - }; - +class PickerAndroid extends React.Component { /* $FlowFixMe(>=0.78.0 site=react_native_android_fb) This issue was found * when making Flow check .android.js files. */ constructor(props, context) { @@ -122,7 +106,7 @@ class PickerAndroid extends React.Component< return ; } - _onChange = (event: Event) => { + _onChange = (event: PickerAndroidChangeEvent) => { if (this.props.onValueChange) { const position = event.nativeEvent.position; if (position >= 0) { diff --git a/Libraries/Components/Picker/PickerAndroid.ios.js b/Libraries/Components/Picker/PickerAndroid.ios.js index 260d559929796f..7a00b6636cf664 100644 --- a/Libraries/Components/Picker/PickerAndroid.ios.js +++ b/Libraries/Components/Picker/PickerAndroid.ios.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. diff --git a/Libraries/Components/Picker/PickerIOS.android.js b/Libraries/Components/Picker/PickerIOS.android.js index 36acfe18342b6f..006c5b4d1ae82f 100644 --- a/Libraries/Components/Picker/PickerIOS.android.js +++ b/Libraries/Components/Picker/PickerIOS.android.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. diff --git a/Libraries/Components/Picker/PickerIOS.ios.js b/Libraries/Components/Picker/PickerIOS.ios.js index 897a3d7da00f2e..b5e58dc5c1af4a 100644 --- a/Libraries/Components/Picker/PickerIOS.ios.js +++ b/Libraries/Components/Picker/PickerIOS.ios.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. @@ -48,6 +48,7 @@ type RCTPickerIOSType = Class< onStartShouldSetResponder: () => boolean, selectedIndex: number, style?: ?TextStyleProp, + testID?: ?string, |}>, >, >; @@ -115,6 +116,7 @@ class PickerIOS extends React.Component { ref={picker => { this._picker = picker; }} + testID={this.props.testID} style={[styles.pickerIOS, this.props.itemStyle]} items={this.state.items} selectedIndex={this.state.selectedIndex} diff --git a/Libraries/Components/ProgressBarAndroid/ProgressBarAndroid.android.js b/Libraries/Components/ProgressBarAndroid/ProgressBarAndroid.android.js index f343e2e5452044..9512fd1dfabec2 100644 --- a/Libraries/Components/ProgressBarAndroid/ProgressBarAndroid.android.js +++ b/Libraries/Components/ProgressBarAndroid/ProgressBarAndroid.android.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. @@ -19,7 +19,7 @@ import type {ViewProps} from 'ViewPropTypes'; const AndroidProgressBar = requireNativeComponent('AndroidProgressBar'); -type Props = $ReadOnly<{| +export type ProgressBarAndroidProps = $ReadOnly<{| ...ViewProps, /** @@ -83,7 +83,7 @@ type Props = $ReadOnly<{| * ``` */ const ProgressBarAndroid = ( - props: Props, + props: ProgressBarAndroidProps, forwardedRef: ?React.Ref<'AndroidProgressBar'>, ) => { return ; @@ -98,4 +98,6 @@ ProgressBarAndroidToExport.defaultProps = { animating: true, }; -module.exports = (ProgressBarAndroidToExport: Class>); +module.exports = (ProgressBarAndroidToExport: Class< + NativeComponent, +>); diff --git a/Libraries/Components/ProgressBarAndroid/ProgressBarAndroid.ios.js b/Libraries/Components/ProgressBarAndroid/ProgressBarAndroid.ios.js index 260d559929796f..7a00b6636cf664 100644 --- a/Libraries/Components/ProgressBarAndroid/ProgressBarAndroid.ios.js +++ b/Libraries/Components/ProgressBarAndroid/ProgressBarAndroid.ios.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. diff --git a/Libraries/Components/ProgressViewIOS/ProgressViewIOS.android.js b/Libraries/Components/ProgressViewIOS/ProgressViewIOS.android.js index 8caa73db33e494..1b5a1436e4f1ba 100644 --- a/Libraries/Components/ProgressViewIOS/ProgressViewIOS.android.js +++ b/Libraries/Components/ProgressViewIOS/ProgressViewIOS.android.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. diff --git a/Libraries/Components/ProgressViewIOS/ProgressViewIOS.ios.js b/Libraries/Components/ProgressViewIOS/ProgressViewIOS.ios.js index ea92fccb980583..2d9ae4b17f5c5d 100644 --- a/Libraries/Components/ProgressViewIOS/ProgressViewIOS.ios.js +++ b/Libraries/Components/ProgressViewIOS/ProgressViewIOS.ios.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. @@ -10,82 +10,69 @@ 'use strict'; -const Image = require('Image'); -const NativeMethodsMixin = require('NativeMethodsMixin'); const React = require('React'); -const ReactNative = require('ReactNative'); -const PropTypes = require('prop-types'); const StyleSheet = require('StyleSheet'); -const ViewPropTypes = require('ViewPropTypes'); -const createReactClass = require('create-react-class'); const requireNativeComponent = require('requireNativeComponent'); +import type {NativeComponent} from 'ReactNative'; import type {ImageSource} from 'ImageSource'; import type {ColorValue} from 'StyleSheetTypes'; import type {ViewProps} from 'ViewPropTypes'; -const RCTProgressView = requireNativeComponent('RCTProgressView'); - type Props = $ReadOnly<{| ...ViewProps, + + /** + * The progress bar style. + */ progressViewStyle?: ?('default' | 'bar'), + + /** + * The progress value (between 0 and 1). + */ progress?: ?number, + + /** + * The tint color of the progress bar itself. + */ progressTintColor?: ?ColorValue, - trackTintColor?: ?string, + + /** + * The tint color of the progress bar track. + */ + trackTintColor?: ?ColorValue, + + /** + * A stretchable image to display as the progress bar. + */ progressImage?: ?ImageSource, + + /** + * A stretchable image to display behind the progress bar. + */ trackImage?: ?ImageSource, |}>; +type NativeProgressViewIOS = Class>; + +const RCTProgressView = ((requireNativeComponent( + 'RCTProgressView', +): any): NativeProgressViewIOS); + /** * Use `ProgressViewIOS` to render a UIProgressView on iOS. */ -const ProgressViewIOS = createReactClass({ - displayName: 'ProgressViewIOS', - mixins: [NativeMethodsMixin], - - propTypes: { - ...ViewPropTypes, - /** - * The progress bar style. - */ - progressViewStyle: PropTypes.oneOf(['default', 'bar']), - - /** - * The progress value (between 0 and 1). - */ - progress: PropTypes.number, - - /** - * The tint color of the progress bar itself. - */ - progressTintColor: PropTypes.string, - - /** - * The tint color of the progress bar track. - */ - trackTintColor: PropTypes.string, - - /** - * A stretchable image to display as the progress bar. - */ - progressImage: Image.propTypes.source, - - /** - * A stretchable image to display behind the progress bar. - */ - trackImage: Image.propTypes.source, - }, - - render: function() { - return ( - - ); - }, -}); +const ProgressViewIOS = ( + props: Props, + forwardedRef?: ?React.Ref, +) => ( + +); const styles = StyleSheet.create({ progressView: { @@ -93,6 +80,7 @@ const styles = StyleSheet.create({ }, }); -module.exports = ((ProgressViewIOS: any): Class< - ReactNative.NativeComponent, ->); +// $FlowFixMe - TODO T29156721 `React.forwardRef` is not defined in Flow, yet. +const ProgressViewIOSWithRef = React.forwardRef(ProgressViewIOS); + +module.exports = (ProgressViewIOSWithRef: NativeProgressViewIOS); diff --git a/Libraries/Components/RefreshControl/RefreshControl.js b/Libraries/Components/RefreshControl/RefreshControl.js index 9b287cc4a180b9..556b06e5d57536 100644 --- a/Libraries/Components/RefreshControl/RefreshControl.js +++ b/Libraries/Components/RefreshControl/RefreshControl.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. @@ -15,21 +15,23 @@ const React = require('React'); const {NativeComponent} = require('ReactNative'); const requireNativeComponent = require('requireNativeComponent'); -const nullthrows = require('fbjs/lib/nullthrows'); +const nullthrows = require('nullthrows'); import type {ColorValue} from 'StyleSheetTypes'; import type {ViewProps} from 'ViewPropTypes'; +let RefreshLayoutConsts; if (Platform.OS === 'android') { - const AndroidSwipeRefreshLayout = require('UIManager') - .AndroidSwipeRefreshLayout; - var RefreshLayoutConsts = AndroidSwipeRefreshLayout + const AndroidSwipeRefreshLayout = require('UIManager').getViewManagerConfig( + 'AndroidSwipeRefreshLayout', + ); + RefreshLayoutConsts = AndroidSwipeRefreshLayout ? AndroidSwipeRefreshLayout.Constants : {SIZE: {}}; } else { - var RefreshLayoutConsts = {SIZE: {}}; + RefreshLayoutConsts = {SIZE: {}}; } -type NativeRefreshControlType = Class>; +type NativeRefreshControlType = Class>; const NativeRefreshControl: NativeRefreshControlType = Platform.OS === 'ios' @@ -77,7 +79,7 @@ type AndroidProps = $ReadOnly<{| progressViewOffset?: ?number, |}>; -type Props = $ReadOnly<{| +export type RefreshControlProps = $ReadOnly<{| ...ViewProps, ...IOSProps, ...AndroidProps, @@ -85,7 +87,7 @@ type Props = $ReadOnly<{| /** * Called when the view starts refreshing. */ - onRefresh?: ?Function, + onRefresh?: ?() => void, /** * Whether the view should be indicating an active refresh. @@ -138,7 +140,7 @@ type Props = $ReadOnly<{| * __Note:__ `refreshing` is a controlled prop, this is why it needs to be set to true * in the `onRefresh` function otherwise the refresh indicator will stop immediately. */ -class RefreshControl extends React.Component { +class RefreshControl extends React.Component { static SIZE = RefreshLayoutConsts.SIZE; _nativeRef: ?React.ElementRef = null; @@ -148,7 +150,7 @@ class RefreshControl extends React.Component { this._lastNativeRefreshing = this.props.refreshing; } - componentDidUpdate(prevProps: Props) { + componentDidUpdate(prevProps: RefreshControlProps) { // RefreshControl is a controlled component so if the native refreshing // value doesn't match the current js refreshing prop update it to // the js value. diff --git a/Libraries/Components/RefreshControl/__mocks__/RefreshControlMock.js b/Libraries/Components/RefreshControl/__mocks__/RefreshControlMock.js index 8e85742ce4c4da..daa576350aa120 100644 --- a/Libraries/Components/RefreshControl/__mocks__/RefreshControlMock.js +++ b/Libraries/Components/RefreshControl/__mocks__/RefreshControlMock.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. diff --git a/Libraries/Components/SafeAreaView/SafeAreaView.ios.js b/Libraries/Components/SafeAreaView/SafeAreaView.ios.js deleted file mode 100644 index 5fb0406b8d5125..00000000000000 --- a/Libraries/Components/SafeAreaView/SafeAreaView.ios.js +++ /dev/null @@ -1,39 +0,0 @@ -/** - * Copyright (c) 2015-present, Facebook, Inc. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @flow - * @format - */ - -const React = require('React'); -const ViewPropTypes = require('ViewPropTypes'); -const requireNativeComponent = require('requireNativeComponent'); - -import type {ViewProps} from 'ViewPropTypes'; - -const RCTSafeAreaView = requireNativeComponent('RCTSafeAreaView'); - -type Props = ViewProps & { - children: any, -}; - -/** - * Renders nested content and automatically applies paddings reflect the portion of the view - * that is not covered by navigation bars, tab bars, toolbars, and other ancestor views. - * Moreover, and most importantly, Safe Area's paddings reflect physical limitation of the screen, - * such as rounded corners or camera notches (aka sensor housing area on iPhone X). - */ -class SafeAreaView extends React.Component { - static propTypes = { - ...ViewPropTypes, - }; - - render() { - return ; - } -} - -module.exports = SafeAreaView; diff --git a/Libraries/Components/SafeAreaView/SafeAreaView.js b/Libraries/Components/SafeAreaView/SafeAreaView.js new file mode 100644 index 00000000000000..6f4ecf3ac867b4 --- /dev/null +++ b/Libraries/Components/SafeAreaView/SafeAreaView.js @@ -0,0 +1,50 @@ +/** + * 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. + * + * @flow strict-local + * @format + */ + +const Platform = require('Platform'); +const React = require('React'); +const View = require('View'); +const requireNativeComponent = require('requireNativeComponent'); + +import type {ViewProps} from 'ViewPropTypes'; + +type Props = $ReadOnly<{| + ...ViewProps, + emulateUnlessSupported?: boolean, +|}>; + +let exported; + +/** + * Renders nested content and automatically applies paddings reflect the portion + * of the view that is not covered by navigation bars, tab bars, toolbars, and + * other ancestor views. + * + * Moreover, and most importantly, Safe Area's paddings reflect physical + * limitation of the screen, such as rounded corners or camera notches (aka + * sensor housing area on iPhone X). + */ +if (Platform.OS === 'android') { + exported = class SafeAreaView extends React.Component { + render(): React.Node { + const {emulateUnlessSupported, ...props} = this.props; + return ; + } + }; +} else { + const RCTSafeAreaView = requireNativeComponent('RCTSafeAreaView'); + exported = class SafeAreaView extends React.Component { + render(): React.Node { + return ; + } + }; +} + +module.exports = exported; diff --git a/Libraries/Components/ScrollResponder.js b/Libraries/Components/ScrollResponder.js index 548efba80da48c..46fe2a7f566330 100644 --- a/Libraries/Components/ScrollResponder.js +++ b/Libraries/Components/ScrollResponder.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. @@ -14,17 +14,20 @@ const Dimensions = require('Dimensions'); const FrameRateLogger = require('FrameRateLogger'); const Keyboard = require('Keyboard'); const ReactNative = require('ReactNative'); -const Subscribable = require('Subscribable'); const TextInputState = require('TextInputState'); const UIManager = require('UIManager'); const invariant = require('fbjs/lib/invariant'); -const nullthrows = require('fbjs/lib/nullthrows'); +const nullthrows = require('nullthrows'); const performanceNow = require('fbjs/lib/performanceNow'); const warning = require('fbjs/lib/warning'); const {ScrollViewManager} = require('NativeModules'); +import type {PressEvent, ScrollEvent} from 'CoreEventTypes'; +import type {KeyboardEvent} from 'Keyboard'; +import type EmitterSubscription from 'EmitterSubscription'; + /** * Mixin that can be integrated in order to handle scrolling that plays well * with `ResponderEventPlugin`. Integrate with your platform specific scroll @@ -112,10 +115,12 @@ type State = { observedScrollSinceBecomingResponder: boolean, becameResponderWhileAnimating: boolean, }; -type Event = Object; const ScrollResponderMixin = { - mixins: [Subscribable.Mixin], + _subscriptionKeyboardWillShow: (null: ?EmitterSubscription), + _subscriptionKeyboardWillHide: (null: ?EmitterSubscription), + _subscriptionKeyboardDidShow: (null: ?EmitterSubscription), + _subscriptionKeyboardDidHide: (null: ?EmitterSubscription), scrollResponderMixinGetInitialState: function(): State { return { isTouching: false, @@ -164,7 +169,9 @@ const ScrollResponderMixin = { * true. * */ - scrollResponderHandleStartShouldSetResponder: function(e: Event): boolean { + scrollResponderHandleStartShouldSetResponder: function( + e: PressEvent, + ): boolean { const currentlyFocusedTextInput = TextInputState.currentlyFocusedField(); if ( @@ -189,7 +196,7 @@ const ScrollResponderMixin = { * Invoke this from an `onStartShouldSetResponderCapture` event. */ scrollResponderHandleStartShouldSetResponderCapture: function( - e: Event, + e: PressEvent, ): boolean { // The scroll view should receive taps instead of its descendants if: // * it is already animating/decelerating @@ -208,6 +215,7 @@ const ScrollResponderMixin = { if ( keyboardNeverPersistTaps && currentlyFocusedTextInput != null && + e.target && !TextInputState.isTextInput(e.target) ) { return true; @@ -250,9 +258,9 @@ const ScrollResponderMixin = { /** * Invoke this from an `onTouchEnd` event. * - * @param {SyntheticEvent} e Event. + * @param {PressEvent} e Event. */ - scrollResponderHandleTouchEnd: function(e: Event) { + scrollResponderHandleTouchEnd: function(e: PressEvent) { const nativeEvent = e.nativeEvent; this.state.isTouching = nativeEvent.touches.length !== 0; this.props.onTouchEnd && this.props.onTouchEnd(e); @@ -261,9 +269,9 @@ const ScrollResponderMixin = { /** * Invoke this from an `onTouchCancel` event. * - * @param {SyntheticEvent} e Event. + * @param {PressEvent} e Event. */ - scrollResponderHandleTouchCancel: function(e: Event) { + scrollResponderHandleTouchCancel: function(e: PressEvent) { this.state.isTouching = false; this.props.onTouchCancel && this.props.onTouchCancel(e); }, @@ -271,7 +279,7 @@ const ScrollResponderMixin = { /** * Invoke this from an `onResponderRelease` event. */ - scrollResponderHandleResponderRelease: function(e: Event) { + scrollResponderHandleResponderRelease: function(e: PressEvent) { this.props.onResponderRelease && this.props.onResponderRelease(e); // By default scroll views will unfocus a textField @@ -291,7 +299,7 @@ const ScrollResponderMixin = { } }, - scrollResponderHandleScroll: function(e: Event) { + scrollResponderHandleScroll: function(e: ScrollEvent) { this.state.observedScrollSinceBecomingResponder = true; this.props.onScroll && this.props.onScroll(e); }, @@ -299,7 +307,7 @@ const ScrollResponderMixin = { /** * Invoke this from an `onResponderGrant` event. */ - scrollResponderHandleResponderGrant: function(e: Event) { + scrollResponderHandleResponderGrant: function(e: ScrollEvent) { this.state.observedScrollSinceBecomingResponder = false; this.props.onResponderGrant && this.props.onResponderGrant(e); this.state.becameResponderWhileAnimating = this.scrollResponderIsAnimating(); @@ -312,7 +320,7 @@ const ScrollResponderMixin = { * * Invoke this from an `onScrollBeginDrag` event. */ - scrollResponderHandleScrollBeginDrag: function(e: Event) { + scrollResponderHandleScrollBeginDrag: function(e: ScrollEvent) { FrameRateLogger.beginScroll(); // TODO: track all scrolls after implementing onScrollEndAnimation this.props.onScrollBeginDrag && this.props.onScrollBeginDrag(e); }, @@ -320,7 +328,7 @@ const ScrollResponderMixin = { /** * Invoke this from an `onScrollEndDrag` event. */ - scrollResponderHandleScrollEndDrag: function(e: Event) { + scrollResponderHandleScrollEndDrag: function(e: ScrollEvent) { const {velocity} = e.nativeEvent; // - If we are animating, then this is a "drag" that is stopping the scrollview and momentum end // will fire. @@ -339,7 +347,7 @@ const ScrollResponderMixin = { /** * Invoke this from an `onMomentumScrollBegin` event. */ - scrollResponderHandleMomentumScrollBegin: function(e: Event) { + scrollResponderHandleMomentumScrollBegin: function(e: ScrollEvent) { this.state.lastMomentumScrollBeginTime = performanceNow(); this.props.onMomentumScrollBegin && this.props.onMomentumScrollBegin(e); }, @@ -347,7 +355,7 @@ const ScrollResponderMixin = { /** * Invoke this from an `onMomentumScrollEnd` event. */ - scrollResponderHandleMomentumScrollEnd: function(e: Event) { + scrollResponderHandleMomentumScrollEnd: function(e: ScrollEvent) { FrameRateLogger.endScroll(); this.state.lastMomentumScrollEndTime = performanceNow(); this.props.onMomentumScrollEnd && this.props.onMomentumScrollEnd(e); @@ -362,9 +370,9 @@ const ScrollResponderMixin = { * responder). The `onResponderReject` won't fire in that case - it only * fires when a *current* responder rejects our request. * - * @param {SyntheticEvent} e Touch Start event. + * @param {PressEvent} e Touch Start event. */ - scrollResponderHandleTouchStart: function(e: Event) { + scrollResponderHandleTouchStart: function(e: PressEvent) { this.state.isTouching = true; this.props.onTouchStart && this.props.onTouchStart(e); }, @@ -378,9 +386,9 @@ const ScrollResponderMixin = { * responder). The `onResponderReject` won't fire in that case - it only * fires when a *current* responder rejects our request. * - * @param {SyntheticEvent} e Touch Start event. + * @param {PressEvent} e Touch Start event. */ - scrollResponderHandleTouchMove: function(e: Event) { + scrollResponderHandleTouchMove: function(e: PressEvent) { this.props.onTouchMove && this.props.onTouchMove(e); }, @@ -405,7 +413,7 @@ const ScrollResponderMixin = { * Components can pass what node to use by defining a `getScrollableNode` * function otherwise `this` is used. */ - scrollResponderGetScrollableNode: function(): any { + scrollResponderGetScrollableNode: function(): ?number { return this.getScrollableNode ? this.getScrollableNode() : ReactNative.findNodeHandle(this); @@ -436,7 +444,7 @@ const ScrollResponderMixin = { } UIManager.dispatchViewManagerCommand( nullthrows(this.scrollResponderGetScrollableNode()), - UIManager.RCTScrollView.Commands.scrollTo, + UIManager.getViewManagerConfig('RCTScrollView').Commands.scrollTo, [x || 0, y || 0, animated !== false], ); }, @@ -454,7 +462,7 @@ const ScrollResponderMixin = { const animated = (options && options.animated) !== false; UIManager.dispatchViewManagerCommand( this.scrollResponderGetScrollableNode(), - UIManager.RCTScrollView.Commands.scrollToEnd, + UIManager.getViewManagerConfig('RCTScrollView').Commands.scrollToEnd, [animated], ); }, @@ -513,7 +521,8 @@ const ScrollResponderMixin = { scrollResponderFlashScrollIndicators: function() { UIManager.dispatchViewManagerCommand( this.scrollResponderGetScrollableNode(), - UIManager.RCTScrollView.Commands.flashScrollIndicators, + UIManager.getViewManagerConfig('RCTScrollView').Commands + .flashScrollIndicators, [], ); }, @@ -522,14 +531,14 @@ const ScrollResponderMixin = { * This method should be used as the callback to onFocus in a TextInputs' * parent view. Note that any module using this mixin needs to return * the parent view's ref in getScrollViewRef() in order to use this method. - * @param {any} nodeHandle The TextInput node handle + * @param {number} nodeHandle The TextInput node handle * @param {number} additionalOffset The scroll view's bottom "contentInset". * Default is 0. * @param {bool} preventNegativeScrolling Whether to allow pulling the content * down to make it meet the keyboard's top. Default is false. */ scrollResponderScrollNativeHandleToKeyboard: function( - nodeHandle: any, + nodeHandle: number, additionalOffset?: number, preventNegativeScrollOffset?: boolean, ) { @@ -579,8 +588,8 @@ const ScrollResponderMixin = { this.preventNegativeScrollOffset = false; }, - scrollResponderTextInputFocusError: function(e: Event) { - console.error('Error measuring text field: ', e); + scrollResponderTextInputFocusError: function(msg: string) { + console.error('Error measuring text field: ', msg); }, /** @@ -601,28 +610,39 @@ const ScrollResponderMixin = { this.keyboardWillOpenTo = null; this.additionalScrollOffset = 0; - this.addListenerOn( - Keyboard, + this._subscriptionKeyboardWillShow = Keyboard.addListener( 'keyboardWillShow', this.scrollResponderKeyboardWillShow, ); - this.addListenerOn( - Keyboard, + this._subscriptionKeyboardWillHide = Keyboard.addListener( 'keyboardWillHide', this.scrollResponderKeyboardWillHide, ); - this.addListenerOn( - Keyboard, + this._subscriptionKeyboardDidShow = Keyboard.addListener( 'keyboardDidShow', this.scrollResponderKeyboardDidShow, ); - this.addListenerOn( - Keyboard, + this._subscriptionKeyboardDidHide = Keyboard.addListener( 'keyboardDidHide', this.scrollResponderKeyboardDidHide, ); }, + componentWillUnmount: function() { + if (this._subscriptionKeyboardWillShow != null) { + this._subscriptionKeyboardWillShow.remove(); + } + if (this._subscriptionKeyboardWillHide != null) { + this._subscriptionKeyboardWillHide.remove(); + } + if (this._subscriptionKeyboardDidShow != null) { + this._subscriptionKeyboardDidShow.remove(); + } + if (this._subscriptionKeyboardDidHide != null) { + this._subscriptionKeyboardDidHide.remove(); + } + }, + /** * Warning, this may be called several times for a single keyboard opening. * It's best to store the information in this method and then take any action @@ -651,17 +671,17 @@ const ScrollResponderMixin = { * relevant to you. (For example, only if you receive these callbacks after * you had explicitly focused a node etc). */ - scrollResponderKeyboardWillShow: function(e: Event) { + scrollResponderKeyboardWillShow: function(e: KeyboardEvent) { this.keyboardWillOpenTo = e; this.props.onKeyboardWillShow && this.props.onKeyboardWillShow(e); }, - scrollResponderKeyboardWillHide: function(e: Event) { + scrollResponderKeyboardWillHide: function(e: KeyboardEvent) { this.keyboardWillOpenTo = null; this.props.onKeyboardWillHide && this.props.onKeyboardWillHide(e); }, - scrollResponderKeyboardDidShow: function(e: Event) { + scrollResponderKeyboardDidShow: function(e: KeyboardEvent) { // TODO(7693961): The event for DidShow is not available on iOS yet. // Use the one from WillShow and do not assign. if (e) { @@ -670,7 +690,7 @@ const ScrollResponderMixin = { this.props.onKeyboardDidShow && this.props.onKeyboardDidShow(e); }, - scrollResponderKeyboardDidHide: function(e: Event) { + scrollResponderKeyboardDidHide: function(e: KeyboardEvent) { this.keyboardWillOpenTo = null; this.props.onKeyboardDidHide && this.props.onKeyboardDidHide(e); }, diff --git a/Libraries/Components/ScrollView/InternalScrollViewType.js b/Libraries/Components/ScrollView/InternalScrollViewType.js index 471e25d9a5dab9..a13db7dee6a65b 100644 --- a/Libraries/Components/ScrollView/InternalScrollViewType.js +++ b/Libraries/Components/ScrollView/InternalScrollViewType.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. diff --git a/Libraries/Components/ScrollView/ScrollView.js b/Libraries/Components/ScrollView/ScrollView.js index f30661dfc45401..98e9a4337047f9 100644 --- a/Libraries/Components/ScrollView/ScrollView.js +++ b/Libraries/Components/ScrollView/ScrollView.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. @@ -26,7 +26,6 @@ const flattenStyle = require('flattenStyle'); const invariant = require('fbjs/lib/invariant'); const processDecelerationRate = require('processDecelerationRate'); const requireNativeComponent = require('requireNativeComponent'); -const warning = require('fbjs/lib/warning'); const resolveAssetSource = require('resolveAssetSource'); import type {PressEvent} from 'CoreEventTypes'; @@ -217,6 +216,11 @@ type IOSProps = $ReadOnly<{| * @platform ios */ scrollsToTop?: ?boolean, + /** + * Fires when the scroll view scrolls to top after the status bar has been tapped + * @platform ios + */ + onScrollToTop?: ?Function, /** * When true, shows a horizontal scroll indicator. * The default value is true. @@ -406,7 +410,9 @@ export type Props = $ReadOnly<{| * - `false`, deprecated, use 'never' instead * - `true`, deprecated, use 'always' instead */ - // $FlowFixMe(site=react_native_fb) Issues found when typing ScrollView + /* $FlowFixMe(>=0.86.0 site=react_native_fb) This comment suppresses an error + * found when Flow v0.86 was deployed. To see the error, delete this comment + * and run Flow. */ keyboardShouldPersistTaps?: ?('always' | 'never' | 'handled' | false | true), /** * Called when the momentum scroll starts (scroll which occurs as the ScrollView glides to a stop). @@ -488,6 +494,22 @@ export type Props = $ReadOnly<{| * Overrides less configurable `pagingEnabled` and `snapToInterval` props. */ snapToOffsets?: ?$ReadOnlyArray, + /** + * Use in conjuction with `snapToOffsets`. By default, the beginning + * of the list counts as a snap offset. Set `snapToStart` to false to disable + * this behavior and allow the list to scroll freely between its start and + * the first `snapToOffsets` offset. + * The default value is true. + */ + snapToStart?: ?boolean, + /** + * Use in conjuction with `snapToOffsets`. By default, the end + * of the list counts as a snap offset. Set `snapToEnd` to false to disable + * this behavior and allow the list to scroll freely between its end and + * the last `snapToOffsets` offset. + * The default value is true. + */ + snapToEnd?: ?boolean, /** * Experimental: When true, offscreen child views (whose `overflow` value is * `hidden`) are removed from their native backing superview when offscreen. @@ -503,7 +525,6 @@ export type Props = $ReadOnly<{| * See [RefreshControl](docs/refreshcontrol.html). */ refreshControl?: ?React.Element, - style?: ?ViewStyleProp, children?: React.Node, |}>; @@ -1005,6 +1026,10 @@ const ScrollView = createReactClass({ ? true : false, DEPRECATED_sendUpdatedChildFrames, + // default to true + snapToStart: this.props.snapToStart !== false, + // default to true + snapToEnd: this.props.snapToEnd !== false, // pagingEnabled is overridden by snapToInterval / snapToOffsets pagingEnabled: Platform.select({ // on iOS, pagingEnabled must be set to false to have snapToInterval / snapToOffsets work diff --git a/Libraries/Components/ScrollView/ScrollViewStickyHeader.js b/Libraries/Components/ScrollView/ScrollViewStickyHeader.js index e17467b264cd98..5ad409c783e96f 100644 --- a/Libraries/Components/ScrollView/ScrollViewStickyHeader.js +++ b/Libraries/Components/ScrollView/ScrollViewStickyHeader.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. diff --git a/Libraries/Components/ScrollView/__mocks__/ScrollViewMock.js b/Libraries/Components/ScrollView/__mocks__/ScrollViewMock.js index 46f691382d2f6e..a2367c357d3189 100644 --- a/Libraries/Components/ScrollView/__mocks__/ScrollViewMock.js +++ b/Libraries/Components/ScrollView/__mocks__/ScrollViewMock.js @@ -1,19 +1,17 @@ /** - * Copyright (c) 2013-present, Facebook, Inc. + * 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 + * @flow strict-local */ /* eslint-env jest */ 'use strict'; -declare var jest: any; - const React = require('React'); const View = require('View'); diff --git a/Libraries/Components/ScrollView/processDecelerationRate.js b/Libraries/Components/ScrollView/processDecelerationRate.js index fc50c6766f92e9..a685381715d835 100644 --- a/Libraries/Components/ScrollView/processDecelerationRate.js +++ b/Libraries/Components/ScrollView/processDecelerationRate.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. diff --git a/Libraries/Components/SegmentedControlIOS/SegmentedControlIOS.android.js b/Libraries/Components/SegmentedControlIOS/SegmentedControlIOS.android.js index 7a988960ceca96..581e77cf6ff8d4 100644 --- a/Libraries/Components/SegmentedControlIOS/SegmentedControlIOS.android.js +++ b/Libraries/Components/SegmentedControlIOS/SegmentedControlIOS.android.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. diff --git a/Libraries/Components/SegmentedControlIOS/SegmentedControlIOS.ios.js b/Libraries/Components/SegmentedControlIOS/SegmentedControlIOS.ios.js index b4635f13f8e4d5..540a31838b5a0b 100644 --- a/Libraries/Components/SegmentedControlIOS/SegmentedControlIOS.ios.js +++ b/Libraries/Components/SegmentedControlIOS/SegmentedControlIOS.ios.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. @@ -10,39 +10,66 @@ 'use strict'; -const NativeMethodsMixin = require('NativeMethodsMixin'); const React = require('React'); -const ReactNative = require('ReactNative'); -const PropTypes = require('prop-types'); const StyleSheet = require('StyleSheet'); -const ViewPropTypes = require('ViewPropTypes'); -const createReactClass = require('create-react-class'); const requireNativeComponent = require('requireNativeComponent'); +import type {SyntheticEvent} from 'CoreEventTypes'; import type {ViewProps} from 'ViewPropTypes'; +import type {NativeComponent} from 'ReactNative'; -const RCTSegmentedControl = requireNativeComponent('RCTSegmentedControl'); +type Event = SyntheticEvent< + $ReadOnly<{| + value: number, + selectedSegmentIndex: number, + |}>, +>; -type DefaultProps = { - values: $ReadOnlyArray, - enabled: boolean, -}; - -type Props = $ReadOnly<{| +type SegmentedControlIOSProps = $ReadOnly<{| ...ViewProps, - values?: ?$ReadOnlyArray, + /** + * The labels for the control's segment buttons, in order. + */ + values?: $ReadOnlyArray, + /** + * The index in `props.values` of the segment to be (pre)selected. + */ selectedIndex?: ?number, - onValueChange?: ?Function, - onChange?: ?Function, - enabled?: ?boolean, + /** + * Callback that is called when the user taps a segment; + * passes the segment's value as an argument + */ + onValueChange?: ?(value: number) => mixed, + /** + * Callback that is called when the user taps a segment; + * passes the event as an argument + */ + onChange?: ?(event: Event) => mixed, + /** + * If false the user won't be able to interact with the control. + * Default value is true. + */ + enabled?: boolean, + /** + * Accent color of the control. + */ tintColor?: ?string, + /** + * If true, then selecting a segment won't persist visually. + * The `onValueChange` callback will still work as expected. + */ momentary?: ?boolean, |}>; -const SEGMENTED_CONTROL_REFERENCE = 'segmentedcontrol'; +type Props = $ReadOnly<{| + ...SegmentedControlIOSProps, + forwardedRef: ?React.Ref, +|}>; -type Event = Object; +type NativeSegmentedControlIOS = Class< + NativeComponent, +>; /** * Use `SegmentedControlIOS` to render a UISegmentedControl iOS. @@ -64,76 +91,35 @@ type Event = Object; * /> * ```` */ -const SegmentedControlIOS = createReactClass({ - displayName: 'SegmentedControlIOS', - mixins: [NativeMethodsMixin], - - propTypes: { - ...ViewPropTypes, - /** - * The labels for the control's segment buttons, in order. - */ - values: PropTypes.arrayOf(PropTypes.string), - - /** - * The index in `props.values` of the segment to be (pre)selected. - */ - selectedIndex: PropTypes.number, - - /** - * Callback that is called when the user taps a segment; - * passes the segment's value as an argument - */ - onValueChange: PropTypes.func, - - /** - * Callback that is called when the user taps a segment; - * passes the event as an argument - */ - onChange: PropTypes.func, - - /** - * If false the user won't be able to interact with the control. - * Default value is true. - */ - enabled: PropTypes.bool, - - /** - * Accent color of the control. - */ - tintColor: PropTypes.string, - - /** - * If true, then selecting a segment won't persist visually. - * The `onValueChange` callback will still work as expected. - */ - momentary: PropTypes.bool, - }, - getDefaultProps: function(): DefaultProps { - return { - values: [], - enabled: true, - }; - }, +const RCTSegmentedControl = ((requireNativeComponent( + 'RCTSegmentedControl', +): any): NativeSegmentedControlIOS); - _onChange: function(event: Event) { +class SegmentedControlIOS extends React.Component { + static defaultProps = { + values: [], + enabled: true, + }; + + _onChange = (event: Event) => { this.props.onChange && this.props.onChange(event); this.props.onValueChange && this.props.onValueChange(event.nativeEvent.value); - }, + }; - render: function() { + render() { + const {forwardedRef, ...props} = this.props; return ( ); - }, -}); + } +} const styles = StyleSheet.create({ segmentedControl: { @@ -141,6 +127,14 @@ const styles = StyleSheet.create({ }, }); -module.exports = ((SegmentedControlIOS: any): Class< - ReactNative.NativeComponent, ->); +// $FlowFixMe - TODO T29156721 `React.forwardRef` is not defined in Flow, yet. +const SegmentedControlIOSWithRef = React.forwardRef( + ( + props: SegmentedControlIOSProps, + forwardedRef: ?React.Ref, + ) => { + return ; + }, +); + +module.exports = (SegmentedControlIOSWithRef: NativeSegmentedControlIOS); diff --git a/Libraries/Components/Slider/Slider.js b/Libraries/Components/Slider/Slider.js index fe37c79b3a47e7..318b9bf50d88eb 100644 --- a/Libraries/Components/Slider/Slider.js +++ b/Libraries/Components/Slider/Slider.js @@ -1,11 +1,11 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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 + * @flow strict-local */ 'use strict'; @@ -21,10 +21,19 @@ import type {ImageSource} from 'ImageSource'; import type {ViewStyleProp} from 'StyleSheet'; import type {ColorValue} from 'StyleSheetTypes'; import type {ViewProps} from 'ViewPropTypes'; +import type {SyntheticEvent} from 'CoreEventTypes'; const RCTSlider = requireNativeComponent('RCTSlider'); -type Event = Object; +type Event = SyntheticEvent< + $ReadOnly<{| + value: number, + /** + * Android Only. + */ + fromUser?: boolean, + |}>, +>; type IOSProps = $ReadOnly<{| /** @@ -66,7 +75,7 @@ type Props = $ReadOnly<{| /** * Used to style and layout the `Slider`. See `StyleSheet.js` and - * `ViewStylePropTypes.js` for more info. + * `DeprecatedViewStylePropTypes.js` for more info. */ style?: ?ViewStyleProp, @@ -118,14 +127,14 @@ type Props = $ReadOnly<{| /** * Callback continuously called while the user is dragging the slider. */ - onValueChange?: ?Function, + onValueChange?: ?(value: number) => void, /** * Callback that is called when the user releases the slider, * regardless if the value has changed. The current value is passed * as an argument to the callback handler. */ - onSlidingComplete?: ?Function, + onSlidingComplete?: ?(value: number) => void, /** * Used to locate this view in UI automation tests. @@ -209,7 +218,8 @@ const Slider = ( if (Platform.OS === 'android') { // On Android there's a special flag telling us the user is // dragging the slider. - userEvent = event.nativeEvent.fromUser; + userEvent = + event.nativeEvent.fromUser != null && event.nativeEvent.fromUser; } props.onValueChange && userEvent && diff --git a/Libraries/Components/StaticContainer.react.js b/Libraries/Components/StaticContainer.react.js index ffba809a46ab72..4772dd4af482cc 100644 --- a/Libraries/Components/StaticContainer.react.js +++ b/Libraries/Components/StaticContainer.react.js @@ -1,11 +1,11 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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 + * @flow strict-local */ 'use strict'; @@ -27,8 +27,19 @@ const React = require('React'); * Typically, you will not need to use this component and should opt for normal * React reconciliation. */ -class StaticContainer extends React.Component { - shouldComponentUpdate(nextProps: Object): boolean { + +type Props = $ReadOnly<{| + /** + * Whether or not this component should update. + */ + shouldUpdate: ?boolean, + /** + * Content short-circuited by React reconciliation process. + */ + children: React.Node, +|}>; +class StaticContainer extends React.Component { + shouldComponentUpdate(nextProps: Props): boolean { return !!nextProps.shouldUpdate; } diff --git a/Libraries/Components/StaticRenderer.js b/Libraries/Components/StaticRenderer.js index 4f8cfbd0989fa8..f4d630d6a98ab0 100644 --- a/Libraries/Components/StaticRenderer.js +++ b/Libraries/Components/StaticRenderer.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. @@ -12,18 +12,20 @@ const React = require('React'); -const PropTypes = require('prop-types'); - -class StaticRenderer extends React.Component<{ +type Props = $ReadOnly<{| + /** + * Indicates whether the render function needs to be called again + */ shouldUpdate: boolean, - render: Function, -}> { - static propTypes = { - shouldUpdate: PropTypes.bool.isRequired, - render: PropTypes.func.isRequired, - }; + /** + * () => renderable + * A function that returns a renderable component + */ + render: () => React.Node, +|}>; - shouldComponentUpdate(nextProps: {shouldUpdate: boolean}): boolean { +class StaticRenderer extends React.Component { + shouldComponentUpdate(nextProps: Props): boolean { return nextProps.shouldUpdate; } diff --git a/Libraries/Components/StatusBar/StatusBar.js b/Libraries/Components/StatusBar/StatusBar.js index 97db49fdd10283..52e6a764d2ca74 100644 --- a/Libraries/Components/StatusBar/StatusBar.js +++ b/Libraries/Components/StatusBar/StatusBar.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. @@ -11,8 +11,6 @@ 'use strict'; const React = require('React'); -const PropTypes = require('prop-types'); -const ColorPropType = require('ColorPropType'); const Platform = require('Platform'); const processColor = require('processColor'); @@ -55,9 +53,55 @@ export type StatusBarAnimation = $Enum<{ slide: string, }>; -type DefaultProps = { - animated: boolean, -}; +type AndroidProps = $ReadOnly<{| + /** + * The background color of the status bar. + * @platform android + */ + backgroundColor?: ?string, + /** + * If the status bar is translucent. + * When translucent is set to true, the app will draw under the status bar. + * This is useful when using a semi transparent status bar color. + * + * @platform android + */ + translucent?: ?boolean, +|}>; + +type IOSProps = $ReadOnly<{| + /** + * If the network activity indicator should be visible. + * + * @platform ios + */ + networkActivityIndicatorVisible?: ?boolean, + /** + * The transition effect when showing and hiding the status bar using the `hidden` + * prop. Defaults to 'fade'. + * + * @platform ios + */ + showHideTransition?: ?('fade' | 'slide'), +|}>; + +type Props = $ReadOnly<{| + ...AndroidProps, + ...IOSProps, + /** + * If the status bar is hidden. + */ + hidden?: ?boolean, + /** + * If the transition between status bar property changes should be animated. + * Supported for backgroundColor, barStyle and hidden. + */ + animated?: ?boolean, + /** + * Sets the color of the status bar text. + */ + barStyle?: ?('default' | 'light-content' | 'dark-content'), +|}>; /** * Merges the prop stack with the default values. @@ -148,15 +192,7 @@ function createStackEntry(props: any): any { * * `currentHeight` (Android only) The height of the status bar. */ -class StatusBar extends React.Component<{ - hidden?: boolean, - animated?: boolean, - backgroundColor?: string, - translucent?: boolean, - barStyle?: 'default' | 'light-content' | 'dark-content', - networkActivityIndicatorVisible?: boolean, - showHideTransition?: 'fade' | 'slide', -}> { +class StatusBar extends React.Component { static _propsStack = []; static _defaultProps = createStackEntry({ @@ -261,48 +297,6 @@ class StatusBar extends React.Component<{ StatusBarManager.setTranslucent(translucent); } - static propTypes = { - /** - * If the status bar is hidden. - */ - hidden: PropTypes.bool, - /** - * If the transition between status bar property changes should be animated. - * Supported for backgroundColor, barStyle and hidden. - */ - animated: PropTypes.bool, - /** - * The background color of the status bar. - * @platform android - */ - backgroundColor: ColorPropType, - /** - * If the status bar is translucent. - * When translucent is set to true, the app will draw under the status bar. - * This is useful when using a semi transparent status bar color. - * - * @platform android - */ - translucent: PropTypes.bool, - /** - * Sets the color of the status bar text. - */ - barStyle: PropTypes.oneOf(['default', 'light-content', 'dark-content']), - /** - * If the network activity indicator should be visible. - * - * @platform ios - */ - networkActivityIndicatorVisible: PropTypes.bool, - /** - * The transition effect when showing and hiding the status bar using the `hidden` - * prop. Defaults to 'fade'. - * - * @platform ios - */ - showHideTransition: PropTypes.oneOf(['fade', 'slide']), - }; - static defaultProps = { animated: false, showHideTransition: 'fade', diff --git a/Libraries/Components/StatusBar/StatusBarIOS.android.js b/Libraries/Components/StatusBar/StatusBarIOS.android.js index 78831fab6d17e7..4e9f97309b29b0 100644 --- a/Libraries/Components/StatusBar/StatusBarIOS.android.js +++ b/Libraries/Components/StatusBar/StatusBarIOS.android.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. diff --git a/Libraries/Components/StatusBar/StatusBarIOS.ios.js b/Libraries/Components/StatusBar/StatusBarIOS.ios.js index ed8ef0f4a1ca11..ea558eafa9ba94 100644 --- a/Libraries/Components/StatusBar/StatusBarIOS.ios.js +++ b/Libraries/Components/StatusBar/StatusBarIOS.ios.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. diff --git a/Libraries/Components/Subscribable.js b/Libraries/Components/Subscribable.js deleted file mode 100644 index a56d42ed864c8d..00000000000000 --- a/Libraries/Components/Subscribable.js +++ /dev/null @@ -1,65 +0,0 @@ -/** - * Copyright (c) 2015-present, Facebook, Inc. - * - * 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 EventEmitter from 'EventEmitter'; - -/** - * Subscribable provides a mixin for safely subscribing a component to an - * eventEmitter - * - * This will be replaced with the observe interface that will be coming soon to - * React Core - */ - -const Subscribable = {}; - -Subscribable.Mixin = { - UNSAFE_componentWillMount: function() { - this._subscribableSubscriptions = []; - }, - - componentWillUnmount: function() { - // This null check is a fix for a broken version of uglify-es. Should be deleted eventually - // https://github.com/facebook/react-native/issues/17348 - this._subscribableSubscriptions && - this._subscribableSubscriptions.forEach(subscription => - subscription.remove(), - ); - this._subscribableSubscriptions = null; - }, - - /** - * Special form of calling `addListener` that *guarantees* that a - * subscription *must* be tied to a component instance, and therefore will - * be cleaned up when the component is unmounted. It is impossible to create - * the subscription and pass it in - this method must be the one to create - * the subscription and therefore can guarantee it is retained in a way that - * will be cleaned up. - * - * @param {EventEmitter} eventEmitter emitter to subscribe to. - * @param {string} eventType Type of event to listen to. - * @param {function} listener Function to invoke when event occurs. - * @param {object} context Object to use as listener context. - */ - addListenerOn: function( - eventEmitter: EventEmitter, - eventType: string, - listener: Function, - context: Object, - ) { - this._subscribableSubscriptions.push( - eventEmitter.addListener(eventType, listener, context), - ); - }, -}; - -module.exports = Subscribable; diff --git a/Libraries/Components/Switch/Switch.js b/Libraries/Components/Switch/Switch.js index 0e11aff4e5e817..80fe6306d7228c 100644 --- a/Libraries/Components/Switch/Switch.js +++ b/Libraries/Components/Switch/Switch.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2013-present, Facebook, Inc. + * 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. @@ -109,7 +109,7 @@ class Switch extends React.Component { _thumbColor = thumbTintColor; if (__DEV__) { console.warn( - 'Switch: `thumbTintColor` is deprecated, use `_thumbColor` instead.', + 'Switch: `thumbTintColor` is deprecated, use `thumbColor` instead.', ); } } diff --git a/Libraries/Components/Switch/SwitchNativeComponent.js b/Libraries/Components/Switch/SwitchNativeComponent.js index a320251744de33..45edc3213568ca 100644 --- a/Libraries/Components/Switch/SwitchNativeComponent.js +++ b/Libraries/Components/Switch/SwitchNativeComponent.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2013-present, Facebook, Inc. + * 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. diff --git a/Libraries/Components/TabBarIOS/TabBarIOS.android.js b/Libraries/Components/TabBarIOS/TabBarIOS.android.js index e8e376f8a9eb7e..81047bfe95d2cb 100644 --- a/Libraries/Components/TabBarIOS/TabBarIOS.android.js +++ b/Libraries/Components/TabBarIOS/TabBarIOS.android.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. @@ -15,9 +15,22 @@ const StyleSheet = require('StyleSheet'); const TabBarItemIOS = require('TabBarItemIOS'); const View = require('View'); +let showedDeprecationWarning = false; + class DummyTabBarIOS extends React.Component<$FlowFixMeProps> { static Item = TabBarItemIOS; + componentDidMount() { + if (!showedDeprecationWarning) { + console.warn( + 'TabBarIOS and TabBarItemIOS are deprecated and will be removed in a future release. ' + + 'Please use react-native-tab-view instead.', + ); + + showedDeprecationWarning = true; + } + } + render() { return ( diff --git a/Libraries/Components/TabBarIOS/TabBarIOS.ios.js b/Libraries/Components/TabBarIOS/TabBarIOS.ios.js index 6cbe213f7fc36d..883ed1bd6e11c3 100644 --- a/Libraries/Components/TabBarIOS/TabBarIOS.ios.js +++ b/Libraries/Components/TabBarIOS/TabBarIOS.ios.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. @@ -10,76 +10,79 @@ 'use strict'; -const ColorPropType = require('ColorPropType'); const React = require('React'); -const PropTypes = require('prop-types'); const StyleSheet = require('StyleSheet'); const TabBarItemIOS = require('TabBarItemIOS'); -const ViewPropTypes = require('ViewPropTypes'); const requireNativeComponent = require('requireNativeComponent'); -import type {DangerouslyImpreciseStyleProp} from 'StyleSheet'; import type {ViewProps} from 'ViewPropTypes'; +import type {ColorValue} from 'StyleSheetTypes'; const RCTTabBar = requireNativeComponent('RCTTabBar'); type Props = $ReadOnly<{| ...ViewProps, - style?: DangerouslyImpreciseStyleProp, - unselectedTintColor?: string, - tintColor?: string, - unselectedItemTintColor?: string, - barTintColor?: string, - barStyle?: 'default' | 'black', - translucent?: boolean, - itemPositioning?: 'fill' | 'center' | 'auto', - children: React.Node, + + /** + * Color of text on unselected tabs + */ + unselectedTintColor?: ColorValue, + + /** + * Color of the currently selected tab icon + */ + tintColor?: ColorValue, + + /** + * Color of unselected tab icons. Available since iOS 10. + */ + unselectedItemTintColor?: ColorValue, + + /** + * Background color of the tab bar + */ + barTintColor?: ColorValue, + + /** + * The style of the tab bar. Supported values are 'default', 'black'. + * Use 'black' instead of setting `barTintColor` to black. This produces + * a tab bar with the native iOS style with higher translucency. + */ + barStyle?: ?('default' | 'black'), + + /** + * A Boolean value that indicates whether the tab bar is translucent + */ + translucent?: ?boolean, + + /** + * Specifies tab bar item positioning. Available values are: + * - fill - distributes items across the entire width of the tab bar + * - center - centers item in the available tab bar space + * - auto (default) - distributes items dynamically according to the + * user interface idiom. In a horizontally compact environment (e.g. iPhone 5) + * this value defaults to `fill`, in a horizontally regular one (e.g. iPad) + * it defaults to center. + */ + itemPositioning?: ?('fill' | 'center' | 'auto'), |}>; +let showedDeprecationWarning = false; + class TabBarIOS extends React.Component { static Item = TabBarItemIOS; - static propTypes = { - ...ViewPropTypes, - style: ViewPropTypes.style, - /** - * Color of text on unselected tabs - */ - unselectedTintColor: ColorPropType, - /** - * Color of the currently selected tab icon - */ - tintColor: ColorPropType, - /** - * Color of unselected tab icons. Available since iOS 10. - */ - unselectedItemTintColor: ColorPropType, - /** - * Background color of the tab bar - */ - barTintColor: ColorPropType, - /** - * The style of the tab bar. Supported values are 'default', 'black'. - * Use 'black' instead of setting `barTintColor` to black. This produces - * a tab bar with the native iOS style with higher translucency. - */ - barStyle: PropTypes.oneOf(['default', 'black']), - /** - * A Boolean value that indicates whether the tab bar is translucent - */ - translucent: PropTypes.bool, - /** - * Specifies tab bar item positioning. Available values are: - * - fill - distributes items across the entire width of the tab bar - * - center - centers item in the available tab bar space - * - auto (default) - distributes items dynamically according to the - * user interface idiom. In a horizontally compact environment (e.g. iPhone 5) - * this value defaults to `fill`, in a horizontally regular one (e.g. iPad) - * it defaults to center. - */ - itemPositioning: PropTypes.oneOf(['fill', 'center', 'auto']), - }; + componentDidMount() { + if (!showedDeprecationWarning) { + console.warn( + 'TabBarIOS and TabBarItemIOS are deprecated and will be removed in a future release. ' + + 'Please use react-native-tab-view instead.', + ); + + showedDeprecationWarning = true; + } + } render() { return ( diff --git a/Libraries/Components/TabBarIOS/TabBarItemIOS.android.js b/Libraries/Components/TabBarIOS/TabBarItemIOS.android.js index 37dc72f4d41faf..424978672f78a2 100644 --- a/Libraries/Components/TabBarIOS/TabBarItemIOS.android.js +++ b/Libraries/Components/TabBarIOS/TabBarItemIOS.android.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. @@ -13,7 +13,20 @@ const React = require('React'); const View = require('View'); const StyleSheet = require('StyleSheet'); +let showedDeprecationWarning = false; + class DummyTab extends React.Component { + componentDidMount() { + if (!showedDeprecationWarning) { + console.warn( + 'TabBarIOS and TabBarItemIOS are deprecated and will be removed in a future release. ' + + 'Please use react-native-tab-view instead.', + ); + + showedDeprecationWarning = true; + } + } + render() { if (!this.props.selected) { return ; diff --git a/Libraries/Components/TabBarIOS/TabBarItemIOS.ios.js b/Libraries/Components/TabBarIOS/TabBarItemIOS.ios.js index b8825977a8cac6..873573ad8a025c 100644 --- a/Libraries/Components/TabBarIOS/TabBarItemIOS.ios.js +++ b/Libraries/Components/TabBarIOS/TabBarItemIOS.ios.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. @@ -10,90 +10,102 @@ 'use strict'; -const ColorPropType = require('ColorPropType'); -const Image = require('Image'); const React = require('React'); -const PropTypes = require('prop-types'); const StaticContainer = require('StaticContainer.react'); const StyleSheet = require('StyleSheet'); const View = require('View'); -const ViewPropTypes = require('ViewPropTypes'); - const requireNativeComponent = require('requireNativeComponent'); -class TabBarItemIOS extends React.Component { - static propTypes = { - ...ViewPropTypes, - /** - * Little red bubble that sits at the top right of the icon. - */ - badge: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), - /** - * Background color for the badge. Available since iOS 10. - */ - badgeColor: ColorPropType, - /** - * Items comes with a few predefined system icons. Note that if you are - * using them, the title and selectedIcon will be overridden with the - * system ones. - */ - systemIcon: PropTypes.oneOf([ - 'bookmarks', - 'contacts', - 'downloads', - 'favorites', - 'featured', - 'history', - 'more', - 'most-recent', - 'most-viewed', - 'recents', - 'search', - 'top-rated', - ]), - /** - * A custom icon for the tab. It is ignored when a system icon is defined. - */ - icon: Image.propTypes.source, - /** - * A custom icon when the tab is selected. It is ignored when a system - * icon is defined. If left empty, the icon will be tinted in blue. - */ - selectedIcon: Image.propTypes.source, - /** - * Callback when this tab is being selected, you should change the state of your - * component to set selected={true}. - */ - onPress: PropTypes.func, - /** - * If set to true it renders the image as original, - * it defaults to being displayed as a template - */ - renderAsOriginal: PropTypes.bool, - /** - * It specifies whether the children are visible or not. If you see a - * blank content, you probably forgot to add a selected one. - */ - selected: PropTypes.bool, - /** - * React style object. - */ - style: ViewPropTypes.style, - /** - * Text that appears under the icon. It is ignored when a system icon - * is defined. - */ - title: PropTypes.string, - /** - *(Apple TV only)* When set to true, this view will be focusable - * and navigable using the Apple TV remote. - * - * @platform ios - */ - isTVSelectable: PropTypes.bool, - }; +import type {ViewProps} from 'ViewPropTypes'; +import type {ColorValue} from 'StyleSheetTypes'; +import type {SyntheticEvent} from 'CoreEventTypes'; +import type {ImageSource} from 'ImageSource'; + +type Props = $ReadOnly<{| + ...ViewProps, + + /** + * Little red bubble that sits at the top right of the icon. + */ + badge?: ?(string | number), + + /** + * Background color for the badge. Available since iOS 10. + */ + badgeColor?: ColorValue, + + /** + * Items comes with a few predefined system icons. Note that if you are + * using them, the title and selectedIcon will be overridden with the + * system ones. + */ + systemIcon?: ?( + | 'bookmarks' + | 'contacts' + | 'downloads' + | 'favorites' + | 'featured' + | 'history' + | 'more' + | 'most-recent' + | 'most-viewed' + | 'recents' + | 'search' + | 'top-rated' + ), + + /** + * A custom icon for the tab. It is ignored when a system icon is defined. + */ + icon?: ?ImageSource, + + /** + * A custom icon when the tab is selected. It is ignored when a system + * icon is defined. If left empty, the icon will be tinted in blue. + */ + selectedIcon?: ?ImageSource, + + /** + * Callback when this tab is being selected, you should change the state of your + * component to set selected={true}. + */ + onPress?: ?(event: SyntheticEvent) => mixed, + + /** + * If set to true it renders the image as original, + * it defaults to being displayed as a template + */ + renderAsOriginal?: ?boolean, + /** + * It specifies whether the children are visible or not. If you see a + * blank content, you probably forgot to add a selected one. + */ + selected?: ?boolean, + + /** + * Text that appears under the icon. It is ignored when a system icon + * is defined. + */ + title?: ?string, + + /** + * *(Apple TV only)* When set to true, this view will be focusable + * and navigable using the Apple TV remote. + * + * @platform ios + */ + isTVSelectable?: ?boolean, +|}>; + +type State = {| + hasBeenSelected: boolean, +|}; + +let showedDeprecationWarning = false; + +class TabBarItemIOS extends React.Component { state = { hasBeenSelected: false, }; @@ -104,25 +116,37 @@ class TabBarItemIOS extends React.Component { } } - UNSAFE_componentWillReceiveProps(nextProps: {selected?: boolean}) { + UNSAFE_componentWillReceiveProps(nextProps: Props) { if (this.state.hasBeenSelected || nextProps.selected) { this.setState({hasBeenSelected: true}); } } + componentDidMount() { + if (!showedDeprecationWarning) { + console.warn( + 'TabBarIOS and TabBarItemIOS are deprecated and will be removed in a future release. ' + + 'Please use react-native-tab-view instead.', + ); + + showedDeprecationWarning = true; + } + } + render() { const {style, children, ...props} = this.props; // if the tab has already been shown once, always continue to show it so we // preserve state between tab transitions + let tabContents; if (this.state.hasBeenSelected) { - var tabContents = ( + tabContents = ( {children} ); } else { - var tabContents = ; + tabContents = ; } return ( diff --git a/Libraries/Components/TextInput/InputAccessoryView.js b/Libraries/Components/TextInput/InputAccessoryView.js index 731476bc7138b7..2e7f906096c3b0 100644 --- a/Libraries/Components/TextInput/InputAccessoryView.js +++ b/Libraries/Components/TextInput/InputAccessoryView.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2013-present, Facebook, Inc. + * 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. @@ -9,15 +9,17 @@ */ 'use strict'; -const ColorPropType = require('ColorPropType'); +const DeprecatedColorPropType = require('DeprecatedColorPropType'); +const Platform = require('Platform'); const React = require('React'); const StyleSheet = require('StyleSheet'); -const ViewPropTypes = require('ViewPropTypes'); const requireNativeComponent = require('requireNativeComponent'); const RCTInputAccessoryView = requireNativeComponent('RCTInputAccessoryView'); +import type {ViewStyleProp} from 'StyleSheet'; + /** * Note: iOS only * @@ -76,20 +78,22 @@ const RCTInputAccessoryView = requireNativeComponent('RCTInputAccessoryView'); * For an example, look at InputAccessoryViewExample.js in RNTester. */ -type Props = { +type Props = $ReadOnly<{| +children: React.Node, /** * An ID which is used to associate this `InputAccessoryView` to * specified TextInput(s). */ - nativeID?: string, - style?: ViewPropTypes.style, - backgroundColor?: ColorPropType, -}; + nativeID?: ?string, + style?: ?ViewStyleProp, + backgroundColor?: ?DeprecatedColorPropType, +|}>; class InputAccessoryView extends React.Component { render(): React.Node { - console.warn(' is not supported on Android yet.'); + if (Platform.OS !== 'ios') { + console.warn(' is only supported on iOS.'); + } if (React.Children.count(this.props.children) === 0) { return null; diff --git a/Libraries/Components/TextInput/TextInput.js b/Libraries/Components/TextInput/TextInput.js index d7d4d8c71e3a2f..c9a7f9a9c5fa9e 100644 --- a/Libraries/Components/TextInput/TextInput.js +++ b/Libraries/Components/TextInput/TextInput.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. @@ -9,32 +9,33 @@ */ 'use strict'; -const ColorPropType = require('ColorPropType'); +const DeprecatedColorPropType = require('DeprecatedColorPropType'); +const DeprecatedViewPropTypes = require('DeprecatedViewPropTypes'); const DocumentSelectionState = require('DocumentSelectionState'); const EventEmitter = require('EventEmitter'); const NativeMethodsMixin = require('NativeMethodsMixin'); const Platform = require('Platform'); -const React = require('React'); -const createReactClass = require('create-react-class'); const PropTypes = require('prop-types'); +const React = require('React'); const ReactNative = require('ReactNative'); const StyleSheet = require('StyleSheet'); const Text = require('Text'); const TextAncestor = require('TextAncestor'); const TextInputState = require('TextInputState'); -const TimerMixin = require('react-timer-mixin'); const TouchableWithoutFeedback = require('TouchableWithoutFeedback'); const UIManager = require('UIManager'); -const ViewPropTypes = require('ViewPropTypes'); +const createReactClass = require('create-react-class'); const emptyFunction = require('fbjs/lib/emptyFunction'); const invariant = require('fbjs/lib/invariant'); const requireNativeComponent = require('requireNativeComponent'); const warning = require('fbjs/lib/warning'); +import type {TextStyleProp, ViewStyleProp} from 'StyleSheet'; import type {ColorValue} from 'StyleSheetTypes'; -import type {TextStyleProp} from 'StyleSheet'; import type {ViewProps} from 'ViewPropTypes'; +import type {SyntheticEvent, ScrollEvent} from 'CoreEventTypes'; +import type {PressEvent} from 'CoreEventTypes'; let AndroidTextInput; let RCTMultilineTextInputView; @@ -64,11 +65,73 @@ const onlyMultiline = { children: true, }; -type Event = Object; -type Selection = { +export type ChangeEvent = SyntheticEvent< + $ReadOnly<{| + eventCount: number, + target: number, + text: string, + |}>, +>; + +export type TextInputEvent = SyntheticEvent< + $ReadOnly<{| + eventCount: number, + previousText: string, + range: $ReadOnly<{| + start: number, + end: number, + |}>, + target: number, + text: string, + |}>, +>; + +export type ContentSizeChangeEvent = SyntheticEvent< + $ReadOnly<{| + target: number, + contentSize: $ReadOnly<{| + width: number, + height: number, + |}>, + |}>, +>; + +type TargetEvent = SyntheticEvent< + $ReadOnly<{| + target: number, + |}>, +>; + +export type BlurEvent = TargetEvent; +export type FocusEvent = TargetEvent; + +type Selection = $ReadOnly<{| start: number, - end?: number, -}; + end: number, +|}>; + +export type SelectionChangeEvent = SyntheticEvent< + $ReadOnly<{| + selection: Selection, + target: number, + |}>, +>; + +export type KeyPressEvent = SyntheticEvent< + $ReadOnly<{| + key: string, + target?: ?number, + eventCount?: ?number, + |}>, +>; + +export type EditingEvent = SyntheticEvent< + $ReadOnly<{| + eventCount: number, + text: string, + target: number, + |}>, +>; const DataDetectorTypes = [ // iOS+macOS @@ -175,7 +238,10 @@ type IOSProps = $ReadOnly<{| | 'telephoneNumber' | 'username' | 'password' + | 'newPassword' + | 'oneTimeCode' ), + scrollEnabled?: ?boolean, |}>; type AndroidProps = $ReadOnly<{| @@ -189,29 +255,30 @@ type AndroidProps = $ReadOnly<{| |}>; type Props = $ReadOnly<{| - ...ViewProps, + ...$Diff>, ...IOSProps, ...AndroidProps, autoCapitalize?: ?AutoCapitalize, autoCorrect?: ?boolean, autoFocus?: ?boolean, allowFontScaling?: ?boolean, + maxFontSizeMultiplier?: ?number, editable?: ?boolean, keyboardType?: ?KeyboardType, returnKeyType?: ?ReturnKeyType, maxLength?: ?number, multiline?: ?boolean, - onBlur?: ?Function, - onFocus?: ?Function, - onChange?: ?Function, - onChangeText?: ?Function, - onContentSizeChange?: ?Function, - onTextInput?: ?Function, - onEndEditing?: ?Function, - onSelectionChange?: ?Function, - onSubmitEditing?: ?Function, - onKeyPress?: ?Function, - onScroll?: ?Function, + onBlur?: ?(e: BlurEvent) => void, + onFocus?: ?(e: FocusEvent) => void, + onChange?: ?(e: ChangeEvent) => void, + onChangeText?: ?(text: string) => void, + onContentSizeChange?: ?(e: ContentSizeChangeEvent) => void, + onTextInput?: ?(e: TextInputEvent) => void, + onEndEditing?: ?(e: EditingEvent) => void, + onSelectionChange?: ?(e: SelectionChangeEvent) => void, + onSubmitEditing?: ?(e: EditingEvent) => void, + onKeyPress?: ?(e: KeyPressEvent) => void, + onScroll?: ?(e: ScrollEvent) => void, placeholder?: ?Stringish, placeholderTextColor?: ?ColorValue, secureTextEntry?: ?boolean, @@ -351,7 +418,7 @@ const TextInput = createReactClass({ }, }, propTypes: { - ...ViewPropTypes, + ...DeprecatedViewPropTypes, /** * Can tell `TextInput` to automatically capitalize certain characters. * @@ -386,6 +453,14 @@ const TextInput = createReactClass({ * default is `true`. */ allowFontScaling: PropTypes.bool, + /** + * Specifies largest possible scale a font can reach when `allowFontScaling` is enabled. + * Possible values: + * `null/undefined` (default): inherit from the parent node or the global default (0) + * `0`: no max, ignore parent/global default + * `>= 1`: sets the maxFontSizeMultiplier of this node to this value + */ + maxFontSizeMultiplier: PropTypes.number, /** * If `false`, text is not editable. The default value is `true`. */ @@ -600,7 +675,13 @@ const TextInput = createReactClass({ /** * The text color of the placeholder string. */ - placeholderTextColor: ColorPropType, + placeholderTextColor: DeprecatedColorPropType, + /** + * If `false`, scrolling of the text view will be disabled. + * The default value is `true`. Does only work with 'multiline={true}'. + * @platform ios + */ + scrollEnabled: PropTypes.bool, /** * If `false`, scrolling of the text view will be disabled. * The default value is `true`. Does only work with 'multiline={true}'. @@ -615,7 +696,7 @@ const TextInput = createReactClass({ /** * The highlight and cursor color of the text input. */ - selectionColor: ColorPropType, + selectionColor: DeprecatedColorPropType, /** * An instance of `DocumentSelectionState`, this is some state that is responsible for * maintaining selection information for a document. @@ -707,7 +788,7 @@ const TextInput = createReactClass({ * The color of the `TextInput` underline. * @platform android */ - underlineColorAndroid: ColorPropType, + underlineColorAndroid: DeprecatedColorPropType, /** * If defined, the provided image resource will be rendered on the left. @@ -818,9 +899,11 @@ const TextInput = createReactClass({ 'telephoneNumber', 'username', 'password', + 'newPassword', + 'oneTimeCode', ]), }, - getDefaultProps(): Object { + getDefaultProps() { return { allowFontScaling: true, underlineColorAndroid: 'transparent', @@ -830,7 +913,7 @@ const TextInput = createReactClass({ * `NativeMethodsMixin` will look for this when invoking `setNativeProps`. We * make `this` look like an actual native component class. */ - mixins: [NativeMethodsMixin, TimerMixin], + mixins: [NativeMethodsMixin], /** * Returns `true` if the input is currently focused; `false` otherwise. @@ -854,6 +937,7 @@ const TextInput = createReactClass({ _focusSubscription: (undefined: ?Function), _lastNativeText: (undefined: ?string), _lastNativeSelection: (undefined: ?Selection), + _rafId: (null: ?AnimationFrameID), componentDidMount: function() { this._lastNativeText = this.props.value; @@ -868,7 +952,7 @@ const TextInput = createReactClass({ 'focus', el => { if (this === el) { - this.requestAnimationFrame(this.focus); + this._rafId = requestAnimationFrame(this.focus); } else if (this.isFocused()) { this.blur(); } @@ -879,7 +963,7 @@ const TextInput = createReactClass({ } } else { if (this.props.autoFocus) { - this.requestAnimationFrame(this.focus); + this._rafId = requestAnimationFrame(this.focus); } } }, @@ -893,6 +977,9 @@ const TextInput = createReactClass({ if (tag != null) { TextInputState.unregisterInput(tag); } + if (this._rafId != null) { + cancelAnimationFrame(this._rafId); + } }, contextTypes: { @@ -911,7 +998,7 @@ const TextInput = createReactClass({ let textInput; if (Platform.OS === 'ios' || Platform.OS === 'macos') { // TODO(macOS ISS#2323203) - textInput = UIManager.RCTVirtualText + textInput = UIManager.getViewManagerConfig('RCTVirtualText') ? this._renderIOS() : this._renderIOSLegacy(); } else if (Platform.OS === 'android') { @@ -985,7 +1072,10 @@ const TextInput = createReactClass({ ); if (childCount >= 1) { children = ( - + {children} ); @@ -1085,10 +1175,9 @@ const TextInput = createReactClass({ _renderAndroid: function() { const props = Object.assign({}, this.props); props.style = [this.props.style]; - props.autoCapitalize = - UIManager.AndroidTextInput.Constants.AutoCapitalizationType[ - props.autoCapitalize || 'sentences' - ]; + props.autoCapitalize = UIManager.getViewManagerConfig( + 'AndroidTextInput', + ).Constants.AutoCapitalizationType[props.autoCapitalize || 'sentences']; /* $FlowFixMe(>=0.53.0 site=react_native_fb,react_native_oss) This comment * suppresses an error when upgrading Flow's support for React. To see the * error delete this comment and run Flow. */ @@ -1158,7 +1247,7 @@ const TextInput = createReactClass({ ); }, // ]TODO(windows ISS) - _onFocus: function(event: Event) { + _onFocus: function(event: FocusEvent) { // [TODO(android ISS) // Set the focused TextInput field info in TextInputState. // Delaying this to onFocus native event ensures that - @@ -1177,16 +1266,16 @@ const TextInput = createReactClass({ } }, - _onPress: function(event: Event) { + _onPress: function(event: PressEvent) { if (this.props.editable || this.props.editable === undefined) { this.focus(); } }, - _onChange: function(event: Event) { + _onChange: function(event: ChangeEvent) { // Make sure to fire the mostRecentEventCount first so it is already set on // native when the text value is set. - if (this._inputRef) { + if (this._inputRef && this._inputRef.setNativeProps) { this._inputRef.setNativeProps({ mostRecentEventCount: event.nativeEvent.eventCount, }); @@ -1206,7 +1295,7 @@ const TextInput = createReactClass({ this.forceUpdate(); }, - _onSelectionChange: function(event: Event) { + _onSelectionChange: function(event: SelectionChangeEvent) { this.props.onSelectionChange && this.props.onSelectionChange(event); if (!this._inputRef) { @@ -1247,7 +1336,11 @@ const TextInput = createReactClass({ nativeProps.selection = this.props.selection; } - if (Object.keys(nativeProps).length > 0 && this._inputRef) { + if ( + Object.keys(nativeProps).length > 0 && + this._inputRef && + this._inputRef.setNativeProps + ) { this._inputRef.setNativeProps(nativeProps); } @@ -1266,6 +1359,10 @@ const TextInput = createReactClass({ TextInputState.clearFocusedTextInput( ReactNative.findNodeHandle(this._inputRef), ); // ]TODO(android ISS) + + // This is a hack to fix https://fburl.com/toehyir8 + // @todo(rsnara) Figure out why this is necessary. + this.blur(); if (this.props.onBlur) { this.props.onBlur(event); } @@ -1275,11 +1372,11 @@ const TextInput = createReactClass({ } }, - _onTextInput: function(event: Event) { + _onTextInput: function(event: TextInputEvent) { this.props.onTextInput && this.props.onTextInput(event); }, - _onScroll: function(event: Event) { + _onScroll: function(event: ScrollEvent) { this.props.onScroll && this.props.onScroll(event); }, }); diff --git a/Libraries/Components/TextInput/TextInputState.js b/Libraries/Components/TextInput/TextInputState.js index b1a28cee149c75..36107f6cf99908 100644 --- a/Libraries/Components/TextInput/TextInputState.js +++ b/Libraries/Components/TextInput/TextInputState.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. @@ -45,7 +45,8 @@ function focusTextInput(textFieldID: ?number) { } else if (Platform.OS === 'android') { UIManager.dispatchViewManagerCommand( textFieldID, - UIManager.AndroidTextInput.Commands.focusTextInput, + UIManager.getViewManagerConfig('AndroidTextInput').Commands + .focusTextInput, null, ); } else if (Platform.OS === 'win32') { @@ -74,7 +75,8 @@ function blurTextInput(textFieldID: ?number) { } else if (Platform.OS === 'android') { UIManager.dispatchViewManagerCommand( textFieldID, - UIManager.AndroidTextInput.Commands.blurTextInput, + UIManager.getViewManagerConfig('AndroidTextInput').Commands + .blurTextInput, null, ); } else if (Platform.OS === 'win32') { diff --git a/Libraries/Components/TextInput/__tests__/TextInput-test.js b/Libraries/Components/TextInput/__tests__/TextInput-test.js new file mode 100644 index 00000000000000..78d6884db03395 --- /dev/null +++ b/Libraries/Components/TextInput/__tests__/TextInput-test.js @@ -0,0 +1,70 @@ +/** + * 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. + * + * @emails oncall+react_native + * @format + * @flow-strict + */ + +'use strict'; + +const React = require('React'); +const ReactTestRenderer = require('react-test-renderer'); +const TextInput = require('TextInput'); + +import Component from '@reactions/component'; + +const {enter} = require('ReactNativeTestTools'); + +jest.unmock('TextInput'); + +describe('TextInput tests', () => { + let input; + let onChangeListener; + let onChangeTextListener; + const initialValue = 'initialValue'; + beforeEach(() => { + onChangeListener = jest.fn(); + onChangeTextListener = jest.fn(); + const renderTree = ReactTestRenderer.create( + + {({setState, state}) => ( + { + onChangeTextListener(text); + setState({text}); + }} + onChange={event => { + onChangeListener(event); + }} + /> + )} + , + ); + input = renderTree.root.findByType(TextInput); + }); + it('has expected instance functions', () => { + expect(input.instance.isFocused).toBeInstanceOf(Function); // Would have prevented S168585 + expect(input.instance.clear).toBeInstanceOf(Function); + expect(input.instance.focus).toBeInstanceOf(Function); + expect(input.instance.blur).toBeInstanceOf(Function); + expect(input.instance.setNativeProps).toBeInstanceOf(Function); + expect(input.instance.measure).toBeInstanceOf(Function); + expect(input.instance.measureInWindow).toBeInstanceOf(Function); + expect(input.instance.measureLayout).toBeInstanceOf(Function); + }); + it('calls onChange callbacks', () => { + expect(input.props.value).toBe(initialValue); + const message = 'This is a test message'; + enter(input, message); + expect(input.props.value).toBe(message); + expect(onChangeTextListener).toHaveBeenCalledWith(message); + expect(onChangeListener).toHaveBeenCalledWith({ + nativeEvent: {text: message}, + }); + }); +}); diff --git a/Libraries/Components/TimePickerAndroid/TimePickerAndroid.android.js b/Libraries/Components/TimePickerAndroid/TimePickerAndroid.android.js index 6cdd964cc8cea2..87c44621dc089b 100644 --- a/Libraries/Components/TimePickerAndroid/TimePickerAndroid.android.js +++ b/Libraries/Components/TimePickerAndroid/TimePickerAndroid.android.js @@ -1,17 +1,22 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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 + * @flow strict-local */ 'use strict'; const TimePickerModule = require('NativeModules').TimePickerAndroid; +import type { + TimePickerOptions, + TimePickerResult, +} from './TimePickerAndroidTypes'; + /** * Opens the standard Android time picker dialog. * @@ -52,22 +57,18 @@ class TimePickerAndroid { * still be resolved with action being `TimePickerAndroid.dismissedAction` and all the other keys * being undefined. **Always** check whether the `action` before reading the values. */ - static async open(options: Object): Promise { + static async open(options: TimePickerOptions): Promise { return TimePickerModule.open(options); } /** * A time has been selected. */ - static get timeSetAction() { - return 'timeSetAction'; - } + static +timeSetAction: 'timeSetAction' = 'timeSetAction'; /** * The dialog has been dismissed. */ - static get dismissedAction() { - return 'dismissedAction'; - } + static +dismissedAction: 'dismissedAction' = 'dismissedAction'; } module.exports = TimePickerAndroid; diff --git a/Libraries/Components/TimePickerAndroid/TimePickerAndroid.ios.js b/Libraries/Components/TimePickerAndroid/TimePickerAndroid.ios.js index 6a0ecfa656313c..59ec50eb27260c 100644 --- a/Libraries/Components/TimePickerAndroid/TimePickerAndroid.ios.js +++ b/Libraries/Components/TimePickerAndroid/TimePickerAndroid.ios.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. diff --git a/Libraries/Components/TimePickerAndroid/TimePickerAndroidTypes.js b/Libraries/Components/TimePickerAndroid/TimePickerAndroidTypes.js new file mode 100644 index 00000000000000..aafa572be6c052 --- /dev/null +++ b/Libraries/Components/TimePickerAndroid/TimePickerAndroidTypes.js @@ -0,0 +1,24 @@ +/** + * 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 strict-local + */ + +'use strict'; + +export type TimePickerOptions = {| + hour?: number, + minute?: number, + is24Hour?: boolean, + mode?: 'clock' | 'spinner' | 'default', +|}; + +export type TimePickerResult = $ReadOnly<{| + action: string, + hour: number, + minute: number, +|}>; diff --git a/Libraries/Components/ToastAndroid/ToastAndroid.android.js b/Libraries/Components/ToastAndroid/ToastAndroid.android.js index c661adf503565d..832887453c3fc0 100644 --- a/Libraries/Components/ToastAndroid/ToastAndroid.android.js +++ b/Libraries/Components/ToastAndroid/ToastAndroid.android.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. diff --git a/Libraries/Components/ToastAndroid/ToastAndroid.ios.js b/Libraries/Components/ToastAndroid/ToastAndroid.ios.js index adb6032ef6731b..ed5fcf02f40116 100644 --- a/Libraries/Components/ToastAndroid/ToastAndroid.ios.js +++ b/Libraries/Components/ToastAndroid/ToastAndroid.ios.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. diff --git a/Libraries/Components/ToolbarAndroid/ToolbarAndroid.android.js b/Libraries/Components/ToolbarAndroid/ToolbarAndroid.android.js index 44bcfc03d8046e..aa92f9cc9bd250 100644 --- a/Libraries/Components/ToolbarAndroid/ToolbarAndroid.android.js +++ b/Libraries/Components/ToolbarAndroid/ToolbarAndroid.android.js @@ -1,32 +1,26 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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'; -const Image = require('Image'); -const NativeMethodsMixin = require('NativeMethodsMixin'); const React = require('React'); -const PropTypes = require('prop-types'); const UIManager = require('UIManager'); -const ViewPropTypes = require('ViewPropTypes'); -const ColorPropType = require('ColorPropType'); -const createReactClass = require('create-react-class'); const requireNativeComponent = require('requireNativeComponent'); const resolveAssetSource = require('resolveAssetSource'); -const optionalImageSource = PropTypes.oneOfType([ - Image.propTypes.source, - // Image.propTypes.source is required but we want it to be optional, so we OR - // it with a nullable propType. - PropTypes.oneOf([]), -]); +import type {SyntheticEvent} from 'CoreEventTypes'; +import type {ImageSource} from 'ImageSource'; +import type {ColorValue} from 'StyleSheetTypes'; +import type {ViewProps} from 'ViewPropTypes'; +import type {NativeComponent} from 'ReactNative'; /** * React component that wraps the Android-only [`Toolbar` widget][0]. A Toolbar can display a logo, @@ -63,149 +57,195 @@ const optionalImageSource = PropTypes.oneOfType([ * * [0]: https://developer.android.com/reference/android/support/v7/widget/Toolbar.html */ -const ToolbarAndroid = createReactClass({ - displayName: 'ToolbarAndroid', - mixins: [NativeMethodsMixin], - - propTypes: { - ...ViewPropTypes, - /** - * Sets possible actions on the toolbar as part of the action menu. These are displayed as icons - * or text on the right side of the widget. If they don't fit they are placed in an 'overflow' - * menu. - * - * This property takes an array of objects, where each object has the following keys: - * - * * `title`: **required**, the title of this action - * * `icon`: the icon for this action, e.g. `require('./some_icon.png')` - * * `show`: when to show this action as an icon or hide it in the overflow menu: `always`, - * `ifRoom` or `never` - * * `showWithText`: boolean, whether to show text alongside the icon or not - */ - actions: PropTypes.arrayOf( - PropTypes.shape({ - title: PropTypes.string.isRequired, - icon: optionalImageSource, - show: PropTypes.oneOf(['always', 'ifRoom', 'never']), - showWithText: PropTypes.bool, - }), - ), - /** - * Sets the toolbar logo. - */ - logo: optionalImageSource, - /** - * Sets the navigation icon. - */ - navIcon: optionalImageSource, - /** - * Callback that is called when an action is selected. The only argument that is passed to the - * callback is the position of the action in the actions array. - */ - onActionSelected: PropTypes.func, - /** - * Callback called when the icon is selected. - */ - onIconClicked: PropTypes.func, - /** - * Sets the overflow icon. - */ - overflowIcon: optionalImageSource, - /** - * Sets the toolbar subtitle. - */ - subtitle: PropTypes.string, - /** - * Sets the toolbar subtitle color. - */ - subtitleColor: ColorPropType, - /** - * Sets the toolbar title. - */ - title: PropTypes.string, - /** - * Sets the toolbar title color. - */ - titleColor: ColorPropType, - /** - * Sets the content inset for the toolbar starting edge. - * - * The content inset affects the valid area for Toolbar content other than - * the navigation button and menu. Insets define the minimum margin for - * these components and can be used to effectively align Toolbar content - * along well-known gridlines. - */ - contentInsetStart: PropTypes.number, - /** - * Sets the content inset for the toolbar ending edge. - * - * The content inset affects the valid area for Toolbar content other than - * the navigation button and menu. Insets define the minimum margin for - * these components and can be used to effectively align Toolbar content - * along well-known gridlines. - */ - contentInsetEnd: PropTypes.number, - /** - * Used to set the toolbar direction to RTL. - * In addition to this property you need to add - * - * android:supportsRtl="true" - * - * to your application AndroidManifest.xml and then call - * `setLayoutDirection(LayoutDirection.RTL)` in your MainActivity - * `onCreate` method. - */ - rtl: PropTypes.bool, - /** - * Used to locate this view in end-to-end tests. - */ - testID: PropTypes.string, - }, - render: function() { - const nativeProps = { - ...this.props, +const NativeToolbar = requireNativeComponent('ToolbarAndroid'); + +type Action = $ReadOnly<{| + title: string, + icon?: ?ImageSource, + show?: 'always' | 'ifRoom' | 'never', + showWithText?: boolean, +|}>; + +type ToolbarAndroidChangeEvent = SyntheticEvent< + $ReadOnly<{| + position: number, + |}>, +>; + +type ToolbarAndroidProps = $ReadOnly<{| + ...ViewProps, + /** + * or text on the right side of the widget. If they don't fit they are placed in an 'overflow' + * Sets possible actions on the toolbar as part of the action menu. These are displayed as icons + * menu. + * + * This property takes an array of objects, where each object has the following keys: + * + * * `title`: **required**, the title of this action + * * `icon`: the icon for this action, e.g. `require('./some_icon.png')` + * * `show`: when to show this action as an icon or hide it in the overflow menu: `always`, + * `ifRoom` or `never` + * * `showWithText`: boolean, whether to show text alongside the icon or not + */ + actions?: ?Array, + /** + * Sets the toolbar logo. + */ + logo?: ?ImageSource, + /** + * Sets the navigation icon. + */ + navIcon?: ?ImageSource, + /** + * Callback that is called when an action is selected. The only argument that is passed to the + * callback is the position of the action in the actions array. + */ + onActionSelected?: ?(position: number) => void, + /** + * Callback called when the icon is selected. + */ + onIconClicked?: ?() => void, + /** + * Sets the overflow icon. + */ + overflowIcon?: ?ImageSource, + /** + * Sets the toolbar subtitle. + */ + subtitle?: ?string, + /** + * Sets the toolbar subtitle color. + */ + subtitleColor?: ?ColorValue, + /** + * Sets the toolbar title. + */ + title?: ?Stringish, + /** + * Sets the toolbar title color. + */ + titleColor?: ?ColorValue, + /** + * Sets the content inset for the toolbar starting edge. + * + * The content inset affects the valid area for Toolbar content other than + * the navigation button and menu. Insets define the minimum margin for + * these components and can be used to effectively align Toolbar content + * along well-known gridlines. + */ + contentInsetStart?: ?number, + /** + * Sets the content inset for the toolbar ending edge. + * + * The content inset affects the valid area for Toolbar content other than + * the navigation button and menu. Insets define the minimum margin for + * these components and can be used to effectively align Toolbar content + * along well-known gridlines. + */ + contentInsetEnd?: ?number, + /** + * Used to set the toolbar direction to RTL. + * In addition to this property you need to add + * + * android:supportsRtl="true" + * + * to your application AndroidManifest.xml and then call + * `setLayoutDirection(LayoutDirection.RTL)` in your MainActivity + * `onCreate` method. + */ + rtl?: ?boolean, + /** + * Used to locate this view in end-to-end tests. + */ + testID?: ?string, +|}>; + +type Props = $ReadOnly<{| + ...ToolbarAndroidProps, + forwardedRef: ?React.Ref, +|}>; + +class ToolbarAndroid extends React.Component { + _onSelect = (event: ToolbarAndroidChangeEvent) => { + const position = event.nativeEvent.position; + if (position === -1) { + this.props.onIconClicked && this.props.onIconClicked(); + } else { + this.props.onActionSelected && this.props.onActionSelected(position); + } + }; + + render() { + const { + onIconClicked, + onActionSelected, + forwardedRef, + ...otherProps + } = this.props; + + const nativeProps: {...typeof otherProps, nativeActions?: Array} = { + ...otherProps, }; + if (this.props.logo) { nativeProps.logo = resolveAssetSource(this.props.logo); } + if (this.props.navIcon) { nativeProps.navIcon = resolveAssetSource(this.props.navIcon); } + if (this.props.overflowIcon) { nativeProps.overflowIcon = resolveAssetSource(this.props.overflowIcon); } + if (this.props.actions) { const nativeActions = []; for (let i = 0; i < this.props.actions.length; i++) { const action = { - ...this.props.actions[i], + icon: this.props.actions[i].icon, + show: this.props.actions[i].show, }; + if (action.icon) { action.icon = resolveAssetSource(action.icon); } if (action.show) { - action.show = - UIManager.ToolbarAndroid.Constants.ShowAsAction[action.show]; + action.show = UIManager.getViewManagerConfig( + 'ToolbarAndroid', + ).Constants.ShowAsAction[action.show]; } - nativeActions.push(action); + + nativeActions.push({ + ...this.props.actions[i], + ...action, + }); } + nativeProps.nativeActions = nativeActions; } - return ; - }, + return ( + + ); + } +} - _onSelect: function(event) { - const position = event.nativeEvent.position; - if (position === -1) { - this.props.onIconClicked && this.props.onIconClicked(); - } else { - this.props.onActionSelected && this.props.onActionSelected(position); - } +// $FlowFixMe - TODO T29156721 `React.forwardRef` is not defined in Flow, yet. +const ToolbarAndroidToExport = React.forwardRef( + ( + props: ToolbarAndroidProps, + forwardedRef: ?React.Ref, + ) => { + return ; }, -}); - -const NativeToolbar = requireNativeComponent('ToolbarAndroid'); +); -module.exports = ToolbarAndroid; +module.exports = (ToolbarAndroidToExport: Class< + NativeComponent, +>); diff --git a/Libraries/Components/ToolbarAndroid/ToolbarAndroid.ios.js b/Libraries/Components/ToolbarAndroid/ToolbarAndroid.ios.js index 260d559929796f..7a00b6636cf664 100644 --- a/Libraries/Components/ToolbarAndroid/ToolbarAndroid.ios.js +++ b/Libraries/Components/ToolbarAndroid/ToolbarAndroid.ios.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. diff --git a/Libraries/Components/Touchable/BoundingDimensions.js b/Libraries/Components/Touchable/BoundingDimensions.js index 755da5ab8937aa..28622a5b2da7f1 100644 --- a/Libraries/Components/Touchable/BoundingDimensions.js +++ b/Libraries/Components/Touchable/BoundingDimensions.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. diff --git a/Libraries/Components/Touchable/PooledClass.js b/Libraries/Components/Touchable/PooledClass.js index a6934facae7049..0d6168a3fa51cf 100644 --- a/Libraries/Components/Touchable/PooledClass.js +++ b/Libraries/Components/Touchable/PooledClass.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2013-present, Facebook, Inc. + * 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. diff --git a/Libraries/Components/Touchable/Position.js b/Libraries/Components/Touchable/Position.js index 19899d74c49820..bc6a45cc6c6a1f 100644 --- a/Libraries/Components/Touchable/Position.js +++ b/Libraries/Components/Touchable/Position.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. diff --git a/Libraries/Components/Touchable/Touchable.js b/Libraries/Components/Touchable/Touchable.js index 3f1874c8aac4a4..5383de2da4ef8f 100644 --- a/Libraries/Components/Touchable/Touchable.js +++ b/Libraries/Components/Touchable/Touchable.js @@ -1,9 +1,10 @@ /** - * Copyright (c) 2013-present, Facebook, Inc. + * 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. * + * @flow * @format */ @@ -14,6 +15,7 @@ const Platform = require('Platform'); const Position = require('Position'); const React = require('React'); const ReactNative = require('ReactNative'); +const StyleSheet = require('StyleSheet'); const TVEventHandler = require('TVEventHandler'); const TouchEventUtils = require('fbjs/lib/TouchEventUtils'); const UIManager = require('UIManager'); @@ -22,6 +24,9 @@ const View = require('View'); const keyMirror = require('fbjs/lib/keyMirror'); const normalizeColor = require('normalizeColor'); +import type {PressEvent} from 'CoreEventTypes'; +import type {EdgeInsetsProp} from 'EdgeInsetsPropType'; + /** * `Touchable`: Taps done right. * @@ -110,6 +115,7 @@ const normalizeColor = require('normalizeColor'); /** * Touchable states. */ + const States = keyMirror({ NOT_RESPONDER: null, // Not the responder RESPONDER_INACTIVE_PRESS_IN: null, // Responder, inactive, in the `PressRect` @@ -121,10 +127,33 @@ const States = keyMirror({ ERROR: null, }); -/** +type State = + | typeof States.NOT_RESPONDER + | typeof States.RESPONDER_INACTIVE_PRESS_IN + | typeof States.RESPONDER_INACTIVE_PRESS_OUT + | typeof States.RESPONDER_ACTIVE_PRESS_IN + | typeof States.RESPONDER_ACTIVE_PRESS_OUT + | typeof States.RESPONDER_ACTIVE_LONG_PRESS_IN + | typeof States.RESPONDER_ACTIVE_LONG_PRESS_OUT + | typeof States.ERROR; + +/* * Quick lookup map for states that are considered to be "active" */ + +const baseStatesConditions = { + NOT_RESPONDER: false, + RESPONDER_INACTIVE_PRESS_IN: false, + RESPONDER_INACTIVE_PRESS_OUT: false, + RESPONDER_ACTIVE_PRESS_IN: false, + RESPONDER_ACTIVE_PRESS_OUT: false, + RESPONDER_ACTIVE_LONG_PRESS_IN: false, + RESPONDER_ACTIVE_LONG_PRESS_OUT: false, + ERROR: false, +}; + const IsActive = { + ...baseStatesConditions, RESPONDER_ACTIVE_PRESS_OUT: true, RESPONDER_ACTIVE_PRESS_IN: true, }; @@ -134,12 +163,14 @@ const IsActive = { * therefore eligible to result in a "selection" if the press stops. */ const IsPressingIn = { + ...baseStatesConditions, RESPONDER_INACTIVE_PRESS_IN: true, RESPONDER_ACTIVE_PRESS_IN: true, RESPONDER_ACTIVE_LONG_PRESS_IN: true, }; const IsLongPressingIn = { + ...baseStatesConditions, RESPONDER_ACTIVE_LONG_PRESS_IN: true, }; @@ -156,6 +187,15 @@ const Signals = keyMirror({ LONG_PRESS_DETECTED: null, }); +type Signal = + | typeof Signals.DELAY + | typeof Signals.RESPONDER_GRANT + | typeof Signals.RESPONDER_RELEASE + | typeof Signals.RESPONDER_TERMINATED + | typeof Signals.ENTER_PRESS_RECT + | typeof Signals.LEAVE_PRESS_RECT + | typeof Signals.LONG_PRESS_DETECTED; + /** * Mapping from States x Signals => States */ @@ -390,7 +430,7 @@ const TouchableMixin = { * @param {SyntheticEvent} e Synthetic event from event system. * */ - touchableHandleResponderGrant: function(e) { + touchableHandleResponderGrant: function(e: PressEvent) { const dispatchID = e.currentTarget; // Since e is used in a callback invoked on another event loop // (as in setTimeout etc), we need to call e.persist() on the @@ -431,21 +471,21 @@ const TouchableMixin = { /** * Place as callback for a DOM element's `onResponderRelease` event. */ - touchableHandleResponderRelease: function(e) { + touchableHandleResponderRelease: function(e: PressEvent) { this._receiveSignal(Signals.RESPONDER_RELEASE, e); }, /** * Place as callback for a DOM element's `onResponderTerminate` event. */ - touchableHandleResponderTerminate: function(e) { + touchableHandleResponderTerminate: function(e: PressEvent) { this._receiveSignal(Signals.RESPONDER_TERMINATED, e); }, /** * Place as callback for a DOM element's `onResponderMove` event. */ - touchableHandleResponderMove: function(e) { + touchableHandleResponderMove: function(e: PressEvent) { // Not enough time elapsed yet, wait for highlight - // this is just a perf optimization. if ( @@ -632,7 +672,14 @@ const TouchableMixin = { UIManager.measure(tag, this._handleQueryLayout); }, - _handleQueryLayout: function(l, t, w, h, globalX, globalY) { + _handleQueryLayout: function( + l: number, + t: number, + w: number, + h: number, + globalX: number, + globalY: number, + ) { //don't do anything UIManager failed to measure node if (!l && !t && !w && !h && !globalX && !globalY) { return; @@ -651,12 +698,12 @@ const TouchableMixin = { ); }, - _handleDelay: function(e) { + _handleDelay: function(e: PressEvent) { this.touchableDelayTimeout = null; this._receiveSignal(Signals.DELAY, e); }, - _handleLongDelay: function(e) { + _handleLongDelay: function(e: PressEvent) { this.longPressDelayTimeout = null; const curState = this.state.touchable.touchState; if ( @@ -684,7 +731,7 @@ const TouchableMixin = { * @throws Error if invalid state transition or unrecognized signal. * @sideeffects */ - _receiveSignal: function(signal, e) { + _receiveSignal: function(signal: Signal, e: PressEvent) { const responderID = this.state.touchable.responderID; const curState = this.state.touchable.touchState; const nextState = Transitions[curState] && Transitions[curState][signal]; @@ -724,14 +771,14 @@ const TouchableMixin = { this.longPressDelayTimeout = null; }, - _isHighlight: function(state) { + _isHighlight: function(state: State) { return ( state === States.RESPONDER_ACTIVE_PRESS_IN || state === States.RESPONDER_ACTIVE_LONG_PRESS_IN ); }, - _savePressInLocation: function(e) { + _savePressInLocation: function(e: PressEvent) { const touch = TouchEventUtils.extractSingleTouch(e.nativeEvent); const pageX = touch && touch.pageX; const pageY = touch && touch.pageY; @@ -740,7 +787,12 @@ const TouchableMixin = { this.pressInLocation = {pageX, pageY, locationX, locationY}; }, - _getDistanceBetweenPoints: function(aX, aY, bX, bY) { + _getDistanceBetweenPoints: function( + aX: number, + aY: number, + bX: number, + bY: number, + ) { const deltaX = aX - bX; const deltaY = aY - bY; return Math.sqrt(deltaX * deltaX + deltaY * deltaY); @@ -757,7 +809,12 @@ const TouchableMixin = { * @param {Event} e Native event. * @sideeffects */ - _performSideEffectsForTransition: function(curState, nextState, signal, e) { + _performSideEffectsForTransition: function( + curState: State, + nextState: State, + signal: Signal, + e: PressEvent, + ) { const curIsHighlight = this._isHighlight(curState); const newIsHighlight = this._isHighlight(nextState); @@ -812,12 +869,12 @@ const TouchableMixin = { UIManager.playTouchSound(); }, - _startHighlight: function(e) { + _startHighlight: function(e: PressEvent) { this._savePressInLocation(e); this.touchableHandleActivePressIn && this.touchableHandleActivePressIn(e); }, - _endHighlight: function(e) { + _endHighlight: function(e: PressEvent) { if (this.touchableHandleActivePressOut) { if ( this.touchableGetPressOutDelayMS && @@ -839,7 +896,13 @@ const Touchable = { /** * Renders a debugging overlay to visualize touch target with hitSlop (might not work on Android). */ - renderDebugView: ({color, hitSlop}) => { + renderDebugView: ({ + color, + hitSlop, + }: { + color: string | number, + hitSlop: EdgeInsetsProp, + }) => { if (!Touchable.TOUCH_TARGET_DEBUG) { return null; } @@ -853,22 +916,34 @@ const Touchable = { for (const key in hitSlop) { debugHitSlopStyle[key] = -hitSlop[key]; } + const normalizedColor = normalizeColor(color); + if (typeof normalizedColor !== 'number') { + return null; + } const hexColor = - '#' + ('00000000' + normalizeColor(color).toString(16)).substr(-8); + '#' + ('00000000' + normalizedColor.toString(16)).substr(-8); return ( ); }, }; +const styles = StyleSheet.create({ + debug: { + position: 'absolute', + borderWidth: 1, + borderStyle: 'dashed', + }, +}); + module.exports = Touchable; diff --git a/Libraries/Components/Touchable/TouchableBounce.js b/Libraries/Components/Touchable/TouchableBounce.js index 89b0f9747a0147..25e0b9c4df8249 100644 --- a/Libraries/Components/Touchable/TouchableBounce.js +++ b/Libraries/Components/Touchable/TouchableBounce.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. @@ -10,20 +10,20 @@ 'use strict'; const Animated = require('Animated'); -const EdgeInsetsPropType = require('EdgeInsetsPropType'); +const DeprecatedViewPropTypes = require('DeprecatedViewPropTypes'); +const DeprecatedEdgeInsetsPropType = require('DeprecatedEdgeInsetsPropType'); const NativeMethodsMixin = require('NativeMethodsMixin'); -const React = require('React'); -const createReactClass = require('create-react-class'); const PropTypes = require('prop-types'); +const React = require('React'); const Touchable = require('Touchable'); const TouchableWithoutFeedback = require('TouchableWithoutFeedback'); -const ViewPropTypes = require('ViewPropTypes'); + +const createReactClass = require('create-react-class'); import type {EdgeInsetsProp} from 'EdgeInsetsPropType'; -import type {Props as TouchableWithoutFeedbackProps} from 'TouchableWithoutFeedback'; import type {ViewStyleProp} from 'StyleSheet'; - -type Event = Object; +import type {Props as TouchableWithoutFeedbackProps} from 'TouchableWithoutFeedback'; +import type {PressEvent} from 'CoreEventTypes'; type State = { animationID: ?number, @@ -35,8 +35,8 @@ const PRESS_RETENTION_OFFSET = {top: 20, left: 20, right: 20, bottom: 30}; type Props = $ReadOnly<{| ...TouchableWithoutFeedbackProps, - onPressWithCompletion?: ?Function, - onPressAnimationComplete?: ?Function, + onPressWithCompletion?: ?(fn: () => void) => void, + onPressAnimationComplete?: ?() => void, pressRetentionOffset?: ?EdgeInsetsProp, releaseVelocity?: ?number, releaseBounciness?: ?number, @@ -69,14 +69,14 @@ const TouchableBounce = ((createReactClass({ * reactivated! Move it back and forth several times while the scroll view * is disabled. Ensure you pass in a constant to reduce memory allocations. */ - pressRetentionOffset: EdgeInsetsPropType, + pressRetentionOffset: DeprecatedEdgeInsetsPropType, releaseVelocity: PropTypes.number.isRequired, releaseBounciness: PropTypes.number.isRequired, /** * Style to apply to the container/underlay. Most commonly used to make sure * rounded corners match the wrapped component. */ - style: ViewPropTypes.style, + style: DeprecatedViewPropTypes.style, }, getDefaultProps: function() { @@ -94,7 +94,7 @@ const TouchableBounce = ((createReactClass({ value: number, velocity: number, bounciness: number, - callback?: ?Function, + callback?: ?() => void, ) { Animated.spring(this.state.scale, { toValue: value, @@ -104,21 +104,28 @@ const TouchableBounce = ((createReactClass({ }).start(callback); }, + /** + * Triggers a bounce animation without invoking any callbacks. + */ + bounce: function() { + this.bounceTo(0.93, 0.1, 0, () => this.bounceTo(1, 0.4, 0)); + }, + /** * `Touchable.Mixin` self callbacks. The mixin will invoke these if they are * defined on your component. */ - touchableHandleActivePressIn: function(e: Event) { + touchableHandleActivePressIn: function(e: PressEvent) { this.bounceTo(0.93, 0.1, 0); this.props.onPressIn && this.props.onPressIn(e); }, - touchableHandleActivePressOut: function(e: Event) { + touchableHandleActivePressOut: function(e: PressEvent) { this.bounceTo(1, 0.4, 0); this.props.onPressOut && this.props.onPressOut(e); }, - touchableHandlePress: function(e: Event) { + touchableHandlePress: function(e: PressEvent) { const onPressWithCompletion = this.props.onPressWithCompletion; if (onPressWithCompletion) { onPressWithCompletion(() => { @@ -146,7 +153,7 @@ const TouchableBounce = ((createReactClass({ return this.props.pressRetentionOffset || PRESS_RETENTION_OFFSET; }, - touchableGetHitSlop: function(): ?Object { + touchableGetHitSlop: function(): ?EdgeInsetsProp { return this.props.hitSlop; }, diff --git a/Libraries/Components/Touchable/TouchableHighlight.js b/Libraries/Components/Touchable/TouchableHighlight.js index 996fd4be6b568f..b414c98d0d60c4 100644 --- a/Libraries/Components/Touchable/TouchableHighlight.js +++ b/Libraries/Components/Touchable/TouchableHighlight.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. @@ -9,25 +9,26 @@ */ 'use strict'; -const ColorPropType = require('ColorPropType'); +const DeprecatedColorPropType = require('DeprecatedColorPropType'); +const DeprecatedViewPropTypes = require('DeprecatedViewPropTypes'); const NativeMethodsMixin = require('NativeMethodsMixin'); -const PropTypes = require('prop-types'); const Platform = require('Platform'); +const PropTypes = require('prop-types'); const React = require('React'); const ReactNativeViewAttributes = require('ReactNativeViewAttributes'); const StyleSheet = require('StyleSheet'); const Touchable = require('Touchable'); const TouchableWithoutFeedback = require('TouchableWithoutFeedback'); const View = require('View'); -const ViewPropTypes = require('ViewPropTypes'); const createReactClass = require('create-react-class'); const ensurePositiveDelayProps = require('ensurePositiveDelayProps'); import type {PressEvent} from 'CoreEventTypes'; -import type {Props as TouchableWithoutFeedbackProps} from 'TouchableWithoutFeedback'; import type {ViewStyleProp} from 'StyleSheet'; import type {ColorValue} from 'StyleSheetTypes'; +import type {Props as TouchableWithoutFeedbackProps} from 'TouchableWithoutFeedback'; +import type {TVParallaxPropertiesType} from 'TVViewPropTypes'; const DEFAULT_PROPS = { activeOpacity: 0.85, @@ -39,7 +40,7 @@ const PRESS_RETENTION_OFFSET = {top: 20, left: 20, right: 20, bottom: 30}; type IOSProps = $ReadOnly<{| hasTVPreferredFocus?: ?boolean, - tvParallaxProperties?: ?Object, + tvParallaxProperties?: ?TVParallaxPropertiesType, |}>; type Props = $ReadOnly<{| @@ -49,8 +50,8 @@ type Props = $ReadOnly<{| activeOpacity?: ?number, underlayColor?: ?ColorValue, style?: ?ViewStyleProp, - onShowUnderlay?: ?Function, - onHideUnderlay?: ?Function, + onShowUnderlay?: ?() => void, + onHideUnderlay?: ?() => void, testOnly_pressed?: ?boolean, |}>; @@ -164,12 +165,12 @@ const TouchableHighlight = ((createReactClass({ * The color of the underlay that will show through when the touch is * active. */ - underlayColor: ColorPropType, + underlayColor: DeprecatedColorPropType, /** * Style to apply to the container/underlay. Most commonly used to make sure * rounded corners match the wrapped component. */ - style: ViewPropTypes.style, + style: DeprecatedViewPropTypes.style, /** * Called immediately after the underlay is shown */ @@ -185,18 +186,7 @@ const TouchableHighlight = ((createReactClass({ */ hasTVPreferredFocus: PropTypes.bool, /** - * *(Apple TV only)* Object with properties to control Apple TV parallax effects. - * - * enabled: If true, parallax effects are enabled. Defaults to true. - * shiftDistanceX: Defaults to 2.0. - * shiftDistanceY: Defaults to 2.0. - * tiltAngle: Defaults to 0.05. - * magnification: Defaults to 1.0. - * pressMagnification: Defaults to 1.0. - * pressDuration: Defaults to 0.3. - * pressDelay: Defaults to 0.0. - * - * @platform ios + * Apple TV parallax effects */ tvParallaxProperties: PropTypes.object, /** diff --git a/Libraries/Components/Touchable/TouchableNativeFeedback.android.js b/Libraries/Components/Touchable/TouchableNativeFeedback.android.js index ff149a7688c8f8..8365c809d6d1de 100644 --- a/Libraries/Components/Touchable/TouchableNativeFeedback.android.js +++ b/Libraries/Components/Touchable/TouchableNativeFeedback.android.js @@ -1,9 +1,10 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. * + * @flow strict-local * @format */ @@ -22,6 +23,8 @@ const createReactClass = require('create-react-class'); const ensurePositiveDelayProps = require('ensurePositiveDelayProps'); const processColor = require('processColor'); +import type {PressEvent} from 'CoreEventTypes'; + const rippleBackgroundPropType = PropTypes.shape({ type: PropTypes.oneOf(['RippleAndroid']), color: PropTypes.number, @@ -38,8 +41,6 @@ const backgroundPropType = PropTypes.oneOfType([ themeAttributeBackgroundPropType, ]); -type Event = Object; - const PRESS_RETENTION_OFFSET = {top: 20, left: 20, right: 20, bottom: 30}; /** @@ -167,7 +168,7 @@ const TouchableNativeFeedback = createReactClass({ * `Touchable.Mixin` self callbacks. The mixin will invoke these if they are * defined on your component. */ - touchableHandleActivePressIn: function(e: Event) { + touchableHandleActivePressIn: function(e: PressEvent) { this.props.onPressIn && this.props.onPressIn(e); this._dispatchPressedStateChange(true); if (this.pressInLocation) { @@ -178,16 +179,16 @@ const TouchableNativeFeedback = createReactClass({ } }, - touchableHandleActivePressOut: function(e: Event) { + touchableHandleActivePressOut: function(e: PressEvent) { this.props.onPressOut && this.props.onPressOut(e); this._dispatchPressedStateChange(false); }, - touchableHandlePress: function(e: Event) { + touchableHandlePress: function(e: PressEvent) { this.props.onPress && this.props.onPress(e); }, - touchableHandleLongPress: function(e: Event) { + touchableHandleLongPress: function(e: PressEvent) { this.props.onLongPress && this.props.onLongPress(e); }, @@ -223,7 +224,7 @@ const TouchableNativeFeedback = createReactClass({ _dispatchHotspotUpdate: function(destX, destY) { UIManager.dispatchViewManagerCommand( ReactNative.findNodeHandle(this), - UIManager.RCTView.Commands.hotspotUpdate, + UIManager.getViewManagerConfig('RCTView').Commands.hotspotUpdate, [destX || 0, destY || 0], ); }, @@ -231,7 +232,7 @@ const TouchableNativeFeedback = createReactClass({ _dispatchPressedStateChange: function(pressed) { UIManager.dispatchViewManagerCommand( ReactNative.findNodeHandle(this), - UIManager.RCTView.Commands.setPressed, + UIManager.getViewManagerConfig('RCTView').Commands.setPressed, [pressed], ); }, diff --git a/Libraries/Components/Touchable/TouchableNativeFeedback.js b/Libraries/Components/Touchable/TouchableNativeFeedback.js index 3eaf44a287463f..9495ca266615f6 100644 --- a/Libraries/Components/Touchable/TouchableNativeFeedback.js +++ b/Libraries/Components/Touchable/TouchableNativeFeedback.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. diff --git a/Libraries/Components/Touchable/TouchableOpacity.js b/Libraries/Components/Touchable/TouchableOpacity.js index 49eb1304f1eebb..257131a01eaa9c 100644 --- a/Libraries/Components/Touchable/TouchableOpacity.js +++ b/Libraries/Components/Touchable/TouchableOpacity.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. @@ -15,7 +15,6 @@ const Easing = require('Easing'); const NativeMethodsMixin = require('NativeMethodsMixin'); const React = require('React'); const PropTypes = require('prop-types'); -const TimerMixin = require('react-timer-mixin'); const Touchable = require('Touchable'); const TouchableWithoutFeedback = require('TouchableWithoutFeedback'); @@ -25,14 +24,14 @@ const flattenStyle = require('flattenStyle'); import type {Props as TouchableWithoutFeedbackProps} from 'TouchableWithoutFeedback'; import type {ViewStyleProp} from 'StyleSheet'; - -type Event = Object; +import type {TVParallaxPropertiesType} from 'TVViewPropTypes'; +import type {PressEvent} from 'CoreEventTypes'; const PRESS_RETENTION_OFFSET = {top: 20, left: 20, right: 20, bottom: 30}; type TVProps = $ReadOnly<{| hasTVPreferredFocus?: ?boolean, - tvParallaxProperties?: ?Object, + tvParallaxProperties?: ?TVParallaxPropertiesType, |}>; type Props = $ReadOnly<{| @@ -132,7 +131,7 @@ type Props = $ReadOnly<{| */ const TouchableOpacity = ((createReactClass({ displayName: 'TouchableOpacity', - mixins: [TimerMixin, Touchable.Mixin, NativeMethodsMixin], + mixins: [Touchable.Mixin, NativeMethodsMixin], propTypes: { ...TouchableWithoutFeedback.propTypes, @@ -194,7 +193,7 @@ const TouchableOpacity = ((createReactClass({ * `Touchable.Mixin` self callbacks. The mixin will invoke these if they are * defined on your component. */ - touchableHandleActivePressIn: function(e: Event) { + touchableHandleActivePressIn: function(e: PressEvent) { if (e.dispatchConfig.registrationName === 'onResponderGrant') { this._opacityActive(0); } else { @@ -203,16 +202,16 @@ const TouchableOpacity = ((createReactClass({ this.props.onPressIn && this.props.onPressIn(e); }, - touchableHandleActivePressOut: function(e: Event) { + touchableHandleActivePressOut: function(e: PressEvent) { this._opacityInactive(250); this.props.onPressOut && this.props.onPressOut(e); }, - touchableHandlePress: function(e: Event) { + touchableHandlePress: function(e: PressEvent) { this.props.onPress && this.props.onPress(e); }, - touchableHandleLongPress: function(e: Event) { + touchableHandleLongPress: function(e: PressEvent) { this.props.onLongPress && this.props.onLongPress(e); }, @@ -248,7 +247,7 @@ const TouchableOpacity = ((createReactClass({ _getChildStyleOpacityWithDefault: function() { const childStyle = flattenStyle(this.props.style) || {}; - return childStyle.opacity == undefined ? 1 : childStyle.opacity; + return childStyle.opacity == null ? 1 : childStyle.opacity; }, render: function() { diff --git a/Libraries/Components/Touchable/TouchableWithoutFeedback.js b/Libraries/Components/Touchable/TouchableWithoutFeedback.js index 51c727fc6d4093..ab09819d3acddc 100755 --- a/Libraries/Components/Touchable/TouchableWithoutFeedback.js +++ b/Libraries/Components/Touchable/TouchableWithoutFeedback.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. @@ -10,31 +10,29 @@ 'use strict'; -const EdgeInsetsPropType = require('EdgeInsetsPropType'); +const DeprecatedEdgeInsetsPropType = require('DeprecatedEdgeInsetsPropType'); const React = require('React'); const PropTypes = require('prop-types'); -const TimerMixin = require('react-timer-mixin'); const Touchable = require('Touchable'); const View = require('View'); const createReactClass = require('create-react-class'); const ensurePositiveDelayProps = require('ensurePositiveDelayProps'); -const warning = require('fbjs/lib/warning'); const { - AccessibilityComponentTypes, - AccessibilityRoles, - AccessibilityStates, - AccessibilityTraits, -} = require('ViewAccessibility'); + DeprecatedAccessibilityComponentTypes, + DeprecatedAccessibilityRoles, + DeprecatedAccessibilityStates, + DeprecatedAccessibilityTraits, +} = require('DeprecatedViewAccessibility'); import type {PressEvent} from 'CoreEventTypes'; import type {EdgeInsetsProp} from 'EdgeInsetsPropType'; import type { AccessibilityComponentType, AccessibilityRole, - AccessibilityStates as AccessibilityStatesFlow, - AccessibilityTraits as AccessibilityTraitsFlow, + AccessibilityStates, + AccessibilityTraits, } from 'ViewAccessibility'; // [TODO(macOS ISS#2323203) @@ -53,10 +51,11 @@ export type Props = $ReadOnly<{| | string | Array | any, - accessibilityHint?: string, + accessibilityHint?: ?Stringish, + accessibilityIgnoresInvertColors?: ?boolean, accessibilityRole?: ?AccessibilityRole, - accessibilityStates?: ?AccessibilityStatesFlow, - accessibilityTraits?: ?AccessibilityTraitsFlow, + accessibilityStates?: ?AccessibilityStates, + accessibilityTraits?: ?AccessibilityTraits, children?: ?React.Node, delayLongPress?: ?number, delayPressIn?: ?number, @@ -64,6 +63,8 @@ export type Props = $ReadOnly<{| disabled?: ?boolean, hitSlop?: ?EdgeInsetsProp, nativeID?: ?string, + onBlur?: ?Function, + onFocus?: ?Function, onLayout?: ?Function, onLongPress?: ?Function, onPress?: ?Function, @@ -93,20 +94,22 @@ export type Props = $ReadOnly<{| */ const TouchableWithoutFeedback = ((createReactClass({ displayName: 'TouchableWithoutFeedback', - mixins: [TimerMixin, Touchable.Mixin], + mixins: [Touchable.Mixin], propTypes: { accessible: PropTypes.bool, accessibilityLabel: PropTypes.node, accessibilityHint: PropTypes.string, - accessibilityComponentType: PropTypes.oneOf(AccessibilityComponentTypes), - accessibilityRole: PropTypes.oneOf(AccessibilityRoles), + accessibilityComponentType: PropTypes.oneOf( + DeprecatedAccessibilityComponentTypes, + ), + accessibilityRole: PropTypes.oneOf(DeprecatedAccessibilityRoles), accessibilityStates: PropTypes.arrayOf( - PropTypes.oneOf(AccessibilityStates), + PropTypes.oneOf(DeprecatedAccessibilityStates), ), accessibilityTraits: PropTypes.oneOfType([ - PropTypes.oneOf(AccessibilityTraits), - PropTypes.arrayOf(PropTypes.oneOf(AccessibilityTraits)), + PropTypes.oneOf(DeprecatedAccessibilityTraits), + PropTypes.arrayOf(PropTypes.oneOf(DeprecatedAccessibilityTraits)), ]), onAccessibilityTap: PropTypes.func, // TODO(OSS Candidate ISS#2710739) tabIndex: PropTypes.number, // TODO(macOS/win ISS#2323203) @@ -206,7 +209,7 @@ const TouchableWithoutFeedback = ((createReactClass({ * reactivated! Move it back and forth several times while the scroll view * is disabled. Ensure you pass in a constant to reduce memory allocations. */ - pressRetentionOffset: EdgeInsetsPropType, + pressRetentionOffset: DeprecatedEdgeInsetsPropType, /** * This defines how far your touch can start away from the button. This is * added to `pressRetentionOffset` when moving off of the button. @@ -215,7 +218,7 @@ const TouchableWithoutFeedback = ((createReactClass({ * of sibling views always takes precedence if a touch hits two overlapping * views. */ - hitSlop: EdgeInsetsPropType, + hitSlop: DeprecatedEdgeInsetsPropType, }, getInitialState: function() { @@ -316,10 +319,10 @@ const TouchableWithoutFeedback = ((createReactClass({ this.props.clickable !== false && this.props.onPress !== undefined, // TODO(android ISS) onClick: this.touchableHandlePress, // TODO(android ISS) onMouseEnter: this.props.onMouseEnter, // [TODO(macOS ISS#2323203) - onMouseLeave: this.props.onMouseLeave, - onDragEnter: this.props.onDragEnter, - onDragLeave: this.props.onDragLeave, - onDrop: this.props.onDrop, + onMouseLeave: this.props.onMouseLeave, // [TODO(macOS ISS#2323203) + onDragEnter: this.props.onDragEnter, // [TODO(macOS ISS#2323203) + onDragLeave: this.props.onDragLeave, // [TODO(macOS ISS#2323203) + onDrop: this.props.onDrop, // [TODO(macOS ISS#2323203) draggedTypes: this.props.draggedTypes, // ]TODO(macOS ISS#2323203) children, }); diff --git a/Libraries/Components/Touchable/__mocks__/ensureComponentIsNative.js b/Libraries/Components/Touchable/__mocks__/ensureComponentIsNative.js index f152b68bba74a4..234c178afddd94 100644 --- a/Libraries/Components/Touchable/__mocks__/ensureComponentIsNative.js +++ b/Libraries/Components/Touchable/__mocks__/ensureComponentIsNative.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. diff --git a/Libraries/Components/Touchable/__tests__/TouchableHighlight-test.js b/Libraries/Components/Touchable/__tests__/TouchableHighlight-test.js index f40cc0b7ad1be9..8f299d8a360103 100644 --- a/Libraries/Components/Touchable/__tests__/TouchableHighlight-test.js +++ b/Libraries/Components/Touchable/__tests__/TouchableHighlight-test.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. diff --git a/Libraries/Components/Touchable/ensureComponentIsNative.js b/Libraries/Components/Touchable/ensureComponentIsNative.js index 5ce5a39d9baaf0..911a8ffbb67bcb 100644 --- a/Libraries/Components/Touchable/ensureComponentIsNative.js +++ b/Libraries/Components/Touchable/ensureComponentIsNative.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. diff --git a/Libraries/Components/Touchable/ensurePositiveDelayProps.js b/Libraries/Components/Touchable/ensurePositiveDelayProps.js index 01c001ad4b6a7e..f4f23aec035641 100644 --- a/Libraries/Components/Touchable/ensurePositiveDelayProps.js +++ b/Libraries/Components/Touchable/ensurePositiveDelayProps.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. diff --git a/Libraries/Components/UnimplementedViews/UnimplementedView.js b/Libraries/Components/UnimplementedViews/UnimplementedView.js index ec21fde54492b2..30e64eb83d01fd 100644 --- a/Libraries/Components/UnimplementedViews/UnimplementedView.js +++ b/Libraries/Components/UnimplementedViews/UnimplementedView.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. diff --git a/Libraries/Components/SafeAreaView/SafeAreaView.android.js b/Libraries/Components/View/PlatformViewPropTypes.android.js similarity index 56% rename from Libraries/Components/SafeAreaView/SafeAreaView.android.js rename to Libraries/Components/View/PlatformViewPropTypes.android.js index a581258a57832f..f96fe3a62d8149 100644 --- a/Libraries/Components/SafeAreaView/SafeAreaView.android.js +++ b/Libraries/Components/View/PlatformViewPropTypes.android.js @@ -1,13 +1,14 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. * + * @providesModule PlatformViewPropTypes * @format * @flow */ 'use strict'; -module.exports = require('View'); +export type PlatformViewPropTypes = {}; diff --git a/Libraries/Components/View/PlatformViewPropTypes.ios.js b/Libraries/Components/View/PlatformViewPropTypes.ios.js new file mode 100644 index 00000000000000..fc842750601026 --- /dev/null +++ b/Libraries/Components/View/PlatformViewPropTypes.ios.js @@ -0,0 +1,16 @@ +/** + * 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. + * + * @providesModule PlatformViewPropTypes + * @format + * @flow + */ + +'use strict'; + +import type {TVViewProps} from 'TVViewPropTypes'; + +export type PlatformViewPropTypes = TVViewProps; diff --git a/Libraries/Components/View/ReactNativeStyleAttributes.js b/Libraries/Components/View/ReactNativeStyleAttributes.js index 7a75dda8b7f41b..240e6a4f0a4e4a 100644 --- a/Libraries/Components/View/ReactNativeStyleAttributes.js +++ b/Libraries/Components/View/ReactNativeStyleAttributes.js @@ -1,32 +1,32 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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 + * @format strict-local * @flow */ 'use strict'; -const ImageStylePropTypes = require('ImageStylePropTypes'); +const DeprecatedImageStylePropTypes = require('DeprecatedImageStylePropTypes'); const TextStylePropTypes = require('TextStylePropTypes'); -const ViewStylePropTypes = require('ViewStylePropTypes'); +const DeprecatedViewStylePropTypes = require('DeprecatedViewStylePropTypes'); -/* $FlowFixMe(>=0.54.0 site=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. */ -const keyMirror = require('fbjs/lib/keyMirror'); const processColor = require('processColor'); const processTransform = require('processTransform'); const sizesDiffer = require('sizesDiffer'); -const ReactNativeStyleAttributes = { - ...keyMirror(ViewStylePropTypes), - ...keyMirror(TextStylePropTypes), - ...keyMirror(ImageStylePropTypes), -}; +const ReactNativeStyleAttributes = {}; + +for (const attributeName of Object.keys({ + ...DeprecatedViewStylePropTypes, + ...TextStylePropTypes, + ...DeprecatedImageStylePropTypes, +})) { + ReactNativeStyleAttributes[attributeName] = true; +} ReactNativeStyleAttributes.transform = {process: processTransform}; ReactNativeStyleAttributes.shadowOffset = {diff: sizesDiffer}; diff --git a/Libraries/Components/View/ReactNativeViewAttributes.js b/Libraries/Components/View/ReactNativeViewAttributes.js index fba37a2c4d6038..138abab5780108 100644 --- a/Libraries/Components/View/ReactNativeViewAttributes.js +++ b/Libraries/Components/View/ReactNativeViewAttributes.js @@ -1,11 +1,11 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. * + * @flow strict-local * @format - * @flow strict */ 'use strict'; diff --git a/Libraries/Components/View/ShadowPropTypesIOS.js b/Libraries/Components/View/ShadowPropTypesIOS.js deleted file mode 100644 index 2dfc021735ad9e..00000000000000 --- a/Libraries/Components/View/ShadowPropTypesIOS.js +++ /dev/null @@ -1,50 +0,0 @@ -/** - * Copyright (c) 2015-present, Facebook, Inc. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @flow - * @format - */ -'use strict'; - -const ColorPropType = require('ColorPropType'); -const ReactPropTypes = require('prop-types'); - -/** - * These props can be used to dynamically generate shadows on views, images, text, etc. - * - * Because they are dynamically generated, they may cause performance regressions. Static - * shadow image asset may be a better way to go for optimal performance. - * - * These properties are iOS only - for similar functionality on Android, use the [`elevation` - * property](docs/viewstyleproptypes.html#elevation). - */ -const ShadowPropTypesIOS = { - /** - * Sets the drop shadow color - * @platform ios - */ - shadowColor: ColorPropType, - /** - * Sets the drop shadow offset - * @platform ios - */ - shadowOffset: ReactPropTypes.shape({ - width: ReactPropTypes.number, - height: ReactPropTypes.number, - }), - /** - * Sets the drop shadow opacity (multiplied by the color's alpha component) - * @platform ios - */ - shadowOpacity: ReactPropTypes.number, - /** - * Sets the drop shadow blur radius - * @platform ios - */ - shadowRadius: ReactPropTypes.number, -}; - -module.exports = ShadowPropTypesIOS; diff --git a/Libraries/Components/View/View.js b/Libraries/Components/View/View.js index 0ec2fda48fc79c..0c4cca3271eaa0 100644 --- a/Libraries/Components/View/View.js +++ b/Libraries/Components/View/View.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. @@ -30,24 +30,27 @@ export type Props = ViewProps; let ViewToExport = ViewNativeComponent; if (__DEV__) { - const View = ( - props: Props, - forwardedRef: React.Ref, - ) => { - return ( - - {hasTextAncestor => { - invariant( - !hasTextAncestor, - 'Nesting of within is not currently supported.', - ); - return ; - }} - - ); - }; - // $FlowFixMe - TODO T29156721 `React.forwardRef` is not defined in Flow, yet. - ViewToExport = React.forwardRef(View); + if (!global.__RCTProfileIsProfiling) { + const View = ( + props: Props, + forwardedRef: React.Ref, + ) => { + return ( + + {hasTextAncestor => { + invariant( + !hasTextAncestor, + 'Nesting of within is not currently supported.', + ); + return ; + }} + + ); + }; + // $FlowFixMe - TODO T29156721 `React.forwardRef` is not defined in Flow, yet. + ViewToExport = React.forwardRef(View); + ViewToExport.displayName = 'View'; + } } module.exports = ((ViewToExport: $FlowFixMe): typeof ViewNativeComponent); diff --git a/Libraries/Components/View/ViewAccessibility.js b/Libraries/Components/View/ViewAccessibility.js index 01a93d6ee2068a..28b4804374e05a 100644 --- a/Libraries/Components/View/ViewAccessibility.js +++ b/Libraries/Components/View/ViewAccessibility.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. @@ -46,6 +46,7 @@ export type AccessibilityNodeInfoProp = { clickable: boolean, }; // ]TODO(android ISS) +// This must be kept in sync with the AccessibilityRolesMask in RCTViewManager.m export type AccessibilityRole = | 'none' | 'button' diff --git a/Libraries/Components/View/ViewNativeComponent.js b/Libraries/Components/View/ViewNativeComponent.js index 67e55637944074..432040ad3c3a4c 100644 --- a/Libraries/Components/View/ViewNativeComponent.js +++ b/Libraries/Components/View/ViewNativeComponent.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. diff --git a/Libraries/Components/View/ViewPropTypes.js b/Libraries/Components/View/ViewPropTypes.js index a6a7ea133a6fea..7997a78ecea705 100644 --- a/Libraries/Components/View/ViewPropTypes.js +++ b/Libraries/Components/View/ViewPropTypes.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. @@ -10,30 +10,18 @@ 'use strict'; -const React = require('React'); -const EdgeInsetsPropType = require('EdgeInsetsPropType'); -const PlatformViewPropTypes = require('PlatformViewPropTypes'); -const PropTypes = require('prop-types'); -const StyleSheetPropType = require('StyleSheetPropType'); -const ViewStylePropTypes = require('ViewStylePropTypes'); - -const { - AccessibilityComponentTypes, - AccessibilityTraits, - AccessibilityRoles, - AccessibilityStates, -} = require('ViewAccessibility'); - +import type {Layout, LayoutEvent} from 'CoreEventTypes'; +import type {EdgeInsetsProp} from 'EdgeInsetsPropType'; +import type React from 'React'; +import type {ViewStyleProp} from 'StyleSheet'; +import type {TVViewProps} from 'TVViewPropTypes'; import type { AccessibilityComponentType, AccessibilityTrait, AccessibilityNodeInfoProp, // TODO(android ISS) AccessibilityRole, - AccessibilityState, + AccessibilityStates, } from 'ViewAccessibility'; -import type {EdgeInsetsProp} from 'EdgeInsetsPropType'; -import type {TVViewProps} from 'TVViewPropTypes'; -import type {Layout, LayoutEvent} from 'CoreEventTypes'; // [TODO(macOS ISS#2323203) const {DraggedTypes} = require('DraggedType'); @@ -41,18 +29,60 @@ const {DraggedTypes} = require('DraggedType'); import type {DraggedType} from 'DraggedType'; // ]TODO(macOS ISS#2323203) -const stylePropType = StyleSheetPropType(ViewStylePropTypes); - export type ViewLayout = Layout; export type ViewLayoutEvent = LayoutEvent; type DirectEventProps = $ReadOnly<{| - onAccessibilityAction?: Function, - onAccessibilityTap?: Function, + /** + * When `accessible` is true, the system will try to invoke this function + * when the user performs an accessibility custom action. + * + * @platform ios + */ + onAccessibilityAction?: ?Function, + + /** + * When `accessible` is true, the system will try to invoke this function + * when the user performs accessibility tap gesture. + * + * See http://facebook.github.io/react-native/docs/view.html#onaccessibilitytap + */ + onAccessibilityTap?: ?Function, + + /** + * When `accessible` is true, the system will try to invoke this function + * when the user performs accessibility double click gesture. + */ onDoubleClick?: ?Function, // TODO(macOS ISS#2323203) + + /** + * When `accessible` is true, the system will try to invoke this function + * when the user performs accessibility key down gesture. + */ onKeyDown?: ?Function, // TODO(macOS ISS#2323203) - onLayout?: ?(event: LayoutEvent) => void, - onMagicTap?: Function, + + onMouseEnter?: Function, // [TODO(macOS ISS#2323203) + + /** + * Invoked on mount and layout changes with: + * + * `{nativeEvent: { layout: {x, y, width, height}}}` + * + * This event is fired immediately once the layout has been calculated, but + * the new layout may not yet be reflected on the screen at the time the + * event is received, especially if a layout animation is in progress. + * + * See http://facebook.github.io/react-native/docs/view.html#onlayout + */ + onLayout?: ?(event: LayoutEvent) => mixed, + + /** + * When `accessible` is `true`, the system will invoke this function when the + * user performs the magic tap gesture. + * + * See http://facebook.github.io/react-native/docs/view.html#onmagictap + */ + onMagicTap?: ?Function, |}>; type TouchEventProps = $ReadOnly<{| @@ -66,17 +96,121 @@ type TouchEventProps = $ReadOnly<{| onTouchStartCapture?: ?Function, |}>; +/** + * For most touch interactions, you'll simply want to wrap your component in + * `TouchableHighlight` or `TouchableOpacity`. Check out `Touchable.js`, + * `ScrollResponder.js` and `ResponderEventPlugin.js` for more discussion. + */ type GestureResponderEventProps = $ReadOnly<{| + /** + * Does this view want to "claim" touch responsiveness? This is called for + * every touch move on the `View` when it is not the responder. + * + * `View.props.onMoveShouldSetResponder: (event) => [true | false]`, where + * `event` is a synthetic touch event as described above. + * + * See http://facebook.github.io/react-native/docs/view.html#onmoveshouldsetresponder + */ onMoveShouldSetResponder?: ?Function, + + /** + * If a parent `View` wants to prevent a child `View` from becoming responder + * on a move, it should have this handler which returns `true`. + * + * `View.props.onMoveShouldSetResponderCapture: (event) => [true | false]`, + * where `event` is a synthetic touch event as described above. + * + * See http://facebook.github.io/react-native/docs/view.html#onMoveShouldsetrespondercapture + */ onMoveShouldSetResponderCapture?: ?Function, + + /** + * The View is now responding for touch events. This is the time to highlight + * and show the user what is happening. + * + * `View.props.onResponderGrant: (event) => {}`, where `event` is a synthetic + * touch event as described above. + * + * See http://facebook.github.io/react-native/docs/view.html#onrespondergrant + */ onResponderGrant?: ?Function, + + /** + * The user is moving their finger. + * + * `View.props.onResponderMove: (event) => {}`, where `event` is a synthetic + * touch event as described above. + * + * See http://facebook.github.io/react-native/docs/view.html#onrespondermove + */ onResponderMove?: ?Function, + + /** + * Another responder is already active and will not release it to that `View` + * asking to be the responder. + * + * `View.props.onResponderReject: (event) => {}`, where `event` is a + * synthetic touch event as described above. + * + * See http://facebook.github.io/react-native/docs/view.html#onresponderreject + */ onResponderReject?: ?Function, + + /** + * Fired at the end of the touch. + * + * `View.props.onResponderRelease: (event) => {}`, where `event` is a + * synthetic touch event as described above. + * + * See http://facebook.github.io/react-native/docs/view.html#onresponderrelease + */ onResponderRelease?: ?Function, + onResponderStart?: ?Function, + + /** + * The responder has been taken from the `View`. Might be taken by other + * views after a call to `onResponderTerminationRequest`, or might be taken + * by the OS without asking (e.g., happens with control center/ notification + * center on iOS) + * + * `View.props.onResponderTerminate: (event) => {}`, where `event` is a + * synthetic touch event as described above. + * + * See http://facebook.github.io/react-native/docs/view.html#onresponderterminate + */ onResponderTerminate?: ?Function, + + /** + * Some other `View` wants to become responder and is asking this `View` to + * release its responder. Returning `true` allows its release. + * + * `View.props.onResponderTerminationRequest: (event) => {}`, where `event` + * is a synthetic touch event as described above. + * + * See http://facebook.github.io/react-native/docs/view.html#onresponderterminationrequest + */ onResponderTerminationRequest?: ?Function, + + /** + * Does this view want to become responder on the start of a touch? + * + * `View.props.onStartShouldSetResponder: (event) => [true | false]`, where + * `event` is a synthetic touch event as described above. + * + * See http://facebook.github.io/react-native/docs/view.html#onstartshouldsetresponder + */ onStartShouldSetResponder?: ?Function, + + /** + * If a parent `View` wants to prevent a child `View` from becoming responder + * on a touch start, it should have this handler which returns `true`. + * + * `View.props.onStartShouldSetResponderCapture: (event) => [true | false]`, + * where `event` is a synthetic touch event as described above. + * + * See http://facebook.github.io/react-native/docs/view.html#onstartshouldsetrespondercapture + */ onStartShouldSetResponderCapture?: ?Function, |}>; @@ -84,119 +218,54 @@ type AndroidViewProps = $ReadOnly<{| nativeBackgroundAndroid?: ?Object, nativeForegroundAndroid?: ?Object, - /* Deprecated transform prop. Use the transform style prop instead */ - rotation?: empty, - /* Deprecated transform prop. Use the transform style prop instead */ - scaleX?: empty, - /* Deprecated transform prop. Use the transform style prop instead */ - scaleY?: empty, - /* Deprecated transform prop. Use the transform style prop instead */ - translateX?: empty, - /* Deprecated transform prop. Use the transform style prop instead */ - translateY?: empty, -|}>; - -export type ViewProps = $ReadOnly<{| - ...DirectEventProps, - ...GestureResponderEventProps, - ...TouchEventProps, - ...AndroidViewProps, - - // There's no easy way to create a different type if (Platform.isTV): - // so we must include TVViewProps - ...TVViewProps, - - accessible?: boolean, - accessibilityLabel?: - | null - | React$PropType$Primitive - | string - | Array - | any, - accessibilityHint?: string, - accessibilityActions?: Array, - accessibilityComponentType?: AccessibilityComponentType, - accessibilityLiveRegion?: 'none' | 'polite' | 'assertive', - importantForAccessibility?: 'auto' | 'yes' | 'no' | 'no-hide-descendants', - accessibilityIgnoresInvertColors?: boolean, - accessibilityTraits?: AccessibilityTrait | Array, - accessibilityRole?: AccessibilityRole, - accessibilityStates?: Array, - accessibilityViewIsModal?: boolean, - accessibilityElementsHidden?: boolean, - children?: ?React.Node, - testID?: ?string, - nativeID?: string, - tabIndex?: number, // TODO(win ISS#2323203) - onDoubleClick?: ?Function, // TODO(macOS ISS#2323203) - onKeyDown?: ?Function, // TODO(macOS ISS#2323203) - hitSlop?: ?EdgeInsetsProp, - pointerEvents?: null | 'box-none' | 'none' | 'box-only' | 'auto', - style?: stylePropType, - removeClippedSubviews?: boolean, - renderToHardwareTextureAndroid?: boolean, - shouldRasterizeIOS?: boolean, - collapsable?: boolean, - needsOffscreenAlphaCompositing?: boolean, - clickable?: boolean, // [TODO(android ISS) - onClick?: Function, - onFocusChange?: Function, // ]TODO(android ISS) - onMouseEnter?: Function, // [TODO(macOS ISS#2323203) - onMouseLeave?: Function, - onDragEnter?: Function, - onDragLeave?: Function, - onDrop?: Function, - onFocus?: Function, - onBlur?: Function, - acceptsKeyboardFocus?: boolean, - enableFocusRing?: boolean, - tooltip?: string, - draggedTypes?: DraggedType | Array, // ]TODO(macOS ISS#2323203) - accessibilityNodeInfo?: AccessibilityNodeInfoProp, // TODO(android ISS) -|}>; - -module.exports = { /** - * When `true`, indicates that the view is an accessibility element. - * By default, all the touchable elements are accessible. + * Whether this `View` should render itself (and all of its children) into a + * single hardware texture on the GPU. * - * See http://facebook.github.io/react-native/docs/view.html#accessible + * @platform android + * + * See http://facebook.github.io/react-native/docs/view.html#rendertohardwaretextureandroid */ - accessible: PropTypes.bool, + renderToHardwareTextureAndroid?: ?boolean, /** - * Overrides the text that's read by the screen reader when the user interacts - * with the element. By default, the label is constructed by traversing all - * the children and accumulating all the `Text` nodes separated by space. + * Views that are only used to layout their children or otherwise don't draw + * anything may be automatically removed from the native hierarchy as an + * optimization. Set this property to `false` to disable this optimization and + * ensure that this `View` exists in the native view hierarchy. * - * See http://facebook.github.io/react-native/docs/view.html#accessibilitylabel + * @platform android + * + * See http://facebook.github.io/react-native/docs/view.html#collapsable */ - accessibilityLabel: PropTypes.node, + collapsable?: ?boolean, /** - * An accessibility hint helps users understand what will happen when they perform - * an action on the accessibility element when that result is not obvious from the - * accessibility label. + * Whether this `View` needs to rendered offscreen and composited with an + * alpha in order to preserve 100% correct colors and blending behavior. * + * @platform android * - * See http://facebook.github.io/react-native/docs/view.html#accessibilityHint + * See http://facebook.github.io/react-native/docs/view.html#needsoffscreenalphacompositing */ - accessibilityHint: PropTypes.string, + needsOffscreenAlphaCompositing?: ?boolean, /** - * Provides an array of custom actions available for accessibility. - * - * @platform ios + * When `true`, indicates that the view is clickable. By default, + * all the touchable elements are clickable. + * + * @platform android */ - accessibilityActions: PropTypes.arrayOf(PropTypes.string), - + clickable?: ?boolean, // TODO(android ISS) + /** - * Prevents view from being inverted if set to true and color inversion is turned on. - * - * @platform ios + * When `clickable` is true, the system will try to invoke this function + * when the user performs a click. + * + * @platform android */ - accessibilityIgnoresInvertColors: PropTypes.bool, + onClick?: ?Function, // TODO(android ISS) /** * Indicates to accessibility services to treat UI component like a * native one. Works for Android only. @@ -205,17 +274,9 @@ module.exports = { * * See http://facebook.github.io/react-native/docs/view.html#accessibilitycomponenttype */ - accessibilityComponentType: PropTypes.oneOf(AccessibilityComponentTypes), - /** - * Indicates to accessibility services to treat UI component like a specific role. - */ - accessibilityRole: PropTypes.oneOf(AccessibilityRoles), + accessibilityComponentType?: ?AccessibilityComponentType, - /** - * Indicates to accessibility services that UI Component is in a specific State. - */ - accessibilityStates: PropTypes.arrayOf(PropTypes.oneOf(AccessibilityStates)), /** * Indicates to accessibility services whether the user should be notified * when this view changes. Works for Android API >= 19 only. @@ -224,7 +285,14 @@ module.exports = { * * See http://facebook.github.io/react-native/docs/view.html#accessibilityliveregion */ - accessibilityLiveRegion: PropTypes.oneOf(['none', 'polite', 'assertive']), + accessibilityLiveRegion?: ?('none' | 'polite' | 'assertive'), + + /** + * fired when the view focus changes (gain->lose or lose->gain) + * + * @platform android + */ + onFocusChange?: ?Function, // TODO(android ISS) /** * Controls how view is important for accessibility which is if it @@ -235,12 +303,25 @@ module.exports = { * * See http://facebook.github.io/react-native/docs/view.html#importantforaccessibility */ - importantForAccessibility: PropTypes.oneOf([ - 'auto', - 'yes', - 'no', - 'no-hide-descendants', - ]), + importantForAccessibility?: ?('auto' | 'yes' | 'no' | 'no-hide-descendants'), + + accessibilityNodeInfo?: AccessibilityNodeInfoProp, // TODO(android ISS) +|}>; + +type IOSViewProps = $ReadOnly<{| + /** + * Provides an array of custom actions available for accessibility. + * + * @platform ios + */ + accessibilityActions?: ?$ReadOnlyArray, + + /** + * Prevents view from being inverted if set to true and color inversion is turned on. + * + * @platform ios + */ + accessibilityIgnoresInvertColors?: ?boolean, /** * Provides additional traits to screen reader. By default no traits are @@ -252,10 +333,10 @@ module.exports = { * * See http://facebook.github.io/react-native/docs/view.html#accessibilitytraits */ - accessibilityTraits: PropTypes.oneOfType([ - PropTypes.oneOf(AccessibilityTraits), - PropTypes.arrayOf(PropTypes.oneOf(AccessibilityTraits)), - ]), + accessibilityTraits?: ?( + | AccessibilityTrait + | $ReadOnlyArray + ), /** * A value indicating whether VoiceOver should ignore the elements @@ -266,7 +347,7 @@ module.exports = { * * See http://facebook.github.io/react-native/docs/view.html#accessibilityviewismodal */ - accessibilityViewIsModal: PropTypes.bool, + accessibilityViewIsModal?: ?boolean, /** * A value indicating whether the accessibility elements contained within @@ -276,17 +357,16 @@ module.exports = { * * See http://facebook.github.io/react-native/docs/view.html#accessibilityElementsHidden */ - accessibilityElementsHidden: PropTypes.bool, + accessibilityElementsHidden?: ?boolean, /** - * When `accessible` is true, the system will try to invoke this function - * when the user performs an accessibility custom action. + * Whether this `View` should be rendered as a bitmap before compositing. * * @platform ios */ - onAccessibilityAction: PropTypes.func, + onAccessibilityAction?: ?Function, - onDoubleClick: PropTypes.func, // TODO(macOS ISS#2323203) + onDoubleClick?: ?Function, // TODO(macOS ISS#2323203) /** * When `accessible` is true, the system will try to invoke this function @@ -294,150 +374,87 @@ module.exports = { * * See http://facebook.github.io/react-native/docs/view.html#onaccessibilitytap */ - onAccessibilityTap: PropTypes.func, + onAccessibilityTap?: ?Function, /** * When `accessible` is `true`, the system will invoke this function when the * user performs the magic tap gesture. * - * See http://facebook.github.io/react-native/docs/view.html#onmagictap - */ - onMagicTap: PropTypes.func, - - /** - * Used to locate this view in end-to-end tests. - * - * > This disables the 'layout-only view removal' optimization for this view! - * - * See http://facebook.github.io/react-native/docs/view.html#testid - */ - testID: PropTypes.string, - - /** - * Used to locate this view from native classes. - * - * > This disables the 'layout-only view removal' optimization for this view! - * - * See http://facebook.github.io/react-native/docs/view.html#nativeid + * See http://facebook.github.io/react-native/docs/view.html#shouldrasterizeios */ - nativeID: PropTypes.string, - - tabIndex: PropTypes.number, // TODO(win ISS#2323203) + shouldRasterizeIOS?: ?boolean, +|}>; - /** - * For most touch interactions, you'll simply want to wrap your component in - * `TouchableHighlight` or `TouchableOpacity`. Check out `Touchable.js`, - * `ScrollResponder.js` and `ResponderEventPlugin.js` for more discussion. - */ +export type ViewProps = $ReadOnly<{| + ...DirectEventProps, + ...GestureResponderEventProps, + ...TouchEventProps, + ...AndroidViewProps, + ...IOSViewProps, - /** - * The View is now responding for touch events. This is the time to highlight - * and show the user what is happening. - * - * `View.props.onResponderGrant: (event) => {}`, where `event` is a synthetic - * touch event as described above. - * - * See http://facebook.github.io/react-native/docs/view.html#onrespondergrant - */ - onResponderGrant: PropTypes.func, + // There's no easy way to create a different type if (Platform.isTV): + // so we must include TVViewProps + ...TVViewProps, - /** - * The user is moving their finger. - * - * `View.props.onResponderMove: (event) => {}`, where `event` is a synthetic - * touch event as described above. - * - * See http://facebook.github.io/react-native/docs/view.html#onrespondermove - */ - onResponderMove: PropTypes.func, + children?: React.Node, + style?: ?ViewStyleProp, /** - * Another responder is already active and will not release it to that `View` - * asking to be the responder. - * - * `View.props.onResponderReject: (event) => {}`, where `event` is a - * synthetic touch event as described above. + * When `true`, indicates that the view is an accessibility element. + * By default, all the touchable elements are accessible. * - * See http://facebook.github.io/react-native/docs/view.html#onresponderreject + * See http://facebook.github.io/react-native/docs/view.html#accessible */ - onResponderReject: PropTypes.func, + accessible?: ?boolean, /** - * Fired at the end of the touch. - * - * `View.props.onResponderRelease: (event) => {}`, where `event` is a - * synthetic touch event as described above. + * Overrides the text that's read by the screen reader when the user interacts + * with the element. By default, the label is constructed by traversing all + * the children and accumulating all the `Text` nodes separated by space. * - * See http://facebook.github.io/react-native/docs/view.html#onresponderrelease + * See http://facebook.github.io/react-native/docs/view.html#accessibilitylabel */ - onResponderRelease: PropTypes.func, + accessibilityLabel?: ?Stringish, /** - * The responder has been taken from the `View`. Might be taken by other - * views after a call to `onResponderTerminationRequest`, or might be taken - * by the OS without asking (e.g., happens with control center/ notification - * center on iOS) + * An accessibility hint helps users understand what will happen when they perform + * an action on the accessibility element when that result is not obvious from the + * accessibility label. * - * `View.props.onResponderTerminate: (event) => {}`, where `event` is a - * synthetic touch event as described above. * - * See http://facebook.github.io/react-native/docs/view.html#onresponderterminate + * See http://facebook.github.io/react-native/docs/view.html#accessibilityHint */ - onResponderTerminate: PropTypes.func, + accessibilityHint?: ?Stringish, /** - * Some other `View` wants to become responder and is asking this `View` to - * release its responder. Returning `true` allows its release. - * - * `View.props.onResponderTerminationRequest: (event) => {}`, where `event` - * is a synthetic touch event as described above. - * - * See http://facebook.github.io/react-native/docs/view.html#onresponderterminationrequest + * Indicates to accessibility services to treat UI component like a specific role. */ - onResponderTerminationRequest: PropTypes.func, + accessibilityRole?: ?AccessibilityRole, /** - * Does this view want to become responder on the start of a touch? - * - * `View.props.onStartShouldSetResponder: (event) => [true | false]`, where - * `event` is a synthetic touch event as described above. - * - * See http://facebook.github.io/react-native/docs/view.html#onstartshouldsetresponder + * Indicates to accessibility services that UI Component is in a specific State. */ - onStartShouldSetResponder: PropTypes.func, + accessibilityStates?: ?AccessibilityStates, /** - * If a parent `View` wants to prevent a child `View` from becoming responder - * on a touch start, it should have this handler which returns `true`. + * Used to locate this view in end-to-end tests. * - * `View.props.onStartShouldSetResponderCapture: (event) => [true | false]`, - * where `event` is a synthetic touch event as described above. + * > This disables the 'layout-only view removal' optimization for this view! * - * See http://facebook.github.io/react-native/docs/view.html#onstartshouldsetrespondercapture + * See http://facebook.github.io/react-native/docs/view.html#testid */ - onStartShouldSetResponderCapture: PropTypes.func, + testID?: ?string, /** - * Does this view want to "claim" touch responsiveness? This is called for - * every touch move on the `View` when it is not the responder. + * Used to locate this view from native classes. * - * `View.props.onMoveShouldSetResponder: (event) => [true | false]`, where - * `event` is a synthetic touch event as described above. + * > This disables the 'layout-only view removal' optimization for this view! * - * See http://facebook.github.io/react-native/docs/view.html#onmoveshouldsetresponder + * See http://facebook.github.io/react-native/docs/view.html#nativeid */ - onMoveShouldSetResponder: PropTypes.func, + nativeID?: ?string, - /** - * If a parent `View` wants to prevent a child `View` from becoming responder - * on a move, it should have this handler which returns `true`. - * - * `View.props.onMoveShouldSetResponderCapture: (event) => [true | false]`, - * where `event` is a synthetic touch event as described above. - * - * See http://facebook.github.io/react-native/docs/view.html#onMoveShouldsetrespondercapture - */ - onMoveShouldSetResponderCapture: PropTypes.func, + tabIndex?: ?number, // TODO(win ISS#2323203) /** * This defines how far a touch event can start away from the view. @@ -450,34 +467,16 @@ module.exports = { * * See http://facebook.github.io/react-native/docs/view.html#hitslop */ - hitSlop: EdgeInsetsPropType, - - /** - * Invoked on mount and layout changes with: - * - * `{nativeEvent: { layout: {x, y, width, height}}}` - * - * This event is fired immediately once the layout has been calculated, but - * the new layout may not yet be reflected on the screen at the time the - * event is received, especially if a layout animation is in progress. - * - * See http://facebook.github.io/react-native/docs/view.html#onlayout - */ - onLayout: PropTypes.func, + hitSlop?: ?EdgeInsetsProp, /** * Controls whether the `View` can be the target of touch events. * * See http://facebook.github.io/react-native/docs/view.html#pointerevents */ - pointerEvents: PropTypes.oneOf(['box-none', 'none', 'box-only', 'auto']), - - /** - * See http://facebook.github.io/react-native/docs/style.html - */ - style: stylePropType, - - /** + pointerEvents?: ?('auto' | 'box-none' | 'box-only' | 'none'), + + /** * This is a special performance property exposed by `RCTView` and is useful * for scrolling content when there are many subviews, most of which are * offscreen. For this property to be effective, it must be applied to a @@ -487,123 +486,61 @@ module.exports = { * * See http://facebook.github.io/react-native/docs/view.html#removeclippedsubviews */ - removeClippedSubviews: PropTypes.bool, - - /** - * Whether this `View` should render itself (and all of its children) into a - * single hardware texture on the GPU. - * - * @platform android - * - * See http://facebook.github.io/react-native/docs/view.html#rendertohardwaretextureandroid - */ - renderToHardwareTextureAndroid: PropTypes.bool, - - /** - * Whether this `View` should be rendered as a bitmap before compositing. - * - * @platform ios - * - * See http://facebook.github.io/react-native/docs/view.html#shouldrasterizeios - */ - shouldRasterizeIOS: PropTypes.bool, - - /** - * Views that are only used to layout their children or otherwise don't draw - * anything may be automatically removed from the native hierarchy as an - * optimization. Set this property to `false` to disable this optimization and - * ensure that this `View` exists in the native view hierarchy. - * - * @platform android - * - * See http://facebook.github.io/react-native/docs/view.html#collapsable - */ - collapsable: PropTypes.bool, - - /** - * Whether this `View` needs to rendered offscreen and composited with an - * alpha in order to preserve 100% correct colors and blending behavior. - * - * @platform android - * - * See http://facebook.github.io/react-native/docs/view.html#needsoffscreenalphacompositing - */ - needsOffscreenAlphaCompositing: PropTypes.bool, - - /** - * When `true`, indicates that the view is clickable. By default, - * all the touchable elements are clickable. - * - * @platform android - */ - clickable: PropTypes.bool, // TODO(android ISS) + removeClippedSubviews?: ?boolean, - /** - * When `clickable` is true, the system will try to invoke this function - * when the user performs a click. - * - * @platform android - */ - onClick: PropTypes.func, // TODO(android ISS) + onKeyDown?: ?Function, // TODO(macOS ISS#2323203) /** * Fired when a pointing device is moved over the view * * @platform macos */ - onMouseEnter: PropTypes.func, // TODO(macOS ISS#2323203) + onMouseEnter?: ?Function, // TODO(macOS ISS#2323203) /** * Fired when a pointing device is moved out the view * * @platform macos */ - onMouseLeave: PropTypes.func, // TODO(macOS ISS#2323203) + onMouseLeave?: ?Function, // TODO(macOS ISS#2323203) /** * Fired when a dragged element enters a valid drop target * * @platform macos */ - onDragEnter: PropTypes.func, // TODO(macOS ISS#2323203) + onDragEnter?: ?Function, // TODO(macOS ISS#2323203) /** * Fired when a dragged element leaves a valid drop target * * @platform macos */ - onDragLeave: PropTypes.func, // TODO(macOS ISS#2323203) + onDragLeave?: ?Function, // TODO(macOS ISS#2323203) /** * Fired when an element is dropped on a valid drop target * * @platform macos */ - onDrop: PropTypes.func, // TODO(macOS ISS#2323203) + onDrop?: ?Function, // TODO(macOS ISS#2323203) /** * Specifies the Tooltip for the view * @platform macos */ - tooltip: PropTypes.string, // TODO(macOS ISS#2323203) + tooltip?: ?string, // TODO(macOS ISS#2323203) /** * Specifies whether the view participates in the key view loop as user tabs * through different controls. */ - acceptsKeyboardFocus: PropTypes.bool, // TODO(macOS ISS#2323203) + acceptsKeyboardFocus?: ?boolean, // TODO(macOS ISS#2323203) /** * Specifies whether focus ring should be drawn when the view has the first responder status. */ - enableFocusRing: PropTypes.bool, // TODO(macOS ISS#2323203) - - /** - * fired when the view focus changes (gain->lose or lose->gain) - * - * @platform android - */ - onFocusChange: PropTypes.func, // TODO(android ISS) + enableFocusRing?: ?boolean, // TODO(macOS ISS#2323203) /** * Fired when an element is focused @@ -611,7 +548,7 @@ module.exports = { * @platform macos * @platform ios */ - onFocus: PropTypes.func, // TODO(macOS ISS#2323203) + onFocus?: ?Function, // TODO(macOS ISS#2323203) /** * Fired when an element loses focus @@ -619,7 +556,7 @@ module.exports = { * @platform macos * @platform ios */ - onBlur: PropTypes.func, // TODO(macOS ISS#2323203) + onBlur?: ?Function, // TODO(macOS ISS#2323203) /** * Enables Dran'n'Drop Support for certain types of dragged types @@ -630,10 +567,7 @@ module.exports = { * * @platform macos */ - draggedTypes: PropTypes.oneOfType([ - PropTypes.oneOf(DraggedTypes), - PropTypes.arrayOf(PropTypes.oneOf(DraggedTypes)), - ]), // TODO(macOS ISS#2323203) + draggedTypes?: ?DraggedTypes | ?$ReadOnlyArray, // TODO(macOS ISS#2323203) /** * Any additional platform-specific view prop types, or prop type overrides. diff --git a/Libraries/Components/ViewPager/ViewPagerAndroid.android.js b/Libraries/Components/ViewPager/ViewPagerAndroid.android.js index 2b69a2777a3ae6..f5075a94ebe7b7 100644 --- a/Libraries/Components/ViewPager/ViewPagerAndroid.android.js +++ b/Libraries/Components/ViewPager/ViewPagerAndroid.android.js @@ -1,29 +1,49 @@ /** - * Copyright (c) 2013-present, Facebook, Inc. + * 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 + * @flow strict-local */ 'use strict'; const React = require('React'); -const PropTypes = require('prop-types'); const ReactNative = require('ReactNative'); const UIManager = require('UIManager'); -const ViewPropTypes = require('ViewPropTypes'); const dismissKeyboard = require('dismissKeyboard'); const requireNativeComponent = require('requireNativeComponent'); const NativeAndroidViewPager = requireNativeComponent('AndroidViewPager'); +import type {SyntheticEvent} from 'CoreEventTypes'; +import type {ViewStyleProp} from 'StyleSheet'; + const VIEWPAGER_REF = 'viewPager'; -type Event = Object; +type PageScrollState = 'idle' | 'dragging' | 'settling'; + +type PageScrollEvent = SyntheticEvent< + $ReadOnly<{| + position: number, + offset: number, + |}>, +>; + +type PageScrollStateChangedEvent = SyntheticEvent< + $ReadOnly<{| + pageScrollState: PageScrollState, + |}>, +>; + +type PageSelectedEvent = SyntheticEvent< + $ReadOnly<{| + position: number, + |}>, +>; export type ViewPagerScrollState = $Enum<{ idle: string, @@ -31,6 +51,73 @@ export type ViewPagerScrollState = $Enum<{ settling: string, }>; +type Props = $ReadOnly<{| + /** + * Index of initial page that should be selected. Use `setPage` method to + * update the page, and `onPageSelected` to monitor page changes + */ + initialPage?: ?number, + + /** + * Executed when transitioning between pages (ether because of animation for + * the requested page change or when user is swiping/dragging between pages) + * The `event.nativeEvent` object for this callback will carry following data: + * - position - index of first page from the left that is currently visible + * - offset - value from range [0,1) describing stage between page transitions. + * Value x means that (1 - x) fraction of the page at "position" index is + * visible, and x fraction of the next page is visible. + */ + onPageScroll?: ?(e: PageScrollEvent) => void, + + /** + * Function called when the page scrolling state has changed. + * The page scrolling state can be in 3 states: + * - idle, meaning there is no interaction with the page scroller happening at the time + * - dragging, meaning there is currently an interaction with the page scroller + * - settling, meaning that there was an interaction with the page scroller, and the + * page scroller is now finishing it's closing or opening animation + */ + onPageScrollStateChanged?: ?(e: PageScrollState) => void, + + /** + * This callback will be called once ViewPager finish navigating to selected page + * (when user swipes between pages). The `event.nativeEvent` object passed to this + * callback will have following fields: + * - position - index of page that has been selected + */ + onPageSelected?: ?(e: PageSelectedEvent) => void, + + /** + * Blank space to show between pages. This is only visible while scrolling, pages are still + * edge-to-edge. + */ + pageMargin?: ?number, + + /** + * Whether enable showing peekFraction or not. If this is true, the preview of + * last and next page will show in current screen. Defaults to false. + */ + + peekEnabled?: ?boolean, + + /** + * Determines whether the keyboard gets dismissed in response to a drag. + * - 'none' (the default), drags do not dismiss the keyboard. + * - 'on-drag', the keyboard is dismissed when a drag begins. + */ + keyboardDismissMode?: ?('none' | 'on-drag'), + + /** + * When false, the content does not scroll. + * The default value is true. + */ + scrollEnabled?: ?boolean, + + children?: React.Node, + + style?: ?ViewStyleProp, +|}>; + /** * Container that allows to flip left and right between child views. Each * child view of the `ViewPagerAndroid` will be treated as a separate page @@ -72,84 +159,8 @@ export type ViewPagerScrollState = $Enum<{ * } * ``` */ -class ViewPagerAndroid extends React.Component<{ - initialPage?: number, - onPageScroll?: Function, - onPageScrollStateChanged?: Function, - onPageSelected?: Function, - pageMargin?: number, - peekEnabled?: boolean, - keyboardDismissMode?: 'none' | 'on-drag', - scrollEnabled?: boolean, -}> { - /* $FlowFixMe(>=0.78.0 site=react_native_android_fb) This issue was found - * when making Flow check .android.js files. */ - static propTypes = { - ...ViewPropTypes, - /** - * Index of initial page that should be selected. Use `setPage` method to - * update the page, and `onPageSelected` to monitor page changes - */ - initialPage: PropTypes.number, - - /** - * Executed when transitioning between pages (ether because of animation for - * the requested page change or when user is swiping/dragging between pages) - * The `event.nativeEvent` object for this callback will carry following data: - * - position - index of first page from the left that is currently visible - * - offset - value from range [0,1) describing stage between page transitions. - * Value x means that (1 - x) fraction of the page at "position" index is - * visible, and x fraction of the next page is visible. - */ - onPageScroll: PropTypes.func, - - /** - * Function called when the page scrolling state has changed. - * The page scrolling state can be in 3 states: - * - idle, meaning there is no interaction with the page scroller happening at the time - * - dragging, meaning there is currently an interaction with the page scroller - * - settling, meaning that there was an interaction with the page scroller, and the - * page scroller is now finishing it's closing or opening animation - */ - onPageScrollStateChanged: PropTypes.func, - - /** - * This callback will be called once ViewPager finish navigating to selected page - * (when user swipes between pages). The `event.nativeEvent` object passed to this - * callback will have following fields: - * - position - index of page that has been selected - */ - onPageSelected: PropTypes.func, - - /** - * Blank space to show between pages. This is only visible while scrolling, pages are still - * edge-to-edge. - */ - pageMargin: PropTypes.number, - - /** - * Determines whether the keyboard gets dismissed in response to a drag. - * - 'none' (the default), drags do not dismiss the keyboard. - * - 'on-drag', the keyboard is dismissed when a drag begins. - */ - keyboardDismissMode: PropTypes.oneOf([ - 'none', // default - 'on-drag', - ]), - - /** - * When false, the content does not scroll. - * The default value is true. - */ - scrollEnabled: PropTypes.bool, - - /** - * Whether enable showing peekFraction or not. If this is true, the preview of - * last and next page will show in current screen. Defaults to false. - */ - peekEnabled: PropTypes.bool, - }; +class ViewPagerAndroid extends React.Component { componentDidMount() { if (this.props.initialPage != null) { this.setPageWithoutAnimation(this.props.initialPage); @@ -205,7 +216,7 @@ class ViewPagerAndroid extends React.Component<{ }); }; - _onPageScroll = (e: Event) => { + _onPageScroll = (e: PageScrollEvent) => { if (this.props.onPageScroll) { this.props.onPageScroll(e); } @@ -214,13 +225,13 @@ class ViewPagerAndroid extends React.Component<{ } }; - _onPageScrollStateChanged = (e: Event) => { + _onPageScrollStateChanged = (e: PageScrollStateChangedEvent) => { if (this.props.onPageScrollStateChanged) { this.props.onPageScrollStateChanged(e.nativeEvent.pageScrollState); } }; - _onPageSelected = (e: Event) => { + _onPageSelected = (e: PageSelectedEvent) => { if (this.props.onPageSelected) { this.props.onPageSelected(e); } @@ -233,7 +244,7 @@ class ViewPagerAndroid extends React.Component<{ setPage = (selectedPage: number) => { UIManager.dispatchViewManagerCommand( ReactNative.findNodeHandle(this), - UIManager.AndroidViewPager.Commands.setPage, + UIManager.getViewManagerConfig('AndroidViewPager').Commands.setPage, [selectedPage], ); }; @@ -245,7 +256,8 @@ class ViewPagerAndroid extends React.Component<{ setPageWithoutAnimation = (selectedPage: number) => { UIManager.dispatchViewManagerCommand( ReactNative.findNodeHandle(this), - UIManager.AndroidViewPager.Commands.setPageWithoutAnimation, + UIManager.getViewManagerConfig('AndroidViewPager').Commands + .setPageWithoutAnimation, [selectedPage], ); }; diff --git a/Libraries/Components/ViewPager/ViewPagerAndroid.ios.js b/Libraries/Components/ViewPager/ViewPagerAndroid.ios.js index 260d559929796f..7a00b6636cf664 100644 --- a/Libraries/Components/ViewPager/ViewPagerAndroid.ios.js +++ b/Libraries/Components/ViewPager/ViewPagerAndroid.ios.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. diff --git a/Libraries/Components/WebView/WebView.android.js b/Libraries/Components/WebView/WebView.android.js index bed2179734579a..83991432b57c83 100644 --- a/Libraries/Components/WebView/WebView.android.js +++ b/Libraries/Components/WebView/WebView.android.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. @@ -9,15 +9,15 @@ 'use strict'; -const EdgeInsetsPropType = require('EdgeInsetsPropType'); const ActivityIndicator = require('ActivityIndicator'); -const React = require('React'); +const DeprecatedViewPropTypes = require('DeprecatedViewPropTypes'); +const DeprecatedEdgeInsetsPropType = require('DeprecatedEdgeInsetsPropType'); const PropTypes = require('prop-types'); +const React = require('React'); const ReactNative = require('ReactNative'); const StyleSheet = require('StyleSheet'); const UIManager = require('UIManager'); const View = require('View'); -const ViewPropTypes = require('ViewPropTypes'); const WebViewShared = require('WebViewShared'); const deprecatedPropType = require('deprecatedPropType'); @@ -44,7 +44,7 @@ const defaultRenderLoading = () => ( */ class WebView extends React.Component { static propTypes = { - ...ViewPropTypes, + ...DeprecatedViewPropTypes, renderError: PropTypes.func, renderLoading: PropTypes.func, onLoad: PropTypes.func, @@ -52,12 +52,12 @@ class WebView extends React.Component { onLoadStart: PropTypes.func, onError: PropTypes.func, automaticallyAdjustContentInsets: PropTypes.bool, - contentInset: EdgeInsetsPropType, + contentInset: DeprecatedEdgeInsetsPropType, onNavigationStateChange: PropTypes.func, onMessage: PropTypes.func, onContentSizeChange: PropTypes.func, startInLoadingState: PropTypes.bool, // force WebView to show loadingView on first load - style: ViewPropTypes.style, + style: DeprecatedViewPropTypes.style, html: deprecatedPropType( PropTypes.string, @@ -150,6 +150,12 @@ class WebView extends React.Component { */ scalesPageToFit: PropTypes.bool, + /** + * Sets whether the webview allow access to file system. + * @platform android + */ + allowFileAccess: PropTypes.bool, + /** * Sets the user-agent for this WebView. The user-agent can also be set in native using * WebViewConfig. This prop will overwrite that config. @@ -317,6 +323,7 @@ class WebView extends React.Component { style={webViewStyles} source={resolveAssetSource(source)} scalesPageToFit={this.props.scalesPageToFit} + allowFileAccess={this.props.allowFileAccess} injectedJavaScript={this.props.injectedJavaScript} userAgent={this.props.userAgent} javaScriptEnabled={this.props.javaScriptEnabled} @@ -359,7 +366,7 @@ class WebView extends React.Component { goForward = () => { UIManager.dispatchViewManagerCommand( this.getWebViewHandle(), - UIManager.RCTWebView.Commands.goForward, + UIManager.getViewManagerConfig('RCTWebView').Commands.goForward, null, ); }; @@ -367,7 +374,7 @@ class WebView extends React.Component { goBack = () => { UIManager.dispatchViewManagerCommand( this.getWebViewHandle(), - UIManager.RCTWebView.Commands.goBack, + UIManager.getViewManagerConfig('RCTWebView').Commands.goBack, null, ); }; @@ -378,7 +385,7 @@ class WebView extends React.Component { }); UIManager.dispatchViewManagerCommand( this.getWebViewHandle(), - UIManager.RCTWebView.Commands.reload, + UIManager.getViewManagerConfig('RCTWebView').Commands.reload, null, ); }; @@ -386,7 +393,7 @@ class WebView extends React.Component { stopLoading = () => { UIManager.dispatchViewManagerCommand( this.getWebViewHandle(), - UIManager.RCTWebView.Commands.stopLoading, + UIManager.getViewManagerConfig('RCTWebView').Commands.stopLoading, null, ); }; @@ -394,7 +401,7 @@ class WebView extends React.Component { postMessage = data => { UIManager.dispatchViewManagerCommand( this.getWebViewHandle(), - UIManager.RCTWebView.Commands.postMessage, + UIManager.getViewManagerConfig('RCTWebView').Commands.postMessage, [String(data)], ); }; @@ -408,7 +415,7 @@ class WebView extends React.Component { injectJavaScript = data => { UIManager.dispatchViewManagerCommand( this.getWebViewHandle(), - UIManager.RCTWebView.Commands.injectJavaScript, + UIManager.getViewManagerConfig('RCTWebView').Commands.injectJavaScript, [data], ); }; diff --git a/Libraries/Components/WebView/WebView.ios.js b/Libraries/Components/WebView/WebView.ios.js index 329dd2027c1844..ba8034644d52a7 100644 --- a/Libraries/Components/WebView/WebView.ios.js +++ b/Libraries/Components/WebView/WebView.ios.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. @@ -11,17 +11,16 @@ 'use strict'; const ActivityIndicator = require('ActivityIndicator'); -const EdgeInsetsPropType = require('EdgeInsetsPropType'); +const DeprecatedViewPropTypes = require('DeprecatedViewPropTypes'); +const DeprecatedEdgeInsetsPropType = require('DeprecatedEdgeInsetsPropType'); const Linking = require('Linking'); const PropTypes = require('prop-types'); const React = require('React'); const ReactNative = require('ReactNative'); -const ScrollView = require('ScrollView'); const StyleSheet = require('StyleSheet'); const Text = require('Text'); const UIManager = require('UIManager'); const View = require('View'); -const ViewPropTypes = require('ViewPropTypes'); const WebViewShared = require('WebViewShared'); const deprecatedPropType = require('deprecatedPropType'); @@ -114,7 +113,7 @@ class WebView extends React.Component { static JSNavigationScheme = JSNavigationScheme; static NavigationType = NavigationType; static propTypes = { - ...ViewPropTypes, + ...DeprecatedViewPropTypes, html: deprecatedPropType( PropTypes.string, @@ -234,7 +233,7 @@ class WebView extends React.Component { * the scroll view. Defaults to {top: 0, left: 0, bottom: 0, right: 0}. * @platform ios */ - contentInset: EdgeInsetsPropType, + contentInset: DeprecatedEdgeInsetsPropType, /** * Function that is invoked when the `WebView` loading starts or ends. */ @@ -257,7 +256,7 @@ class WebView extends React.Component { /** * The style to apply to the `WebView`. */ - style: ViewPropTypes.style, + style: DeprecatedViewPropTypes.style, /** * Determines the types of data converted to clickable URLs in the web view's content. @@ -561,10 +560,10 @@ class WebView extends React.Component { _getCommands() { if (!this.props.useWebKit) { - return UIManager.RCTWebView.Commands; + return UIManager.getViewManagerConfig('RCTWebView').Commands; } - return UIManager.RCTWKWebView.Commands; + return UIManager.getViewManagerConfig('RCTWKWebView').Commands; } /** diff --git a/Libraries/Components/WebView/WebViewShared.js b/Libraries/Components/WebView/WebViewShared.js index 5a3006e845b0cc..af2f7e9a80baaa 100644 --- a/Libraries/Components/WebView/WebViewShared.js +++ b/Libraries/Components/WebView/WebViewShared.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. diff --git a/Libraries/Components/WebView/__tests__/WebViewShared-test.js b/Libraries/Components/WebView/__tests__/WebViewShared-test.js index b7456638fedb71..2a6dee2e2758de 100644 --- a/Libraries/Components/WebView/__tests__/WebViewShared-test.js +++ b/Libraries/Components/WebView/__tests__/WebViewShared-test.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2013-present, Facebook, Inc. + * 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. diff --git a/Libraries/Core/Devtools/__tests__/parseErrorStack-test.js b/Libraries/Core/Devtools/__tests__/parseErrorStack-test.js index 79d677e217e71c..14aafede381848 100644 --- a/Libraries/Core/Devtools/__tests__/parseErrorStack-test.js +++ b/Libraries/Core/Devtools/__tests__/parseErrorStack-test.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. diff --git a/Libraries/Core/Devtools/getDevServer.js b/Libraries/Core/Devtools/getDevServer.js index adcc28c2d067e1..3eae2fbc404baf 100644 --- a/Libraries/Core/Devtools/getDevServer.js +++ b/Libraries/Core/Devtools/getDevServer.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. diff --git a/Libraries/Core/Devtools/openFileInEditor.js b/Libraries/Core/Devtools/openFileInEditor.js index eedf9f1233d68d..00074b91eefedf 100644 --- a/Libraries/Core/Devtools/openFileInEditor.js +++ b/Libraries/Core/Devtools/openFileInEditor.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. diff --git a/Libraries/Core/Devtools/parseErrorStack.js b/Libraries/Core/Devtools/parseErrorStack.js index ec85260d7eaa35..ff308d1dd243cf 100644 --- a/Libraries/Core/Devtools/parseErrorStack.js +++ b/Libraries/Core/Devtools/parseErrorStack.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. @@ -19,6 +19,7 @@ export type StackFrame = { export type ExtendedError = Error & { framesToPop?: number, + jsEngine?: string, }; function parseErrorStack(e: ExtendedError): Array { diff --git a/Libraries/Core/Devtools/setupDevtools.js b/Libraries/Core/Devtools/setupDevtools.js index ba0f578b066445..010c1abc109a2d 100644 --- a/Libraries/Core/Devtools/setupDevtools.js +++ b/Libraries/Core/Devtools/setupDevtools.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. @@ -10,16 +10,6 @@ 'use strict'; -type DevToolsPluginConnection = { - isAppActive: () => boolean, - host: string, - port: number, -}; - -type DevToolsPlugin = { - connectToDevTools: (connection: DevToolsPluginConnection) => void, -}; - let register = function() { // noop }; diff --git a/Libraries/Core/Devtools/symbolicateStackTrace.js b/Libraries/Core/Devtools/symbolicateStackTrace.js index b5d7d4e9754ff0..93d643cdb3380d 100644 --- a/Libraries/Core/Devtools/symbolicateStackTrace.js +++ b/Libraries/Core/Devtools/symbolicateStackTrace.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. diff --git a/Libraries/Core/ExceptionsManager.js b/Libraries/Core/ExceptionsManager.js index bc32f5d0d23890..08fe06f72b6c47 100644 --- a/Libraries/Core/ExceptionsManager.js +++ b/Libraries/Core/ExceptionsManager.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. @@ -22,18 +22,16 @@ function reportException(e: ExtendedError, isFatal: boolean) { const parseErrorStack = require('parseErrorStack'); const stack = parseErrorStack(e); const currentExceptionID = ++exceptionID; + const message = + e.jsEngine == null ? e.message : `${e.message}, js engine: ${e.jsEngine}`; if (isFatal) { ExceptionsManager.reportFatalException( - e.message, + message, stack, currentExceptionID, ); } else { - ExceptionsManager.reportSoftException( - e.message, - stack, - currentExceptionID, - ); + ExceptionsManager.reportSoftException(message, stack, currentExceptionID); } if (__DEV__) { const symbolicateStackTrace = require('symbolicateStackTrace'); diff --git a/Libraries/Core/InitializeCore.js b/Libraries/Core/InitializeCore.js index 119deb92b2b0bc..2a2ca6479b5399 100644 --- a/Libraries/Core/InitializeCore.js +++ b/Libraries/Core/InitializeCore.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. @@ -25,198 +25,31 @@ */ 'use strict'; -const {polyfillObjectProperty, polyfillGlobal} = require('PolyfillFunctions'); - -if (global.GLOBAL === undefined) { - global.GLOBAL = global; -} - -if (global.window === undefined) { - global.window = global; -} - -// Set up collections -const _shouldPolyfillCollection = require('_shouldPolyfillES6Collection'); -if (_shouldPolyfillCollection('Map')) { - polyfillGlobal('Map', () => require('Map')); -} -if (_shouldPolyfillCollection('Set')) { - polyfillGlobal('Set', () => require('Set')); -} - -// Set up process -global.process = global.process || {}; -global.process.env = global.process.env || {}; -if (!global.process.env.NODE_ENV) { - global.process.env.NODE_ENV = __DEV__ ? 'development' : 'production'; -} - -// Setup the Systrace profiling hooks if necessary -if (global.__RCTProfileIsProfiling) { - const Systrace = require('Systrace'); - Systrace.installReactHook(); - Systrace.setEnabled(true); -} - -// Set up console -const ExceptionsManager = require('ExceptionsManager'); -ExceptionsManager.installConsoleErrorReporter(); - -// Set up error handler -if (!global.__fbDisableExceptionsManager) { - const handleError = (e, isFatal) => { - try { - ExceptionsManager.handleException(e, isFatal); - } catch (ee) { - console.log('Failed to print error: ', ee.message); - throw e; - } - }; - - const ErrorUtils = require('ErrorUtils'); - ErrorUtils.setGlobalHandler(handleError); -} - -// Check for compatibility between the JS and native code -const ReactNativeVersionCheck = require('ReactNativeVersionCheck'); -ReactNativeVersionCheck.checkVersions(); - -// Set up Promise -// The native Promise implementation throws the following error: -// ERROR: Event loop not supported. -polyfillGlobal('Promise', () => require('Promise')); - -// Set up regenerator. -polyfillGlobal('regeneratorRuntime', () => { - // The require just sets up the global, so make sure when we first - // invoke it the global does not exist - delete global.regeneratorRuntime; - /* $FlowFixMe(>=0.54.0 site=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. */ - require('regenerator-runtime/runtime'); - return global.regeneratorRuntime; -}); - -// Set up timers -const defineLazyTimer = name => { - polyfillGlobal(name, () => require('JSTimers')[name]); -}; -defineLazyTimer('setTimeout'); -defineLazyTimer('setInterval'); -defineLazyTimer('setImmediate'); -defineLazyTimer('clearTimeout'); -defineLazyTimer('clearInterval'); -defineLazyTimer('clearImmediate'); -defineLazyTimer('requestAnimationFrame'); -defineLazyTimer('cancelAnimationFrame'); -defineLazyTimer('requestIdleCallback'); -defineLazyTimer('cancelIdleCallback'); - -// Set up XHR -// The native XMLHttpRequest in Chrome dev tools is CORS aware and won't -// let you fetch anything from the internet -polyfillGlobal('XMLHttpRequest', () => require('XMLHttpRequest')); -polyfillGlobal('FormData', () => require('FormData')); - -polyfillGlobal('fetch', () => require('fetch').fetch); -polyfillGlobal('Headers', () => require('fetch').Headers); -polyfillGlobal('Request', () => require('fetch').Request); -polyfillGlobal('Response', () => require('fetch').Response); -polyfillGlobal('WebSocket', () => require('WebSocket')); -polyfillGlobal('Blob', () => require('Blob')); -polyfillGlobal('File', () => require('File')); -polyfillGlobal('FileReader', () => require('FileReader')); -polyfillGlobal('URL', () => require('URL')); - -// Set up alert -if (!global.alert) { - global.alert = function(text) { - // Require Alert on demand. Requiring it too early can lead to issues - // with things like Platform not being fully initialized. - require('Alert').alert('Alert', '' + text); - }; -} - -// Set up Geolocation -let navigator = global.navigator; -if (navigator === undefined) { - global.navigator = navigator = {}; +const start = Date.now(); + +require('setUpGlobals'); +require('polyfillES6Collections'); +require('setUpSystrace'); +require('setUpErrorHandling'); +require('checkNativeVersion'); +require('polyfillPromise'); +require('setUpRegeneratorRuntime'); +require('setUpTimers'); +require('setUpXHR'); +require('setUpAlert'); +require('setUpGeolocation'); +require('setUpBatchedBridge'); +require('setUpSegmentFetcher'); +if (__DEV__) { + require('setUpDeveloperTools'); } -// see https://github.com/facebook/react-native/issues/10881 -polyfillObjectProperty(navigator, 'product', () => 'ReactNative'); -polyfillObjectProperty(navigator, 'geolocation', () => require('Geolocation')); - -// Just to make sure the JS gets packaged up. Wait until the JS environment has -// been initialized before requiring them. -const BatchedBridge = require('BatchedBridge'); -BatchedBridge.registerLazyCallableModule('Systrace', () => require('Systrace')); -BatchedBridge.registerLazyCallableModule('JSTimers', () => require('JSTimers')); -BatchedBridge.registerLazyCallableModule('HeapCapture', () => - require('HeapCapture'), -); -BatchedBridge.registerLazyCallableModule('SamplingProfiler', () => - require('SamplingProfiler'), -); -BatchedBridge.registerLazyCallableModule('RCTLog', () => require('RCTLog')); -BatchedBridge.registerLazyCallableModule('RCTDeviceEventEmitter', () => - require('RCTDeviceEventEmitter'), -); -BatchedBridge.registerLazyCallableModule('RCTNativeAppEventEmitter', () => - require('RCTNativeAppEventEmitter'), -); -BatchedBridge.registerLazyCallableModule('PerformanceLogger', () => - require('PerformanceLogger'), +const PerformanceLogger = require('PerformanceLogger'); +// We could just call PerformanceLogger.markPoint at the top of the file, +// but then we'd be excluding the time it took to require PerformanceLogger. +// Instead, we just use Date.now and backdate the timestamp. +PerformanceLogger.markPoint( + 'initializeCore_start', + PerformanceLogger.currentTimestamp() - (Date.now() - start), ); -BatchedBridge.registerLazyCallableModule('JSDevSupportModule', () => - require('JSDevSupportModule'), -); - -global.__fetchSegment = function( - segmentId: number, - options: {|+otaBuildNumber: ?string|}, - callback: (?Error) => void, -) { - const {SegmentFetcher} = require('NativeModules'); - if (!SegmentFetcher) { - throw new Error( - 'SegmentFetcher is missing. Please ensure that it is ' + - 'included as a NativeModule.', - ); - } - - SegmentFetcher.fetchSegment( - segmentId, - options, - (errorObject: ?{message: string, code: string}) => { - if (errorObject) { - const error = new Error(errorObject.message); - (error: any).code = errorObject.code; - callback(error); - } - - callback(null); - }, - ); -}; - -// Set up devtools -if (__DEV__) { - if (!global.__RCTProfileIsProfiling) { - BatchedBridge.registerCallableModule('HMRClient', require('HMRClient')); - - // not when debugging in chrome - // TODO(t12832058) This check is broken - if (!window.document) { - require('setupDevtools'); - } - - // Set up inspector - const JSInspector = require('JSInspector'); - /* $FlowFixMe(>=0.56.0 site=react_native_fb,react_native_oss) This comment - * suppresses an error found when Flow v0.56 was deployed. To see the error - * delete this comment and run Flow. */ - JSInspector.registerAgent(require('NetworkAgent')); - } -} +PerformanceLogger.markPoint('initializeCore_end'); diff --git a/Libraries/Core/ReactNativeVersion.js b/Libraries/Core/ReactNativeVersion.js index 1b2b2155f55175..1a0b78da1f7ee5 100644 --- a/Libraries/Core/ReactNativeVersion.js +++ b/Libraries/Core/ReactNativeVersion.js @@ -1,7 +1,7 @@ /** * @generated by scripts/bump-oss-version.js * - * Copyright (c) 2015-present, Facebook, Inc. + * 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. @@ -11,7 +11,7 @@ exports.version = { major: 0, - minor: 0, - patch: 0, + minor: 58, + patch: 6, prerelease: null, }; diff --git a/Libraries/Core/ReactNativeVersionCheck.js b/Libraries/Core/ReactNativeVersionCheck.js index 623ae4f3536b19..578b205645a487 100644 --- a/Libraries/Core/ReactNativeVersionCheck.js +++ b/Libraries/Core/ReactNativeVersionCheck.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2017-present, Facebook, Inc. + * 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. diff --git a/Libraries/Core/Timers/JSTimers.js b/Libraries/Core/Timers/JSTimers.js index 7cffb4e3d06d82..36a56fd8cf97cd 100644 --- a/Libraries/Core/Timers/JSTimers.js +++ b/Libraries/Core/Timers/JSTimers.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. @@ -290,6 +290,9 @@ const JSTimers = { * @param {function} func Callback to be invoked before the end of the * current JavaScript execution loop. */ + /* $FlowFixMe(>=0.79.1 site=react_native_fb) This comment suppresses an + * error found when Flow v0.79 was deployed. To see the error delete this + * comment and run Flow. */ setImmediate: function(func: Function, ...args: any) { const id = _allocateCallback( () => func.apply(undefined, args), @@ -302,6 +305,9 @@ const JSTimers = { /** * @param {function} func Callback to be invoked every frame. */ + /* $FlowFixMe(>=0.79.1 site=react_native_fb) This comment suppresses an + * error found when Flow v0.79 was deployed. To see the error delete this + * comment and run Flow. */ requestAnimationFrame: function(func: Function) { const id = _allocateCallback(func, 'requestAnimationFrame'); Timing.createTimer(id, 1, Date.now(), /* recurring */ false); @@ -313,6 +319,9 @@ const JSTimers = { * with time remaining in frame. * @param {?object} options */ + /* $FlowFixMe(>=0.79.1 site=react_native_fb) This comment suppresses an + * error found when Flow v0.79 was deployed. To see the error delete this + * comment and run Flow. */ requestIdleCallback: function(func: Function, options: ?Object) { if (requestIdleCallbacks.length === 0) { Timing.setSendIdleEvents(true); diff --git a/Libraries/Core/__mocks__/ErrorUtils.js b/Libraries/Core/__mocks__/ErrorUtils.js index 2719c138c4549d..8505e23dc562fc 100644 --- a/Libraries/Core/__mocks__/ErrorUtils.js +++ b/Libraries/Core/__mocks__/ErrorUtils.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2013-present, Facebook, Inc. + * 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. diff --git a/Libraries/Core/__tests__/ReactNativeVersionCheck-test.js b/Libraries/Core/__tests__/ReactNativeVersionCheck-test.js index e5c8cefddf15bb..6f4da360362e9f 100644 --- a/Libraries/Core/__tests__/ReactNativeVersionCheck-test.js +++ b/Libraries/Core/__tests__/ReactNativeVersionCheck-test.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2017-present, Facebook, Inc. + * 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. diff --git a/Libraries/Core/checkNativeVersion.js b/Libraries/Core/checkNativeVersion.js new file mode 100644 index 00000000000000..36a8b40ac530ba --- /dev/null +++ b/Libraries/Core/checkNativeVersion.js @@ -0,0 +1,17 @@ +/** + * 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. + * + * @flow strict-local + * @format + */ +'use strict'; + +/** + * Check for compatibility between the JS and native code. + * You can use this module directly, or just require InitializeCore. + */ +const ReactNativeVersionCheck = require('ReactNativeVersionCheck'); +ReactNativeVersionCheck.checkVersions(); diff --git a/Libraries/Core/polyfillES6Collections.js b/Libraries/Core/polyfillES6Collections.js new file mode 100644 index 00000000000000..ca1ee798c73f4c --- /dev/null +++ b/Libraries/Core/polyfillES6Collections.js @@ -0,0 +1,25 @@ +/** + * 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. + * + * @flow strict-local + * @format + */ +'use strict'; + +const {polyfillGlobal} = require('PolyfillFunctions'); + +/** + * Polyfill ES6 collections (Map and Set). + * If you don't need these polyfills, don't use InitializeCore; just directly + * require the modules you need from InitializeCore for setup. + */ +const _shouldPolyfillCollection = require('_shouldPolyfillES6Collection'); +if (_shouldPolyfillCollection('Map')) { + polyfillGlobal('Map', () => require('Map')); +} +if (_shouldPolyfillCollection('Set')) { + polyfillGlobal('Set', () => require('Set')); +} diff --git a/Libraries/Core/polyfillPromise.js b/Libraries/Core/polyfillPromise.js new file mode 100644 index 00000000000000..f2068df4e98a02 --- /dev/null +++ b/Libraries/Core/polyfillPromise.js @@ -0,0 +1,21 @@ +/** + * 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. + * + * @flow + * @format + */ +'use strict'; + +const {polyfillGlobal} = require('PolyfillFunctions'); + +/** + * Set up Promise. The native Promise implementation throws the following error: + * ERROR: Event loop not supported. + * + * If you don't need these polyfills, don't use InitializeCore; just directly + * require the modules you need from InitializeCore for setup. + */ +polyfillGlobal('Promise', () => require('Promise')); diff --git a/Libraries/Core/setUpAlert.js b/Libraries/Core/setUpAlert.js new file mode 100644 index 00000000000000..0b2bdc9f6a5273 --- /dev/null +++ b/Libraries/Core/setUpAlert.js @@ -0,0 +1,22 @@ +/** + * 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. + * + * @flow strict-local + * @format + */ +'use strict'; + +/** + * Set up alert(). + * You can use this module directly, or just require InitializeCore. + */ +if (!global.alert) { + global.alert = function(text) { + // Require Alert on demand. Requiring it too early can lead to issues + // with things like Platform not being fully initialized. + require('Alert').alert('Alert', '' + text); + }; +} diff --git a/Libraries/Core/setUpBatchedBridge.js b/Libraries/Core/setUpBatchedBridge.js new file mode 100644 index 00000000000000..fd936bf50426a3 --- /dev/null +++ b/Libraries/Core/setUpBatchedBridge.js @@ -0,0 +1,42 @@ +/** + * 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. + * + * @flow strict-local + * @format + */ +'use strict'; + +/** + * Set up the BatchedBridge. This must be done after the other steps in + * InitializeCore to ensure that the JS environment has been initialized. + * You can use this module directly, or just require InitializeCore. + */ +const BatchedBridge = require('BatchedBridge'); +BatchedBridge.registerLazyCallableModule('Systrace', () => require('Systrace')); +BatchedBridge.registerLazyCallableModule('JSTimers', () => require('JSTimers')); +BatchedBridge.registerLazyCallableModule('HeapCapture', () => + require('HeapCapture'), +); +BatchedBridge.registerLazyCallableModule('SamplingProfiler', () => + require('SamplingProfiler'), +); +BatchedBridge.registerLazyCallableModule('RCTLog', () => require('RCTLog')); +BatchedBridge.registerLazyCallableModule('RCTDeviceEventEmitter', () => + require('RCTDeviceEventEmitter'), +); +BatchedBridge.registerLazyCallableModule('RCTNativeAppEventEmitter', () => + require('RCTNativeAppEventEmitter'), +); +BatchedBridge.registerLazyCallableModule('PerformanceLogger', () => + require('PerformanceLogger'), +); +BatchedBridge.registerLazyCallableModule('JSDevSupportModule', () => + require('JSDevSupportModule'), +); + +if (__DEV__ && !global.__RCTProfileIsProfiling) { + BatchedBridge.registerCallableModule('HMRClient', require('HMRClient')); +} diff --git a/Libraries/Core/setUpDeveloperTools.js b/Libraries/Core/setUpDeveloperTools.js new file mode 100644 index 00000000000000..2ee713da0b4dae --- /dev/null +++ b/Libraries/Core/setUpDeveloperTools.js @@ -0,0 +1,28 @@ +/** + * 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. + * + * @flow strict-local + * @format + */ +'use strict'; + +/** + * Sets up developer tools for React Native. + * You can use this module directly, or just require InitializeCore. + */ +if (__DEV__) { + if (!global.__RCTProfileIsProfiling) { + // not when debugging in chrome + // TODO(t12832058) This check is broken + if (!window.document) { + require('setupDevtools'); + } + + // Set up inspector + const JSInspector = require('JSInspector'); + JSInspector.registerAgent(require('NetworkAgent')); + } +} diff --git a/Libraries/Core/setUpErrorHandling.js b/Libraries/Core/setUpErrorHandling.js new file mode 100644 index 00000000000000..7a9c566905d8f9 --- /dev/null +++ b/Libraries/Core/setUpErrorHandling.js @@ -0,0 +1,32 @@ +/** + * 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. + * + * @flow strict-local + * @format + */ +'use strict'; + +/** + * Sets up the console and exception handling (redbox) for React Native. + * You can use this module directly, or just require InitializeCore. + */ +const ExceptionsManager = require('ExceptionsManager'); +ExceptionsManager.installConsoleErrorReporter(); + +// Set up error handler +if (!global.__fbDisableExceptionsManager) { + const handleError = (e, isFatal) => { + try { + ExceptionsManager.handleException(e, isFatal); + } catch (ee) { + console.log('Failed to print error: ', ee.message); + throw e; + } + }; + + const ErrorUtils = require('ErrorUtils'); + ErrorUtils.setGlobalHandler(handleError); +} diff --git a/Libraries/Core/setUpGeolocation.js b/Libraries/Core/setUpGeolocation.js new file mode 100644 index 00000000000000..fd68182bce6bfb --- /dev/null +++ b/Libraries/Core/setUpGeolocation.js @@ -0,0 +1,25 @@ +/** + * 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. + * + * @flow strict-local + * @format + */ +'use strict'; + +const {polyfillObjectProperty} = require('PolyfillFunctions'); + +/** + * Set up Geolocation. + * You can use this module directly, or just require InitializeCore. + */ +let navigator = global.navigator; +if (navigator === undefined) { + global.navigator = navigator = {}; +} + +// see https://github.com/facebook/react-native/issues/10881 +polyfillObjectProperty(navigator, 'product', () => 'ReactNative'); +polyfillObjectProperty(navigator, 'geolocation', () => require('Geolocation')); diff --git a/Libraries/Core/setUpGlobals.js b/Libraries/Core/setUpGlobals.js new file mode 100644 index 00000000000000..0310f3c2bcf047 --- /dev/null +++ b/Libraries/Core/setUpGlobals.js @@ -0,0 +1,29 @@ +/** + * 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. + * + * @flow strict-local + * @format + */ +'use strict'; + +/** + * Sets up global variables for React Native. + * You can use this module directly, or just require InitializeCore. + */ +if (global.GLOBAL === undefined) { + global.GLOBAL = global; +} + +if (global.window === undefined) { + global.window = global; +} + +// Set up process +global.process = global.process || {}; +global.process.env = global.process.env || {}; +if (!global.process.env.NODE_ENV) { + global.process.env.NODE_ENV = __DEV__ ? 'development' : 'production'; +} diff --git a/Libraries/Core/setUpRegeneratorRuntime.js b/Libraries/Core/setUpRegeneratorRuntime.js new file mode 100644 index 00000000000000..26fb440c6d270a --- /dev/null +++ b/Libraries/Core/setUpRegeneratorRuntime.js @@ -0,0 +1,26 @@ +/** + * 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. + * + * @flow strict-local + * @format + */ +'use strict'; + +const {polyfillGlobal} = require('PolyfillFunctions'); + +/** + * Set up regenerator. + * You can use this module directly, or just require InitializeCore. + */ +polyfillGlobal('regeneratorRuntime', () => { + // The require just sets up the global, so make sure when we first + // invoke it the global does not exist + delete global.regeneratorRuntime; + + // regenerator-runtime/runtime exports the regeneratorRuntime object, so we + // can return it safely. + return require('regenerator-runtime/runtime'); // flowlint-line untyped-import:off +}); diff --git a/Libraries/Core/setUpSegmentFetcher.js b/Libraries/Core/setUpSegmentFetcher.js new file mode 100644 index 00000000000000..440caf380f31ac --- /dev/null +++ b/Libraries/Core/setUpSegmentFetcher.js @@ -0,0 +1,42 @@ +/** + * 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. + * + * @flow strict-local + * @format + */ +'use strict'; + +/** + * Set up SegmentFetcher. + * You can use this module directly, or just require InitializeCore. + */ +global.__fetchSegment = function( + segmentId: number, + options: {|+otaBuildNumber: ?string|}, + callback: (?Error) => void, +) { + const {SegmentFetcher} = require('NativeModules'); + if (!SegmentFetcher) { + throw new Error( + 'SegmentFetcher is missing. Please ensure that it is ' + + 'included as a NativeModule.', + ); + } + + SegmentFetcher.fetchSegment( + segmentId, + options, + (errorObject: ?{message: string, code: string}) => { + if (errorObject) { + const error = new Error(errorObject.message); + (error: any).code = errorObject.code; // flowlint-line unclear-type: off + callback(error); + } + + callback(null); + }, + ); +}; diff --git a/Libraries/Core/setUpSystrace.js b/Libraries/Core/setUpSystrace.js new file mode 100644 index 00000000000000..36a6bf40c0ff91 --- /dev/null +++ b/Libraries/Core/setUpSystrace.js @@ -0,0 +1,20 @@ +/** + * 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. + * + * @flow strict-local + * @format + */ +'use strict'; + +/** + * Set up Systrace profiling hooks if necessary. + * You can use this module directly, or just require InitializeCore. + */ +if (global.__RCTProfileIsProfiling) { + const Systrace = require('Systrace'); + Systrace.installReactHook(); + Systrace.setEnabled(true); +} diff --git a/Libraries/Core/setUpTimers.js b/Libraries/Core/setUpTimers.js new file mode 100644 index 00000000000000..1a95afa8751bed --- /dev/null +++ b/Libraries/Core/setUpTimers.js @@ -0,0 +1,30 @@ +/** + * 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. + * + * @flow strict-local + * @format + */ +'use strict'; + +const {polyfillGlobal} = require('PolyfillFunctions'); + +/** + * Set up timers. + * You can use this module directly, or just require InitializeCore. + */ +const defineLazyTimer = name => { + polyfillGlobal(name, () => require('JSTimers')[name]); +}; +defineLazyTimer('setTimeout'); +defineLazyTimer('setInterval'); +defineLazyTimer('setImmediate'); +defineLazyTimer('clearTimeout'); +defineLazyTimer('clearInterval'); +defineLazyTimer('clearImmediate'); +defineLazyTimer('requestAnimationFrame'); +defineLazyTimer('cancelAnimationFrame'); +defineLazyTimer('requestIdleCallback'); +defineLazyTimer('cancelIdleCallback'); diff --git a/Libraries/Core/setUpXHR.js b/Libraries/Core/setUpXHR.js new file mode 100644 index 00000000000000..ac528db6d7d50e --- /dev/null +++ b/Libraries/Core/setUpXHR.js @@ -0,0 +1,31 @@ +/** + * 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. + * + * @flow strict-local + * @format + */ +'use strict'; + +const {polyfillGlobal} = require('PolyfillFunctions'); + +/** + * Set up XMLHttpRequest. The native XMLHttpRequest in Chrome dev tools is CORS + * aware and won't let you fetch anything from the internet. + * + * You can use this module directly, or just require InitializeCore. + */ +polyfillGlobal('XMLHttpRequest', () => require('XMLHttpRequest')); +polyfillGlobal('FormData', () => require('FormData')); + +polyfillGlobal('fetch', () => require('fetch').fetch); // flowlint-line untyped-import:off +polyfillGlobal('Headers', () => require('fetch').Headers); // flowlint-line untyped-import:off +polyfillGlobal('Request', () => require('fetch').Request); // flowlint-line untyped-import:off +polyfillGlobal('Response', () => require('fetch').Response); // flowlint-line untyped-import:off +polyfillGlobal('WebSocket', () => require('WebSocket')); +polyfillGlobal('Blob', () => require('Blob')); +polyfillGlobal('File', () => require('File')); +polyfillGlobal('FileReader', () => require('FileReader')); +polyfillGlobal('URL', () => require('URL')); diff --git a/Libraries/StyleSheet/ColorPropType.js b/Libraries/DeprecatedPropTypes/DeprecatedColorPropType.js similarity index 96% rename from Libraries/StyleSheet/ColorPropType.js rename to Libraries/DeprecatedPropTypes/DeprecatedColorPropType.js index 93474c47ae234e..84d3b225a45f33 100644 --- a/Libraries/StyleSheet/ColorPropType.js +++ b/Libraries/DeprecatedPropTypes/DeprecatedColorPropType.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. diff --git a/Libraries/DeprecatedPropTypes/DeprecatedEdgeInsetsPropType.js b/Libraries/DeprecatedPropTypes/DeprecatedEdgeInsetsPropType.js new file mode 100644 index 00000000000000..67a016fffc8d24 --- /dev/null +++ b/Libraries/DeprecatedPropTypes/DeprecatedEdgeInsetsPropType.js @@ -0,0 +1,22 @@ +/** + * 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 strict + */ + +'use strict'; + +const PropTypes = require('prop-types'); + +const DeprecatedEdgeInsetsPropType = PropTypes.shape({ + top: PropTypes.number, + left: PropTypes.number, + bottom: PropTypes.number, + right: PropTypes.number, +}); + +module.exports = DeprecatedEdgeInsetsPropType; diff --git a/Libraries/DeprecatedPropTypes/DeprecatedImagePropType.js b/Libraries/DeprecatedPropTypes/DeprecatedImagePropType.js new file mode 100644 index 00000000000000..6b8c16b579d23e --- /dev/null +++ b/Libraries/DeprecatedPropTypes/DeprecatedImagePropType.js @@ -0,0 +1,65 @@ +/** + * 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. + * + * @flow + * @format + */ + +'use strict'; + +const DeprecatedEdgeInsetsPropType = require('DeprecatedEdgeInsetsPropType'); +const DeprecatedImageSourcePropType = require('DeprecatedImageSourcePropType'); +const DeprecatedImageStylePropTypes = require('DeprecatedImageStylePropTypes'); +const DeprecatedStyleSheetPropType = require('DeprecatedStyleSheetPropType'); +const PropTypes = require('prop-types'); + +module.exports = { + style: DeprecatedStyleSheetPropType(DeprecatedImageStylePropTypes), + source: DeprecatedImageSourcePropType, + defaultSource: PropTypes.oneOfType([ + PropTypes.shape({ + uri: PropTypes.string, + width: PropTypes.number, + height: PropTypes.number, + scale: PropTypes.number, + }), + PropTypes.number, + ]), + + accessible: PropTypes.bool, + + accessibilityLabel: PropTypes.node, + + blurRadius: PropTypes.number, + + capInsets: DeprecatedEdgeInsetsPropType, + + resizeMethod: PropTypes.oneOf(['auto', 'resize', 'scale']), + + resizeMode: PropTypes.oneOf([ + 'cover', + 'contain', + 'stretch', + 'repeat', + 'center', + ]), + + testID: PropTypes.string, + + onLayout: PropTypes.func, + + onLoadStart: PropTypes.func, + + onProgress: PropTypes.func, + + onError: PropTypes.func, + + onPartialLoad: PropTypes.func, + + onLoad: PropTypes.func, + + onLoadEnd: PropTypes.func, +}; diff --git a/Libraries/DeprecatedPropTypes/DeprecatedImageSourcePropType.js b/Libraries/DeprecatedPropTypes/DeprecatedImageSourcePropType.js new file mode 100644 index 00000000000000..0670023ae73ba2 --- /dev/null +++ b/Libraries/DeprecatedPropTypes/DeprecatedImageSourcePropType.js @@ -0,0 +1,39 @@ +/** + * 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. + * + * @no-flow + * @format + */ +'use strict'; + +const PropTypes = require('prop-types'); + +const ImageURISourcePropType = PropTypes.shape({ + uri: PropTypes.string, + bundle: PropTypes.string, + method: PropTypes.string, + headers: PropTypes.objectOf(PropTypes.string), + body: PropTypes.string, + cache: PropTypes.oneOf([ + 'default', + 'reload', + 'force-cache', + 'only-if-cached', + ]), + width: PropTypes.number, + height: PropTypes.number, + scale: PropTypes.number, +}); + +const ImageSourcePropType = PropTypes.oneOfType([ + ImageURISourcePropType, + // Opaque type returned by require('./image.jpg') + PropTypes.number, + // Multiple sources + PropTypes.arrayOf(ImageURISourcePropType), +]); + +module.exports = ImageSourcePropType; diff --git a/Libraries/Image/ImageStylePropTypes.js b/Libraries/DeprecatedPropTypes/DeprecatedImageStylePropTypes.js similarity index 69% rename from Libraries/Image/ImageStylePropTypes.js rename to Libraries/DeprecatedPropTypes/DeprecatedImageStylePropTypes.js index 54e500994227db..3fbed21da30fe0 100644 --- a/Libraries/Image/ImageStylePropTypes.js +++ b/Libraries/DeprecatedPropTypes/DeprecatedImageStylePropTypes.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. @@ -9,21 +9,26 @@ */ 'use strict'; -const ColorPropType = require('ColorPropType'); -const ImageResizeMode = require('ImageResizeMode'); -const LayoutPropTypes = require('LayoutPropTypes'); +const DeprecatedColorPropType = require('DeprecatedColorPropType'); +const DeprecatedLayoutPropTypes = require('DeprecatedLayoutPropTypes'); const ReactPropTypes = require('prop-types'); -const ShadowPropTypesIOS = require('ShadowPropTypesIOS'); -const TransformPropTypes = require('TransformPropTypes'); +const DeprecatedShadowPropTypesIOS = require('DeprecatedShadowPropTypesIOS'); +const DeprecatedTransformPropTypes = require('DeprecatedTransformPropTypes'); const ImageStylePropTypes = { - ...LayoutPropTypes, - ...ShadowPropTypesIOS, - ...TransformPropTypes, - resizeMode: ReactPropTypes.oneOf(Object.keys(ImageResizeMode)), + ...DeprecatedLayoutPropTypes, + ...DeprecatedShadowPropTypesIOS, + ...DeprecatedTransformPropTypes, + resizeMode: ReactPropTypes.oneOf([ + 'center', + 'contain', + 'cover', + 'repeat', + 'stretch', + ]), backfaceVisibility: ReactPropTypes.oneOf(['visible', 'hidden']), - backgroundColor: ColorPropType, - borderColor: ColorPropType, + backgroundColor: DeprecatedColorPropType, + borderColor: DeprecatedColorPropType, borderWidth: ReactPropTypes.number, borderRadius: ReactPropTypes.number, overflow: ReactPropTypes.oneOf(['visible', 'hidden']), @@ -31,7 +36,7 @@ const ImageStylePropTypes = { /** * Changes the color of all the non-transparent pixels to the tintColor. */ - tintColor: ColorPropType, + tintColor: DeprecatedColorPropType, opacity: ReactPropTypes.number, /** * When the image has rounded corners, specifying an overlayColor will diff --git a/Libraries/DeprecatedPropTypes/DeprecatedLayoutPropTypes.js b/Libraries/DeprecatedPropTypes/DeprecatedLayoutPropTypes.js new file mode 100644 index 00000000000000..0ebccaa8d07083 --- /dev/null +++ b/Libraries/DeprecatedPropTypes/DeprecatedLayoutPropTypes.js @@ -0,0 +1,190 @@ +/** + * 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 strict + */ + +'use strict'; + +const ReactPropTypes = require('prop-types'); + +const LayoutPropTypes = { + display: ReactPropTypes.oneOf(['none', 'flex']), + width: ReactPropTypes.oneOfType([ + ReactPropTypes.number, + ReactPropTypes.string, + ]), + height: ReactPropTypes.oneOfType([ + ReactPropTypes.number, + ReactPropTypes.string, + ]), + start: ReactPropTypes.oneOfType([ + ReactPropTypes.number, + ReactPropTypes.string, + ]), + end: ReactPropTypes.oneOfType([ReactPropTypes.number, ReactPropTypes.string]), + top: ReactPropTypes.oneOfType([ReactPropTypes.number, ReactPropTypes.string]), + left: ReactPropTypes.oneOfType([ + ReactPropTypes.number, + ReactPropTypes.string, + ]), + right: ReactPropTypes.oneOfType([ + ReactPropTypes.number, + ReactPropTypes.string, + ]), + bottom: ReactPropTypes.oneOfType([ + ReactPropTypes.number, + ReactPropTypes.string, + ]), + minWidth: ReactPropTypes.oneOfType([ + ReactPropTypes.number, + ReactPropTypes.string, + ]), + maxWidth: ReactPropTypes.oneOfType([ + ReactPropTypes.number, + ReactPropTypes.string, + ]), + minHeight: ReactPropTypes.oneOfType([ + ReactPropTypes.number, + ReactPropTypes.string, + ]), + maxHeight: ReactPropTypes.oneOfType([ + ReactPropTypes.number, + ReactPropTypes.string, + ]), + margin: ReactPropTypes.oneOfType([ + ReactPropTypes.number, + ReactPropTypes.string, + ]), + marginVertical: ReactPropTypes.oneOfType([ + ReactPropTypes.number, + ReactPropTypes.string, + ]), + marginHorizontal: ReactPropTypes.oneOfType([ + ReactPropTypes.number, + ReactPropTypes.string, + ]), + marginTop: ReactPropTypes.oneOfType([ + ReactPropTypes.number, + ReactPropTypes.string, + ]), + marginBottom: ReactPropTypes.oneOfType([ + ReactPropTypes.number, + ReactPropTypes.string, + ]), + marginLeft: ReactPropTypes.oneOfType([ + ReactPropTypes.number, + ReactPropTypes.string, + ]), + marginRight: ReactPropTypes.oneOfType([ + ReactPropTypes.number, + ReactPropTypes.string, + ]), + marginStart: ReactPropTypes.oneOfType([ + ReactPropTypes.number, + ReactPropTypes.string, + ]), + marginEnd: ReactPropTypes.oneOfType([ + ReactPropTypes.number, + ReactPropTypes.string, + ]), + padding: ReactPropTypes.oneOfType([ + ReactPropTypes.number, + ReactPropTypes.string, + ]), + paddingVertical: ReactPropTypes.oneOfType([ + ReactPropTypes.number, + ReactPropTypes.string, + ]), + paddingHorizontal: ReactPropTypes.oneOfType([ + ReactPropTypes.number, + ReactPropTypes.string, + ]), + paddingTop: ReactPropTypes.oneOfType([ + ReactPropTypes.number, + ReactPropTypes.string, + ]), + paddingBottom: ReactPropTypes.oneOfType([ + ReactPropTypes.number, + ReactPropTypes.string, + ]), + paddingLeft: ReactPropTypes.oneOfType([ + ReactPropTypes.number, + ReactPropTypes.string, + ]), + paddingRight: ReactPropTypes.oneOfType([ + ReactPropTypes.number, + ReactPropTypes.string, + ]), + paddingStart: ReactPropTypes.oneOfType([ + ReactPropTypes.number, + ReactPropTypes.string, + ]), + paddingEnd: ReactPropTypes.oneOfType([ + ReactPropTypes.number, + ReactPropTypes.string, + ]), + borderWidth: ReactPropTypes.number, + borderTopWidth: ReactPropTypes.number, + borderStartWidth: ReactPropTypes.number, + borderEndWidth: ReactPropTypes.number, + borderRightWidth: ReactPropTypes.number, + borderBottomWidth: ReactPropTypes.number, + borderLeftWidth: ReactPropTypes.number, + position: ReactPropTypes.oneOf(['absolute', 'relative']), + flexDirection: ReactPropTypes.oneOf([ + 'row', + 'row-reverse', + 'column', + 'column-reverse', + ]), + flexWrap: ReactPropTypes.oneOf(['wrap', 'nowrap', 'wrap-reverse']), + justifyContent: ReactPropTypes.oneOf([ + 'flex-start', + 'flex-end', + 'center', + 'space-between', + 'space-around', + 'space-evenly', + ]), + alignItems: ReactPropTypes.oneOf([ + 'flex-start', + 'flex-end', + 'center', + 'stretch', + 'baseline', + ]), + alignSelf: ReactPropTypes.oneOf([ + 'auto', + 'flex-start', + 'flex-end', + 'center', + 'stretch', + 'baseline', + ]), + alignContent: ReactPropTypes.oneOf([ + 'flex-start', + 'flex-end', + 'center', + 'stretch', + 'space-between', + 'space-around', + ]), + overflow: ReactPropTypes.oneOf(['visible', 'hidden', 'scroll']), + flex: ReactPropTypes.number, + flexGrow: ReactPropTypes.number, + flexShrink: ReactPropTypes.number, + flexBasis: ReactPropTypes.oneOfType([ + ReactPropTypes.number, + ReactPropTypes.string, + ]), + aspectRatio: ReactPropTypes.number, + zIndex: ReactPropTypes.number, + direction: ReactPropTypes.oneOf(['inherit', 'ltr', 'rtl']), +}; + +module.exports = LayoutPropTypes; diff --git a/Libraries/DeprecatedPropTypes/DeprecatedPointPropType.js b/Libraries/DeprecatedPropTypes/DeprecatedPointPropType.js new file mode 100644 index 00000000000000..9ae8c8f9872d5c --- /dev/null +++ b/Libraries/DeprecatedPropTypes/DeprecatedPointPropType.js @@ -0,0 +1,20 @@ +/** + * 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 strict + */ + +'use strict'; + +const PropTypes = require('prop-types'); + +const PointPropType = PropTypes.shape({ + x: PropTypes.number, + y: PropTypes.number, +}); + +module.exports = PointPropType; diff --git a/Libraries/DeprecatedPropTypes/DeprecatedShadowPropTypesIOS.js b/Libraries/DeprecatedPropTypes/DeprecatedShadowPropTypesIOS.js new file mode 100644 index 00000000000000..889b5624938736 --- /dev/null +++ b/Libraries/DeprecatedPropTypes/DeprecatedShadowPropTypesIOS.js @@ -0,0 +1,25 @@ +/** + * 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. + * + * @flow + * @format + */ +'use strict'; + +const DeprecatedColorPropType = require('DeprecatedColorPropType'); +const ReactPropTypes = require('prop-types'); + +const DeprecatedShadowPropTypesIOS = { + shadowColor: DeprecatedColorPropType, + shadowOffset: ReactPropTypes.shape({ + width: ReactPropTypes.number, + height: ReactPropTypes.number, + }), + shadowOpacity: ReactPropTypes.number, + shadowRadius: ReactPropTypes.number, +}; + +module.exports = DeprecatedShadowPropTypesIOS; diff --git a/Libraries/StyleSheet/StyleSheetPropType.js b/Libraries/DeprecatedPropTypes/DeprecatedStyleSheetPropType.js similarity index 67% rename from Libraries/StyleSheet/StyleSheetPropType.js rename to Libraries/DeprecatedPropTypes/DeprecatedStyleSheetPropType.js index 97674b9a1e4f33..9cad5470ad7374 100644 --- a/Libraries/StyleSheet/StyleSheetPropType.js +++ b/Libraries/DeprecatedPropTypes/DeprecatedStyleSheetPropType.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. @@ -10,13 +10,13 @@ 'use strict'; -const createStrictShapeTypeChecker = require('createStrictShapeTypeChecker'); +const deprecatedCreateStrictShapeTypeChecker = require('deprecatedCreateStrictShapeTypeChecker'); const flattenStyle = require('flattenStyle'); -function StyleSheetPropType(shape: { +function DeprecatedStyleSheetPropType(shape: { [key: string]: ReactPropsCheckType, }): ReactPropsCheckType { - const shapePropType = createStrictShapeTypeChecker(shape); + const shapePropType = deprecatedCreateStrictShapeTypeChecker(shape); return function(props, propName, componentName, location?, ...rest) { let newProps = props; if (props[propName]) { @@ -28,4 +28,4 @@ function StyleSheetPropType(shape: { }; } -module.exports = StyleSheetPropType; +module.exports = DeprecatedStyleSheetPropType; diff --git a/Libraries/DeprecatedPropTypes/DeprecatedTVViewPropTypes.js b/Libraries/DeprecatedPropTypes/DeprecatedTVViewPropTypes.js new file mode 100644 index 00000000000000..90af60cc27da35 --- /dev/null +++ b/Libraries/DeprecatedPropTypes/DeprecatedTVViewPropTypes.js @@ -0,0 +1,25 @@ +/** + * 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'; + +const PropTypes = require('prop-types'); + +const DeprecatedTVViewPropTypes = { + isTVSelectable: PropTypes.bool, + hasTVPreferredFocus: PropTypes.bool, + tvParallaxProperties: PropTypes.object, + tvParallaxShiftDistanceX: PropTypes.number, + tvParallaxShiftDistanceY: PropTypes.number, + tvParallaxTiltAngle: PropTypes.number, + tvParallaxMagnification: PropTypes.number, +}; + +module.exports = DeprecatedTVViewPropTypes; diff --git a/Libraries/DeprecatedPropTypes/DeprecatedTextPropTypes.js b/Libraries/DeprecatedPropTypes/DeprecatedTextPropTypes.js new file mode 100644 index 00000000000000..1723bb56cb6cdd --- /dev/null +++ b/Libraries/DeprecatedPropTypes/DeprecatedTextPropTypes.js @@ -0,0 +1,41 @@ +/** + * 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. + * + * @flow + * @format + */ + +'use strict'; + +const DeprecatedColorPropType = require('DeprecatedColorPropType'); +const DeprecatedEdgeInsetsPropType = require('DeprecatedEdgeInsetsPropType'); +const DeprecatedStyleSheetPropType = require('DeprecatedStyleSheetPropType'); +const PropTypes = require('prop-types'); +const TextStylePropTypes = require('TextStylePropTypes'); + +const stylePropType = DeprecatedStyleSheetPropType(TextStylePropTypes); + +module.exports = { + ellipsizeMode: PropTypes.oneOf(['head', 'middle', 'tail', 'clip']), + numberOfLines: PropTypes.number, + textBreakStrategy: PropTypes.oneOf(['simple', 'highQuality', 'balanced']), + onLayout: PropTypes.func, + onPress: PropTypes.func, + onLongPress: PropTypes.func, + pressRetentionOffset: DeprecatedEdgeInsetsPropType, + selectable: PropTypes.bool, + selectionColor: DeprecatedColorPropType, + suppressHighlighting: PropTypes.bool, + style: stylePropType, + testID: PropTypes.string, + nativeID: PropTypes.string, + allowFontScaling: PropTypes.bool, + maxFontSizeMultiplier: PropTypes.number, + accessible: PropTypes.bool, + adjustsFontSizeToFit: PropTypes.bool, + minimumFontScale: PropTypes.number, + disabled: PropTypes.bool, +}; diff --git a/Libraries/StyleSheet/TransformPropTypes.js b/Libraries/DeprecatedPropTypes/DeprecatedTransformPropTypes.js similarity index 70% rename from Libraries/StyleSheet/TransformPropTypes.js rename to Libraries/DeprecatedPropTypes/DeprecatedTransformPropTypes.js index 105df3f073b9ad..a463dcc1cd15db 100644 --- a/Libraries/StyleSheet/TransformPropTypes.js +++ b/Libraries/DeprecatedPropTypes/DeprecatedTransformPropTypes.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. @@ -40,23 +40,7 @@ const DecomposedMatrixPropType = function( } }; -const TransformPropTypes = { - /** - * `transform` accepts an array of transformation objects. Each object specifies - * the property that will be transformed as the key, and the value to use in the - * transformation. Objects should not be combined. Use a single key/value pair - * per object. - * - * The rotate transformations require a string so that the transform may be - * expressed in degrees (deg) or radians (rad). For example: - * - * `transform([{ rotateX: '45deg' }, { rotateZ: '0.785398rad' }])` - * - * The skew transformations require a string so that the transform may be - * expressed in degrees (deg). For example: - * - * `transform([{ skewX: '45deg' }])` - */ +const DeprecatedTransformPropTypes = { transform: ReactPropTypes.arrayOf( ReactPropTypes.oneOfType([ ReactPropTypes.shape({perspective: ReactPropTypes.number}), @@ -73,17 +57,8 @@ const TransformPropTypes = { ReactPropTypes.shape({skewY: ReactPropTypes.string}), ]), ), - - /** - * Deprecated. Use the transform prop instead. - */ transformMatrix: TransformMatrixPropType, - /** - * Deprecated. Use the transform prop instead. - */ decomposedMatrix: DecomposedMatrixPropType, - - /* Deprecated transform props used on Android only */ scaleX: deprecatedPropType( ReactPropTypes.number, 'Use the transform prop instead.', @@ -106,4 +81,4 @@ const TransformPropTypes = { ), }; -module.exports = TransformPropTypes; +module.exports = DeprecatedTransformPropTypes; diff --git a/Libraries/DeprecatedPropTypes/DeprecatedViewAccessibility.js b/Libraries/DeprecatedPropTypes/DeprecatedViewAccessibility.js new file mode 100644 index 00000000000000..890dd49f0f8672 --- /dev/null +++ b/Libraries/DeprecatedPropTypes/DeprecatedViewAccessibility.js @@ -0,0 +1,55 @@ +/** + * 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 strict + */ + +'use strict'; + +module.exports = { + DeprecatedAccessibilityTraits: [ + 'none', + 'button', + 'link', + 'header', + 'search', + 'image', + 'selected', + 'plays', + 'key', + 'text', + 'summary', + 'disabled', + 'frequentUpdates', + 'startsMedia', + 'adjustable', + 'allowsDirectInteraction', + 'pageTurn', + ], + DeprecatedAccessibilityComponentTypes: [ + 'none', + 'button', + 'radiobutton_checked', + 'radiobutton_unchecked', + ], + // This must be kept in sync with the AccessibilityRolesMask in RCTViewManager.m + DeprecatedAccessibilityRoles: [ + 'none', + 'button', + 'link', + 'search', + 'image', + 'keyboardkey', + 'text', + 'adjustable', + 'imagebutton', + 'header', + 'summary', + ], + // This must be kept in sync with the AccessibilityStatesMask in RCTViewManager.m + DeprecatedAccessibilityStates: ['selected', 'disabled'], +}; diff --git a/Libraries/DeprecatedPropTypes/DeprecatedViewPropTypes.js b/Libraries/DeprecatedPropTypes/DeprecatedViewPropTypes.js new file mode 100644 index 00000000000000..0d5b0746c4a3d8 --- /dev/null +++ b/Libraries/DeprecatedPropTypes/DeprecatedViewPropTypes.js @@ -0,0 +1,409 @@ +/** + * 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'; + +const DeprecatedEdgeInsetsPropType = require('DeprecatedEdgeInsetsPropType'); +const PlatformViewPropTypes = require('PlatformViewPropTypes'); +const PropTypes = require('prop-types'); +const DeprecatedStyleSheetPropType = require('DeprecatedStyleSheetPropType'); +const DeprecatedViewStylePropTypes = require('DeprecatedViewStylePropTypes'); + +const { + DeprecatedAccessibilityComponentTypes, + DeprecatedAccessibilityTraits, + DeprecatedAccessibilityRoles, + DeprecatedAccessibilityStates, +} = require('DeprecatedViewAccessibility'); + +const stylePropType = DeprecatedStyleSheetPropType( + DeprecatedViewStylePropTypes, +); + +module.exports = { + /** + * When `true`, indicates that the view is an accessibility element. + * By default, all the touchable elements are accessible. + * + * See http://facebook.github.io/react-native/docs/view.html#accessible + */ + accessible: PropTypes.bool, + + /** + * Overrides the text that's read by the screen reader when the user interacts + * with the element. By default, the label is constructed by traversing all + * the children and accumulating all the `Text` nodes separated by space. + * + * See http://facebook.github.io/react-native/docs/view.html#accessibilitylabel + */ + accessibilityLabel: PropTypes.node, + + /** + * An accessibility hint helps users understand what will happen when they perform + * an action on the accessibility element when that result is not obvious from the + * accessibility label. + * + * + * See http://facebook.github.io/react-native/docs/view.html#accessibilityHint + */ + accessibilityHint: PropTypes.string, + + /** + * Provides an array of custom actions available for accessibility. + * + * @platform ios + */ + accessibilityActions: PropTypes.arrayOf(PropTypes.string), + + /** + * Prevents view from being inverted if set to true and color inversion is turned on. + * + * @platform ios + */ + accessibilityIgnoresInvertColors: PropTypes.bool, + + /** + * Indicates to accessibility services to treat UI component like a + * native one. Works for Android only. + * + * @platform android + * + * See http://facebook.github.io/react-native/docs/view.html#accessibilitycomponenttype + */ + accessibilityComponentType: PropTypes.oneOf( + DeprecatedAccessibilityComponentTypes, + ), + + /** + * Indicates to accessibility services to treat UI component like a specific role. + */ + accessibilityRole: PropTypes.oneOf(DeprecatedAccessibilityRoles), + + /** + * Indicates to accessibility services that UI Component is in a specific State. + */ + accessibilityStates: PropTypes.arrayOf( + PropTypes.oneOf(DeprecatedAccessibilityStates), + ), + /** + * Indicates to accessibility services whether the user should be notified + * when this view changes. Works for Android API >= 19 only. + * + * @platform android + * + * See http://facebook.github.io/react-native/docs/view.html#accessibilityliveregion + */ + accessibilityLiveRegion: PropTypes.oneOf(['none', 'polite', 'assertive']), + + /** + * Controls how view is important for accessibility which is if it + * fires accessibility events and if it is reported to accessibility services + * that query the screen. Works for Android only. + * + * @platform android + * + * See http://facebook.github.io/react-native/docs/view.html#importantforaccessibility + */ + importantForAccessibility: PropTypes.oneOf([ + 'auto', + 'yes', + 'no', + 'no-hide-descendants', + ]), + + /** + * Provides additional traits to screen reader. By default no traits are + * provided unless specified otherwise in element. + * + * You can provide one trait or an array of many traits. + * + * @platform ios + * + * See http://facebook.github.io/react-native/docs/view.html#accessibilitytraits + */ + accessibilityTraits: PropTypes.oneOfType([ + PropTypes.oneOf(DeprecatedAccessibilityTraits), + PropTypes.arrayOf(PropTypes.oneOf(DeprecatedAccessibilityTraits)), + ]), + + /** + * A value indicating whether VoiceOver should ignore the elements + * within views that are siblings of the receiver. + * Default is `false`. + * + * @platform ios + * + * See http://facebook.github.io/react-native/docs/view.html#accessibilityviewismodal + */ + accessibilityViewIsModal: PropTypes.bool, + + /** + * A value indicating whether the accessibility elements contained within + * this accessibility element are hidden. + * + * @platform ios + * + * See http://facebook.github.io/react-native/docs/view.html#accessibilityElementsHidden + */ + accessibilityElementsHidden: PropTypes.bool, + + /** + * When `accessible` is true, the system will try to invoke this function + * when the user performs an accessibility custom action. + * + * @platform ios + */ + onAccessibilityAction: PropTypes.func, + + /** + * When `accessible` is true, the system will try to invoke this function + * when the user performs accessibility tap gesture. + * + * See http://facebook.github.io/react-native/docs/view.html#onaccessibilitytap + */ + onAccessibilityTap: PropTypes.func, + + /** + * When `accessible` is `true`, the system will invoke this function when the + * user performs the magic tap gesture. + * + * See http://facebook.github.io/react-native/docs/view.html#onmagictap + */ + onMagicTap: PropTypes.func, + + /** + * Used to locate this view in end-to-end tests. + * + * > This disables the 'layout-only view removal' optimization for this view! + * + * See http://facebook.github.io/react-native/docs/view.html#testid + */ + testID: PropTypes.string, + + /** + * Used to locate this view from native classes. + * + * > This disables the 'layout-only view removal' optimization for this view! + * + * See http://facebook.github.io/react-native/docs/view.html#nativeid + */ + nativeID: PropTypes.string, + + /** + * For most touch interactions, you'll simply want to wrap your component in + * `TouchableHighlight` or `TouchableOpacity`. Check out `Touchable.js`, + * `ScrollResponder.js` and `ResponderEventPlugin.js` for more discussion. + */ + + /** + * The View is now responding for touch events. This is the time to highlight + * and show the user what is happening. + * + * `View.props.onResponderGrant: (event) => {}`, where `event` is a synthetic + * touch event as described above. + * + * See http://facebook.github.io/react-native/docs/view.html#onrespondergrant + */ + onResponderGrant: PropTypes.func, + + /** + * The user is moving their finger. + * + * `View.props.onResponderMove: (event) => {}`, where `event` is a synthetic + * touch event as described above. + * + * See http://facebook.github.io/react-native/docs/view.html#onrespondermove + */ + onResponderMove: PropTypes.func, + + /** + * Another responder is already active and will not release it to that `View` + * asking to be the responder. + * + * `View.props.onResponderReject: (event) => {}`, where `event` is a + * synthetic touch event as described above. + * + * See http://facebook.github.io/react-native/docs/view.html#onresponderreject + */ + onResponderReject: PropTypes.func, + + /** + * Fired at the end of the touch. + * + * `View.props.onResponderRelease: (event) => {}`, where `event` is a + * synthetic touch event as described above. + * + * See http://facebook.github.io/react-native/docs/view.html#onresponderrelease + */ + onResponderRelease: PropTypes.func, + + /** + * The responder has been taken from the `View`. Might be taken by other + * views after a call to `onResponderTerminationRequest`, or might be taken + * by the OS without asking (e.g., happens with control center/ notification + * center on iOS) + * + * `View.props.onResponderTerminate: (event) => {}`, where `event` is a + * synthetic touch event as described above. + * + * See http://facebook.github.io/react-native/docs/view.html#onresponderterminate + */ + onResponderTerminate: PropTypes.func, + + /** + * Some other `View` wants to become responder and is asking this `View` to + * release its responder. Returning `true` allows its release. + * + * `View.props.onResponderTerminationRequest: (event) => {}`, where `event` + * is a synthetic touch event as described above. + * + * See http://facebook.github.io/react-native/docs/view.html#onresponderterminationrequest + */ + onResponderTerminationRequest: PropTypes.func, + + /** + * Does this view want to become responder on the start of a touch? + * + * `View.props.onStartShouldSetResponder: (event) => [true | false]`, where + * `event` is a synthetic touch event as described above. + * + * See http://facebook.github.io/react-native/docs/view.html#onstartshouldsetresponder + */ + onStartShouldSetResponder: PropTypes.func, + + /** + * If a parent `View` wants to prevent a child `View` from becoming responder + * on a touch start, it should have this handler which returns `true`. + * + * `View.props.onStartShouldSetResponderCapture: (event) => [true | false]`, + * where `event` is a synthetic touch event as described above. + * + * See http://facebook.github.io/react-native/docs/view.html#onstartshouldsetrespondercapture + */ + onStartShouldSetResponderCapture: PropTypes.func, + + /** + * Does this view want to "claim" touch responsiveness? This is called for + * every touch move on the `View` when it is not the responder. + * + * `View.props.onMoveShouldSetResponder: (event) => [true | false]`, where + * `event` is a synthetic touch event as described above. + * + * See http://facebook.github.io/react-native/docs/view.html#onmoveshouldsetresponder + */ + onMoveShouldSetResponder: PropTypes.func, + + /** + * If a parent `View` wants to prevent a child `View` from becoming responder + * on a move, it should have this handler which returns `true`. + * + * `View.props.onMoveShouldSetResponderCapture: (event) => [true | false]`, + * where `event` is a synthetic touch event as described above. + * + * See http://facebook.github.io/react-native/docs/view.html#onMoveShouldsetrespondercapture + */ + onMoveShouldSetResponderCapture: PropTypes.func, + + /** + * This defines how far a touch event can start away from the view. + * Typical interface guidelines recommend touch targets that are at least + * 30 - 40 points/density-independent pixels. + * + * > The touch area never extends past the parent view bounds and the Z-index + * > of sibling views always takes precedence if a touch hits two overlapping + * > views. + * + * See http://facebook.github.io/react-native/docs/view.html#hitslop + */ + hitSlop: DeprecatedEdgeInsetsPropType, + + /** + * Invoked on mount and layout changes with: + * + * `{nativeEvent: { layout: {x, y, width, height}}}` + * + * This event is fired immediately once the layout has been calculated, but + * the new layout may not yet be reflected on the screen at the time the + * event is received, especially if a layout animation is in progress. + * + * See http://facebook.github.io/react-native/docs/view.html#onlayout + */ + onLayout: PropTypes.func, + + /** + * Controls whether the `View` can be the target of touch events. + * + * See http://facebook.github.io/react-native/docs/view.html#pointerevents + */ + pointerEvents: PropTypes.oneOf(['box-none', 'none', 'box-only', 'auto']), + + /** + * See http://facebook.github.io/react-native/docs/style.html + */ + style: stylePropType, + + /** + * This is a special performance property exposed by `RCTView` and is useful + * for scrolling content when there are many subviews, most of which are + * offscreen. For this property to be effective, it must be applied to a + * view that contains many subviews that extend outside its bound. The + * subviews must also have `overflow: hidden`, as should the containing view + * (or one of its superviews). + * + * See http://facebook.github.io/react-native/docs/view.html#removeclippedsubviews + */ + removeClippedSubviews: PropTypes.bool, + + /** + * Whether this `View` should render itself (and all of its children) into a + * single hardware texture on the GPU. + * + * @platform android + * + * See http://facebook.github.io/react-native/docs/view.html#rendertohardwaretextureandroid + */ + renderToHardwareTextureAndroid: PropTypes.bool, + + /** + * Whether this `View` should be rendered as a bitmap before compositing. + * + * @platform ios + * + * See http://facebook.github.io/react-native/docs/view.html#shouldrasterizeios + */ + shouldRasterizeIOS: PropTypes.bool, + + /** + * Views that are only used to layout their children or otherwise don't draw + * anything may be automatically removed from the native hierarchy as an + * optimization. Set this property to `false` to disable this optimization and + * ensure that this `View` exists in the native view hierarchy. + * + * @platform android + * + * See http://facebook.github.io/react-native/docs/view.html#collapsable + */ + collapsable: PropTypes.bool, + + /** + * Whether this `View` needs to rendered offscreen and composited with an + * alpha in order to preserve 100% correct colors and blending behavior. + * + * @platform android + * + * See http://facebook.github.io/react-native/docs/view.html#needsoffscreenalphacompositing + */ + needsOffscreenAlphaCompositing: PropTypes.bool, + + /** + * Any additional platform-specific view prop types, or prop type overrides. + */ + ...PlatformViewPropTypes, +}; diff --git a/Libraries/Components/View/ViewStylePropTypes.js b/Libraries/DeprecatedPropTypes/DeprecatedViewStylePropTypes.js similarity index 63% rename from Libraries/Components/View/ViewStylePropTypes.js rename to Libraries/DeprecatedPropTypes/DeprecatedViewStylePropTypes.js index 8f690fb32f6891..546da9cee33e8d 100644 --- a/Libraries/Components/View/ViewStylePropTypes.js +++ b/Libraries/DeprecatedPropTypes/DeprecatedViewStylePropTypes.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. @@ -10,28 +10,28 @@ 'use strict'; -const ColorPropType = require('ColorPropType'); -const LayoutPropTypes = require('LayoutPropTypes'); +const DeprecatedColorPropType = require('DeprecatedColorPropType'); +const DeprecatedLayoutPropTypes = require('DeprecatedLayoutPropTypes'); const ReactPropTypes = require('prop-types'); -const ShadowPropTypesIOS = require('ShadowPropTypesIOS'); -const TransformPropTypes = require('TransformPropTypes'); +const DeprecatedShadowPropTypesIOS = require('DeprecatedShadowPropTypesIOS'); +const DeprecatedTransformPropTypes = require('DeprecatedTransformPropTypes'); /** * Warning: Some of these properties may not be supported in all releases. */ -const ViewStylePropTypes = { - ...LayoutPropTypes, - ...ShadowPropTypesIOS, - ...TransformPropTypes, +const DeprecatedViewStylePropTypes = { + ...DeprecatedLayoutPropTypes, + ...DeprecatedShadowPropTypesIOS, + ...DeprecatedTransformPropTypes, backfaceVisibility: ReactPropTypes.oneOf(['visible', 'hidden']), - backgroundColor: ColorPropType, - borderColor: ColorPropType, - borderTopColor: ColorPropType, - borderRightColor: ColorPropType, - borderBottomColor: ColorPropType, - borderLeftColor: ColorPropType, - borderStartColor: ColorPropType, - borderEndColor: ColorPropType, + backgroundColor: DeprecatedColorPropType, + borderColor: DeprecatedColorPropType, + borderTopColor: DeprecatedColorPropType, + borderRightColor: DeprecatedColorPropType, + borderBottomColor: DeprecatedColorPropType, + borderLeftColor: DeprecatedColorPropType, + borderStartColor: DeprecatedColorPropType, + borderEndColor: DeprecatedColorPropType, borderRadius: ReactPropTypes.number, borderTopLeftRadius: ReactPropTypes.number, borderTopRightRadius: ReactPropTypes.number, @@ -58,4 +58,4 @@ const ViewStylePropTypes = { elevation: ReactPropTypes.number, }; -module.exports = ViewStylePropTypes; +module.exports = DeprecatedViewStylePropTypes; diff --git a/Libraries/Utilities/createStrictShapeTypeChecker.js b/Libraries/DeprecatedPropTypes/deprecatedCreateStrictShapeTypeChecker.js similarity index 92% rename from Libraries/Utilities/createStrictShapeTypeChecker.js rename to Libraries/DeprecatedPropTypes/deprecatedCreateStrictShapeTypeChecker.js index ad097e9682344e..524e605ca05b72 100644 --- a/Libraries/Utilities/createStrictShapeTypeChecker.js +++ b/Libraries/DeprecatedPropTypes/deprecatedCreateStrictShapeTypeChecker.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. @@ -13,7 +13,7 @@ const invariant = require('fbjs/lib/invariant'); const merge = require('merge'); -function createStrictShapeTypeChecker(shapeTypes: { +function deprecatedCreateStrictShapeTypeChecker(shapeTypes: { [key: string]: ReactPropsCheckType, }): ReactPropsChainableTypeChecker { function checkType( @@ -83,4 +83,4 @@ function createStrictShapeTypeChecker(shapeTypes: { return chainedCheckType; } -module.exports = createStrictShapeTypeChecker; +module.exports = deprecatedCreateStrictShapeTypeChecker; diff --git a/Libraries/EventEmitter/MissingNativeEventEmitterShim.js b/Libraries/EventEmitter/MissingNativeEventEmitterShim.js index 562964b85f4cf4..1b9a51c708a637 100644 --- a/Libraries/EventEmitter/MissingNativeEventEmitterShim.js +++ b/Libraries/EventEmitter/MissingNativeEventEmitterShim.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. diff --git a/Libraries/EventEmitter/NativeEventEmitter.js b/Libraries/EventEmitter/NativeEventEmitter.js index 8f8658c14e85a3..4047b6d06dc85d 100644 --- a/Libraries/EventEmitter/NativeEventEmitter.js +++ b/Libraries/EventEmitter/NativeEventEmitter.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. diff --git a/Libraries/EventEmitter/RCTDeviceEventEmitter.js b/Libraries/EventEmitter/RCTDeviceEventEmitter.js index b0977f219abc25..342aa733bf08ff 100644 --- a/Libraries/EventEmitter/RCTDeviceEventEmitter.js +++ b/Libraries/EventEmitter/RCTDeviceEventEmitter.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. diff --git a/Libraries/EventEmitter/RCTEventEmitter.js b/Libraries/EventEmitter/RCTEventEmitter.js index 1a51905ba20d1e..f84bca058ed366 100644 --- a/Libraries/EventEmitter/RCTEventEmitter.js +++ b/Libraries/EventEmitter/RCTEventEmitter.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. diff --git a/Libraries/EventEmitter/RCTNativeAppEventEmitter.js b/Libraries/EventEmitter/RCTNativeAppEventEmitter.js index fcf5ae86438887..2d302c014feebb 100644 --- a/Libraries/EventEmitter/RCTNativeAppEventEmitter.js +++ b/Libraries/EventEmitter/RCTNativeAppEventEmitter.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. diff --git a/Libraries/EventEmitter/__mocks__/NativeEventEmitter.js b/Libraries/EventEmitter/__mocks__/NativeEventEmitter.js index e822b72c73c192..e34e60e2e9f201 100644 --- a/Libraries/EventEmitter/__mocks__/NativeEventEmitter.js +++ b/Libraries/EventEmitter/__mocks__/NativeEventEmitter.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. diff --git a/Libraries/Experimental/Incremental.js b/Libraries/Experimental/Incremental.js index cfd0c69fd03cfe..76d8ff902680ab 100644 --- a/Libraries/Experimental/Incremental.js +++ b/Libraries/Experimental/Incremental.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. @@ -90,14 +90,12 @@ export type Props = { * Tags instances and associated tasks for easier debugging. */ name: string, - children?: any, -}; -type DefaultProps = { - name: string, + children: React.Node, }; type State = { doIncrementalRender: boolean, }; + class Incremental extends React.Component { props: Props; state: State; diff --git a/Libraries/Experimental/IncrementalExample.js b/Libraries/Experimental/IncrementalExample.js index 3cc441fff38591..e63f59a996f974 100644 --- a/Libraries/Experimental/IncrementalExample.js +++ b/Libraries/Experimental/IncrementalExample.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. diff --git a/Libraries/Experimental/IncrementalGroup.js b/Libraries/Experimental/IncrementalGroup.js index af1a7ad63ddb79..03421e92c58f4c 100644 --- a/Libraries/Experimental/IncrementalGroup.js +++ b/Libraries/Experimental/IncrementalGroup.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. diff --git a/Libraries/Experimental/IncrementalPresenter.js b/Libraries/Experimental/IncrementalPresenter.js index 9927179d173966..784878f93468d4 100644 --- a/Libraries/Experimental/IncrementalPresenter.js +++ b/Libraries/Experimental/IncrementalPresenter.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. @@ -11,13 +11,13 @@ 'use strict'; const IncrementalGroup = require('IncrementalGroup'); -const React = require('React'); const PropTypes = require('prop-types'); +const React = require('React'); const View = require('View'); -const ViewPropTypes = require('ViewPropTypes'); - import type {Context} from 'Incremental'; +import type {ViewStyleProp} from 'StyleSheet'; +import type {LayoutEvent} from 'CoreEventTypes'; /** * WARNING: EXPERIMENTAL. Breaking changes will probably happen a lot and will @@ -31,25 +31,19 @@ import type {Context} from 'Incremental'; * * See Incremental.js for more info. */ -type Props = { +type Props = $ReadOnly<{| name: string, disabled?: boolean, - onDone?: () => void, - onLayout?: (event: Object) => void, - style?: mixed, - children?: any, -}; + onDone?: () => mixed, + onLayout?: (event: LayoutEvent) => mixed, + style?: ViewStyleProp, + children?: React.Node, +|}>; + class IncrementalPresenter extends React.Component { context: Context; _isDone: boolean; - static propTypes = { - name: PropTypes.string, - disabled: PropTypes.bool, - onDone: PropTypes.func, - onLayout: PropTypes.func, - style: ViewPropTypes.style, - }; static contextTypes = { incrementalGroup: PropTypes.object, incrementalGroupEnabled: PropTypes.bool, @@ -74,14 +68,15 @@ class IncrementalPresenter extends React.Component { this.props.onDone && this.props.onDone(); } render() { + let style: ViewStyleProp; if ( this.props.disabled !== true && this.context.incrementalGroupEnabled !== false && !this._isDone ) { - var style = [this.props.style, {opacity: 0, position: 'absolute'}]; + style = [this.props.style, {opacity: 0, position: 'absolute'}]; } else { - var style = this.props.style; + style = this.props.style; } return ( number), - // Callback method to render the view that will be unveiled on swipe + + /** + * Callback method to render the view that will be unveiled on swipe + */ renderQuickActions: renderItemType, }; type Props = SwipableListProps & FlatListProps; -type State = { +type State = {| openRowKey: ?string, -}; +|}; /** * A container component that renders multiple SwipeableRow's in a FlatList @@ -53,29 +60,9 @@ type State = { */ class SwipeableFlatList extends React.Component, State> { - props: Props; - state: State; - _flatListRef: ?FlatList = null; _shouldBounceFirstRowOnMount: boolean = false; - static propTypes = { - ...FlatList.propTypes, - - /** - * To alert the user that swiping is possible, the first row can bounce - * on component mount. - */ - bounceFirstRowOnMount: PropTypes.bool.isRequired, - - // Maximum distance to open to after a swipe - maxSwipeDistance: PropTypes.oneOfType([PropTypes.number, PropTypes.func]) - .isRequired, - - // Callback method to render the view that will be unveiled on swipe - renderQuickActions: PropTypes.func.isRequired, - }; - static defaultProps = { ...FlatList.defaultProps, bounceFirstRowOnMount: true, diff --git a/Libraries/Experimental/SwipeableRow/SwipeableListView.js b/Libraries/Experimental/SwipeableRow/SwipeableListView.js index bae4eb5f2ff846..3189b728a7962a 100644 --- a/Libraries/Experimental/SwipeableRow/SwipeableListView.js +++ b/Libraries/Experimental/SwipeableRow/SwipeableListView.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. @@ -11,30 +11,53 @@ 'use strict'; const ListView = require('ListView'); -const PropTypes = require('prop-types'); const React = require('React'); const SwipeableListViewDataSource = require('SwipeableListViewDataSource'); const SwipeableRow = require('SwipeableRow'); -type DefaultProps = { - bounceFirstRowOnMount: boolean, - renderQuickActions: Function, -}; +type ListViewProps = React.ElementConfig; + +type Props = $ReadOnly<{| + ...ListViewProps, -type Props = { + /** + * To alert the user that swiping is possible, the first row can bounce + * on component mount. + */ bounceFirstRowOnMount: boolean, + /** + * Use `SwipeableListView.getNewDataSource()` to get a data source to use, + * then use it just like you would a normal ListView data source + */ dataSource: SwipeableListViewDataSource, + /** + * Maximum distance to open to after a swipe + */ maxSwipeDistance: | number - | ((rowData: any, sectionID: string, rowID: string) => number), + | ((rowData: Object, sectionID: string, rowID: string) => number), onScroll?: ?Function, - renderRow: Function, - renderQuickActions: Function, -}; + /** + * Callback method to render the swipeable view + */ + renderRow: ( + rowData: Object, + sectionID: string, + rowID: string, + ) => React.Element, + /** + * Callback method to render the view that will be unveiled on swipe + */ + renderQuickActions: ( + rowData: Object, + sectionID: string, + rowID: string, + ) => ?React.Element, +|}>; -type State = { +type State = {| dataSource: Object, -}; +|}; /** * A container component that renders multiple SwipeableRow's in a ListView @@ -70,26 +93,6 @@ class SwipeableListView extends React.Component { }); } - static propTypes = { - /** - * To alert the user that swiping is possible, the first row can bounce - * on component mount. - */ - bounceFirstRowOnMount: PropTypes.bool.isRequired, - /** - * Use `SwipeableListView.getNewDataSource()` to get a data source to use, - * then use it just like you would a normal ListView data source - */ - dataSource: PropTypes.instanceOf(SwipeableListViewDataSource).isRequired, - // Maximum distance to open to after a swipe - maxSwipeDistance: PropTypes.oneOfType([PropTypes.number, PropTypes.func]) - .isRequired, - // Callback method to render the swipeable view - renderRow: PropTypes.func.isRequired, - // Callback method to render the view that will be unveiled on swipe - renderQuickActions: PropTypes.func.isRequired, - }; - static defaultProps = { bounceFirstRowOnMount: false, renderQuickActions: () => null, diff --git a/Libraries/Experimental/SwipeableRow/SwipeableListViewDataSource.js b/Libraries/Experimental/SwipeableRow/SwipeableListViewDataSource.js index 6c409a9acad1c4..38e03c66140d0f 100644 --- a/Libraries/Experimental/SwipeableRow/SwipeableListViewDataSource.js +++ b/Libraries/Experimental/SwipeableRow/SwipeableListViewDataSource.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. diff --git a/Libraries/Experimental/SwipeableRow/SwipeableQuickActionButton.js b/Libraries/Experimental/SwipeableRow/SwipeableQuickActionButton.js index f7067fc8de1c08..278af853bd8a92 100644 --- a/Libraries/Experimental/SwipeableRow/SwipeableQuickActionButton.js +++ b/Libraries/Experimental/SwipeableRow/SwipeableQuickActionButton.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. @@ -10,12 +10,12 @@ 'use strict'; +const DeprecatedViewPropTypes = require('DeprecatedViewPropTypes'); const Image = require('Image'); const React = require('React'); const Text = require('Text'); const TouchableHighlight = require('TouchableHighlight'); const View = require('View'); -const ViewPropTypes = require('ViewPropTypes'); import type {ImageSource} from 'ImageSource'; @@ -28,13 +28,22 @@ class SwipeableQuickActionButton extends React.Component<{ accessibilityLabel?: string, accessibilityHint?: string, // TODO(OSS Candidate ISS#2710739) imageSource?: ?(ImageSource | number), - imageStyle?: ?ViewPropTypes.style, + /* $FlowFixMe(>=0.82.0 site=react_native_fb) This comment suppresses an error + * found when Flow v0.82 was deployed. To see the error delete this comment + * and run Flow. */ + imageStyle?: ?DeprecatedViewPropTypes.style, mainView?: ?React.Node, onPress?: Function, - style?: ?ViewPropTypes.style, + /* $FlowFixMe(>=0.82.0 site=react_native_fb) This comment suppresses an error + * found when Flow v0.82 was deployed. To see the error delete this comment + * and run Flow. */ + style?: ?DeprecatedViewPropTypes.style, testID?: string, text?: ?(string | Object | Array), - textStyle?: ?ViewPropTypes.style, + /* $FlowFixMe(>=0.82.0 site=react_native_fb) This comment suppresses an error + * found when Flow v0.82 was deployed. To see the error delete this comment + * and run Flow. */ + textStyle?: ?DeprecatedViewPropTypes.style, }> { render(): React.Node { if (!this.props.imageSource && !this.props.text && !this.props.mainView) { diff --git a/Libraries/Experimental/SwipeableRow/SwipeableQuickActions.js b/Libraries/Experimental/SwipeableRow/SwipeableQuickActions.js index 8178770c882d29..c97f77648af76f 100644 --- a/Libraries/Experimental/SwipeableRow/SwipeableQuickActions.js +++ b/Libraries/Experimental/SwipeableRow/SwipeableQuickActions.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. @@ -14,7 +14,12 @@ const React = require('React'); const StyleSheet = require('StyleSheet'); const View = require('View'); -const ViewPropTypes = require('ViewPropTypes'); +import type {ViewStyleProp} from 'StyleSheet'; + +type Props = $ReadOnly<{| + style?: ?ViewStyleProp, + children: React.Node, +|}>; /** * A thin wrapper around standard quick action buttons that can, if the user @@ -26,13 +31,8 @@ const ViewPropTypes = require('ViewPropTypes'); * * */ -class SwipeableQuickActions extends React.Component<{style?: $FlowFixMe}> { - static propTypes = { - style: ViewPropTypes.style, - }; - +class SwipeableQuickActions extends React.Component { render(): React.Node { - // $FlowFixMe found when converting React.createClass to ES6 const children = this.props.children; let buttons = []; @@ -41,8 +41,7 @@ class SwipeableQuickActions extends React.Component<{style?: $FlowFixMe}> { for (let i = 0; i < children.length; i++) { buttons.push(children[i]); - // $FlowFixMe found when converting React.createClass to ES6 - if (i < this.props.children.length - 1) { + if (i < children.length - 1) { // Not last button buttons.push(); } diff --git a/Libraries/Experimental/SwipeableRow/SwipeableRow.js b/Libraries/Experimental/SwipeableRow/SwipeableRow.js index 3cbeb3d6ca2558..76eb13dcfc78c3 100644 --- a/Libraries/Experimental/SwipeableRow/SwipeableRow.js +++ b/Libraries/Experimental/SwipeableRow/SwipeableRow.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. @@ -14,17 +14,14 @@ const Animated = require('Animated'); const I18nManager = require('I18nManager'); const PanResponder = require('PanResponder'); const React = require('React'); -const PropTypes = require('prop-types'); const StyleSheet = require('StyleSheet'); -/* $FlowFixMe(>=0.54.0 site=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. */ -const TimerMixin = require('react-timer-mixin'); const View = require('View'); -const createReactClass = require('create-react-class'); const emptyFunction = require('fbjs/lib/emptyFunction'); +import type {LayoutEvent, PressEvent} from 'CoreEventTypes'; +import type {GestureState} from 'PanResponder'; + const IS_RTL = I18nManager.isRTL; // NOTE: Eventually convert these consts to an input object of configurations @@ -56,21 +53,28 @@ const RIGHT_SWIPE_BOUNCE_BACK_DURATION = 300; * how far the finger swipes, and not the actual animation distance. */ const RIGHT_SWIPE_THRESHOLD = 30 * SLOW_SPEED_SWIPE_FACTOR; +const DEFAULT_SWIPE_THRESHOLD = 30; type Props = $ReadOnly<{| children?: ?React.Node, isOpen?: ?boolean, maxSwipeDistance?: ?number, - onClose?: ?Function, - onOpen?: ?Function, - onSwipeEnd?: ?Function, - onSwipeStart?: ?Function, + onClose?: ?() => void, + onOpen?: ?() => void, + onSwipeEnd?: ?() => void, + onSwipeStart?: ?() => void, preventSwipeRight?: ?boolean, shouldBounceOnMount?: ?boolean, slideoutView?: ?React.Node, swipeThreshold?: ?number, |}>; +type State = { + currentLeft: Animated.Value, + isSwipeableViewRendered: boolean, + rowHeight: ?number, +}; + /** * Creates a swipable row that allows taps on the main item and a custom View * on the item hidden behind the row. Typically this should be used in @@ -78,75 +82,98 @@ type Props = $ReadOnly<{| * used in a normal ListView. See the renderRow for SwipeableListView to see how * to use this component separately. */ -const SwipeableRow = createReactClass({ - displayName: 'SwipeableRow', - _panResponder: {}, - _previousLeft: CLOSED_LEFT_POSITION, - - mixins: [TimerMixin], - - propTypes: { - children: PropTypes.any, - isOpen: PropTypes.bool, - preventSwipeRight: PropTypes.bool, - maxSwipeDistance: PropTypes.number.isRequired, - onOpen: PropTypes.func.isRequired, - onClose: PropTypes.func.isRequired, - onSwipeEnd: PropTypes.func.isRequired, - onSwipeStart: PropTypes.func.isRequired, - // Should bounce the row on mount - shouldBounceOnMount: PropTypes.bool, - /** - * A ReactElement that is unveiled when the user swipes - */ - slideoutView: PropTypes.node.isRequired, - /** - * The minimum swipe distance required before fully animating the swipe. If - * the user swipes less than this distance, the item will return to its - * previous (open/close) position. - */ - swipeThreshold: PropTypes.number.isRequired, - }, +class SwipeableRow extends React.Component { + _handleMoveShouldSetPanResponderCapture = ( + event: PressEvent, + gestureState: GestureState, + ): boolean => { + // Decides whether a swipe is responded to by this component or its child + return gestureState.dy < 10 && this._isValidSwipe(gestureState); + }; - getInitialState(): Object { - return { - currentLeft: new Animated.Value(this._previousLeft), - /** - * In order to render component A beneath component B, A must be rendered - * before B. However, this will cause "flickering", aka we see A briefly - * then B. To counter this, _isSwipeableViewRendered flag is used to set - * component A to be transparent until component B is loaded. - */ - isSwipeableViewRendered: false, - rowHeight: (null: ?number), - }; - }, + _handlePanResponderGrant = ( + event: PressEvent, + gestureState: GestureState, + ): void => {}; - getDefaultProps(): Object { - return { - isOpen: false, - preventSwipeRight: false, - maxSwipeDistance: 0, - onOpen: emptyFunction, - onClose: emptyFunction, - onSwipeEnd: emptyFunction, - onSwipeStart: emptyFunction, - swipeThreshold: 30, - }; - }, + _handlePanResponderMove = ( + event: PressEvent, + gestureState: GestureState, + ): void => { + if (this._isSwipingExcessivelyRightFromClosedPosition(gestureState)) { + return; + } - UNSAFE_componentWillMount(): void { - this._panResponder = PanResponder.create({ - onMoveShouldSetPanResponderCapture: this - ._handleMoveShouldSetPanResponderCapture, - onPanResponderGrant: this._handlePanResponderGrant, - onPanResponderMove: this._handlePanResponderMove, - onPanResponderRelease: this._handlePanResponderEnd, - onPanResponderTerminationRequest: this._onPanResponderTerminationRequest, - onPanResponderTerminate: this._handlePanResponderEnd, - onShouldBlockNativeResponder: (event, gestureState) => false, - }); - }, + this.props.onSwipeStart && this.props.onSwipeStart(); + + if (this._isSwipingRightFromClosed(gestureState)) { + this._swipeSlowSpeed(gestureState); + } else { + this._swipeFullSpeed(gestureState); + } + }; + + _onPanResponderTerminationRequest = ( + event: PressEvent, + gestureState: GestureState, + ): boolean => { + return false; + }; + + _handlePanResponderEnd = ( + event: PressEvent, + gestureState: GestureState, + ): void => { + const horizontalDistance = IS_RTL ? -gestureState.dx : gestureState.dx; + if (this._isSwipingRightFromClosed(gestureState)) { + this.props.onOpen && this.props.onOpen(); + this._animateBounceBack(RIGHT_SWIPE_BOUNCE_BACK_DURATION); + } else if (this._shouldAnimateRemainder(gestureState)) { + if (horizontalDistance < 0) { + // Swiped left + this.props.onOpen && this.props.onOpen(); + this._animateToOpenPositionWith(gestureState.vx, horizontalDistance); + } else { + // Swiped right + this.props.onClose && this.props.onClose(); + this._animateToClosedPosition(); + } + } else { + if (this._previousLeft === CLOSED_LEFT_POSITION) { + this._animateToClosedPosition(); + } else { + this._animateToOpenPosition(); + } + } + + this.props.onSwipeEnd && this.props.onSwipeEnd(); + }; + + _panResponder = PanResponder.create({ + onMoveShouldSetPanResponderCapture: this + ._handleMoveShouldSetPanResponderCapture, + onPanResponderGrant: this._handlePanResponderGrant, + onPanResponderMove: this._handlePanResponderMove, + onPanResponderRelease: this._handlePanResponderEnd, + onPanResponderTerminationRequest: this._onPanResponderTerminationRequest, + onPanResponderTerminate: this._handlePanResponderEnd, + onShouldBlockNativeResponder: (event, gestureState) => false, + }); + + _previousLeft = CLOSED_LEFT_POSITION; + _timeoutID: ?TimeoutID = null; + + state = { + currentLeft: new Animated.Value(this._previousLeft), + /** + * In order to render component A beneath component B, A must be rendered + * before B. However, this will cause "flickering", aka we see A briefly + * then B. To counter this, _isSwipeableViewRendered flag is used to set + * component A to be transparent until component B is loaded. + */ + isSwipeableViewRendered: false, + rowHeight: null, + }; componentDidMount(): void { if (this.props.shouldBounceOnMount) { @@ -154,21 +181,30 @@ const SwipeableRow = createReactClass({ * Do the on mount bounce after a delay because if we animate when other * components are loading, the animation will be laggy */ - this.setTimeout(() => { + this._timeoutID = setTimeout(() => { this._animateBounceBack(ON_MOUNT_BOUNCE_DURATION); }, ON_MOUNT_BOUNCE_DELAY); } - }, + } - UNSAFE_componentWillReceiveProps(nextProps: Object): void { + UNSAFE_componentWillReceiveProps(nextProps: $Shape): void { /** * We do not need an "animateOpen(noCallback)" because this animation is * handled internally by this component. */ - if (this.props.isOpen && !nextProps.isOpen) { + const isOpen = this.props.isOpen ?? false; + const nextIsOpen = nextProps.isOpen ?? false; + + if (isOpen && !nextIsOpen) { this._animateToClosedPosition(); } - }, + } + + componentWillUnmount() { + if (this._timeoutID != null) { + clearTimeout(this._timeoutID); + } + } render(): React.Element { // The view hidden behind the main view @@ -197,60 +233,38 @@ const SwipeableRow = createReactClass({ {swipeableView} ); - }, + } close(): void { - this.props.onClose(); + this.props.onClose && this.props.onClose(); this._animateToClosedPosition(); - }, + } - _onSwipeableViewLayout(event: Object): void { + _onSwipeableViewLayout = (event: LayoutEvent): void => { this.setState({ isSwipeableViewRendered: true, rowHeight: event.nativeEvent.layout.height, }); - }, + }; - _handleMoveShouldSetPanResponderCapture( - event: Object, - gestureState: Object, - ): boolean { - // Decides whether a swipe is responded to by this component or its child - return gestureState.dy < 10 && this._isValidSwipe(gestureState); - }, - - _handlePanResponderGrant(event: Object, gestureState: Object): void {}, - - _handlePanResponderMove(event: Object, gestureState: Object): void { - if (this._isSwipingExcessivelyRightFromClosedPosition(gestureState)) { - return; - } - - this.props.onSwipeStart(); - - if (this._isSwipingRightFromClosed(gestureState)) { - this._swipeSlowSpeed(gestureState); - } else { - this._swipeFullSpeed(gestureState); - } - }, - - _isSwipingRightFromClosed(gestureState: Object): boolean { + _isSwipingRightFromClosed(gestureState: GestureState): boolean { const gestureStateDx = IS_RTL ? -gestureState.dx : gestureState.dx; return this._previousLeft === CLOSED_LEFT_POSITION && gestureStateDx > 0; - }, + } - _swipeFullSpeed(gestureState: Object): void { + _swipeFullSpeed(gestureState: GestureState): void { this.state.currentLeft.setValue(this._previousLeft + gestureState.dx); - }, + } - _swipeSlowSpeed(gestureState: Object): void { + _swipeSlowSpeed(gestureState: GestureState): void { this.state.currentLeft.setValue( this._previousLeft + gestureState.dx / SLOW_SPEED_SWIPE_FACTOR, ); - }, + } - _isSwipingExcessivelyRightFromClosedPosition(gestureState: Object): boolean { + _isSwipingExcessivelyRightFromClosedPosition( + gestureState: GestureState, + ): boolean { /** * We want to allow a BIT of right swipe, to allow users to know that * swiping is available, but swiping right does not do anything @@ -261,14 +275,7 @@ const SwipeableRow = createReactClass({ this._isSwipingRightFromClosed(gestureState) && gestureStateDx > RIGHT_SWIPE_THRESHOLD ); - }, - - _onPanResponderTerminationRequest( - event: Object, - gestureState: Object, - ): boolean { - return false; - }, + } _animateTo( toValue: number, @@ -283,14 +290,15 @@ const SwipeableRow = createReactClass({ this._previousLeft = toValue; callback(); }); - }, + } _animateToOpenPosition(): void { - const maxSwipeDistance = IS_RTL - ? -this.props.maxSwipeDistance - : this.props.maxSwipeDistance; - this._animateTo(-maxSwipeDistance); - }, + const maxSwipeDistance = this.props.maxSwipeDistance ?? 0; + const directionAwareMaxSwipeDistance = IS_RTL + ? -maxSwipeDistance + : maxSwipeDistance; + this._animateTo(-directionAwareMaxSwipeDistance); + } _animateToOpenPositionWith(speed: number, distMoved: number): void { /** @@ -301,26 +309,25 @@ const SwipeableRow = createReactClass({ speed > HORIZONTAL_FULL_SWIPE_SPEED_THRESHOLD ? speed : HORIZONTAL_FULL_SWIPE_SPEED_THRESHOLD; + const maxSwipeDistance = this.props.maxSwipeDistance ?? 0; /** * Calculate the duration the row should take to swipe the remaining distance * at the same speed the user swiped (or the speed threshold) */ - const duration = Math.abs( - (this.props.maxSwipeDistance - Math.abs(distMoved)) / speed, - ); - const maxSwipeDistance = IS_RTL - ? -this.props.maxSwipeDistance - : this.props.maxSwipeDistance; - this._animateTo(-maxSwipeDistance, duration); - }, + const duration = Math.abs((maxSwipeDistance - Math.abs(distMoved)) / speed); + const directionAwareMaxSwipeDistance = IS_RTL + ? -maxSwipeDistance + : maxSwipeDistance; + this._animateTo(-directionAwareMaxSwipeDistance, duration); + } _animateToClosedPosition(duration: number = SWIPE_DURATION): void { this._animateTo(CLOSED_LEFT_POSITION, duration); - }, + } - _animateToClosedPositionDuringBounce(): void { + _animateToClosedPositionDuringBounce = (): void => { this._animateToClosedPosition(RIGHT_SWIPE_BOUNCE_BACK_DURATION); - }, + }; _animateBounceBack(duration: number): void { /** @@ -335,12 +342,13 @@ const SwipeableRow = createReactClass({ duration, this._animateToClosedPositionDuringBounce, ); - }, + } // Ignore swipes due to user's finger moving slightly when tapping - _isValidSwipe(gestureState: Object): boolean { + _isValidSwipe(gestureState: GestureState): boolean { + const preventSwipeRight = this.props.preventSwipeRight ?? false; if ( - this.props.preventSwipeRight && + preventSwipeRight && this._previousLeft === CLOSED_LEFT_POSITION && gestureState.dx > 0 ) { @@ -348,49 +356,19 @@ const SwipeableRow = createReactClass({ } return Math.abs(gestureState.dx) > HORIZONTAL_SWIPE_DISTANCE_THRESHOLD; - }, + } - _shouldAnimateRemainder(gestureState: Object): boolean { + _shouldAnimateRemainder(gestureState: GestureState): boolean { /** * If user has swiped past a certain distance, animate the rest of the way * if they let go */ + const swipeThreshold = this.props.swipeThreshold ?? DEFAULT_SWIPE_THRESHOLD; return ( - Math.abs(gestureState.dx) > this.props.swipeThreshold || + Math.abs(gestureState.dx) > swipeThreshold || gestureState.vx > HORIZONTAL_FULL_SWIPE_SPEED_THRESHOLD ); - }, - - _handlePanResponderEnd(event: Object, gestureState: Object): void { - const horizontalDistance = IS_RTL ? -gestureState.dx : gestureState.dx; - if (this._isSwipingRightFromClosed(gestureState)) { - this.props.onOpen(); - this._animateBounceBack(RIGHT_SWIPE_BOUNCE_BACK_DURATION); - } else if (this._shouldAnimateRemainder(gestureState)) { - if (horizontalDistance < 0) { - // Swiped left - this.props.onOpen(); - this._animateToOpenPositionWith(gestureState.vx, horizontalDistance); - } else { - // Swiped right - this.props.onClose(); - this._animateToClosedPosition(); - } - } else { - if (this._previousLeft === CLOSED_LEFT_POSITION) { - this._animateToClosedPosition(); - } else { - this._animateToOpenPosition(); - } - } - - this.props.onSwipeEnd(); - }, -}); - -// TODO: Delete this when `SwipeableRow` uses class syntax. -class TypedSwipeableRow extends React.Component { - close() {} + } } const styles = StyleSheet.create({ @@ -403,4 +381,4 @@ const styles = StyleSheet.create({ }, }); -module.exports = ((SwipeableRow: any): Class); +module.exports = SwipeableRow; diff --git a/Libraries/Experimental/WindowedListView.js b/Libraries/Experimental/WindowedListView.js index 15f1d0b4a8755a..8ce5b44c07b052 100644 --- a/Libraries/Experimental/WindowedListView.js +++ b/Libraries/Experimental/WindowedListView.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. @@ -14,7 +14,6 @@ const Batchinator = require('Batchinator'); const IncrementalGroup = require('IncrementalGroup'); const React = require('React'); const ScrollView = require('ScrollView'); -const Set = require('Set'); const StyleSheet = require('StyleSheet'); const Systrace = require('Systrace'); const View = require('View'); @@ -24,7 +23,7 @@ const clamp = require('clamp'); const deepDiffer = require('deepDiffer'); const infoLog = require('infoLog'); const invariant = require('fbjs/lib/invariant'); -const nullthrows = require('fbjs/lib/nullthrows'); +const nullthrows = require('nullthrows'); import type {NativeMethodsMixinType} from 'ReactNativeTypes'; @@ -778,11 +777,7 @@ class CellRenderer extends React.Component { if (DEBUG) { infoLog('render cell ' + this.props.rowIndex); const Text = require('Text'); - debug = ( - - Row: {this.props.rowIndex} - - ); + debug = Row: {this.props.rowIndex}; } const style = this._includeInLayoutLatch ? styles.include : styles.remove; return ( @@ -820,6 +815,9 @@ const styles = StyleSheet.create({ right: -removedXOffset, opacity: DEBUG ? 0.1 : 0, }, + debug: { + backgroundColor: 'lightblue', + }, }); module.exports = WindowedListView; diff --git a/Libraries/Geolocation/Geolocation.js b/Libraries/Geolocation/Geolocation.js index d252da95bca58f..0cde34c59456bc 100644 --- a/Libraries/Geolocation/Geolocation.js +++ b/Libraries/Geolocation/Geolocation.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. diff --git a/Libraries/Geolocation/RCTLocationObserver.h b/Libraries/Geolocation/RCTLocationObserver.h index 5de0ea289d881d..f3f9e19b8f2902 100644 --- a/Libraries/Geolocation/RCTLocationObserver.h +++ b/Libraries/Geolocation/RCTLocationObserver.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. diff --git a/Libraries/Geolocation/RCTLocationObserver.m b/Libraries/Geolocation/RCTLocationObserver.m index 8fa9956a1885c0..44969b28167552 100644 --- a/Libraries/Geolocation/RCTLocationObserver.m +++ b/Libraries/Geolocation/RCTLocationObserver.m @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. diff --git a/Libraries/Image/AssetRegistry.js b/Libraries/Image/AssetRegistry.js index b050a9e239cd27..7d9626f8771f42 100644 --- a/Libraries/Image/AssetRegistry.js +++ b/Libraries/Image/AssetRegistry.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. diff --git a/Libraries/Image/AssetSourceResolver.js b/Libraries/Image/AssetSourceResolver.js index a870a325242838..b5650620ae1481 100644 --- a/Libraries/Image/AssetSourceResolver.js +++ b/Libraries/Image/AssetSourceResolver.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. diff --git a/Libraries/Image/Image.android.js b/Libraries/Image/Image.android.js index 0058b210d957bd..70e6e0f40414a5 100644 --- a/Libraries/Image/Image.android.js +++ b/Libraries/Image/Image.android.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. @@ -10,25 +10,24 @@ 'use strict'; -const ImageStylePropTypes = require('ImageStylePropTypes'); +const DeprecatedImageStylePropTypes = require('DeprecatedImageStylePropTypes'); +const DeprecatedStyleSheetPropType = require('DeprecatedStyleSheetPropType'); +const DeprecatedViewPropTypes = require('DeprecatedViewPropTypes'); +const ImageViewNativeComponent = require('ImageViewNativeComponent'); const NativeModules = require('NativeModules'); -const React = require('React'); -const ReactNative = require('ReactNative'); const PropTypes = require('prop-types'); +const React = require('React'); +const ReactNative = require('ReactNative'); // eslint-disable-line no-unused-vars const StyleSheet = require('StyleSheet'); -const StyleSheetPropType = require('StyleSheetPropType'); const TextAncestor = require('TextAncestor'); -const ViewPropTypes = require('ViewPropTypes'); const flattenStyle = require('flattenStyle'); const merge = require('merge'); -const requireNativeComponent = require('requireNativeComponent'); const resolveAssetSource = require('resolveAssetSource'); const {ImageLoader} = NativeModules; -const RKImage = requireNativeComponent('RCTImageView'); -const RCTTextInlineImage = requireNativeComponent('RCTTextInlineImage'); +const TextInlineImageNativeComponent = require('TextInlineImageNativeComponent'); import type {ImageProps as ImagePropsType} from 'ImageProps'; @@ -38,8 +37,8 @@ function generateRequestId() { } const ImageProps = { - ...ViewPropTypes, - style: StyleSheetPropType(ImageStylePropTypes), + ...DeprecatedViewPropTypes, + style: DeprecatedStyleSheetPropType(DeprecatedImageStylePropTypes), /** * See https://facebook.github.io/react-native/docs/image.html#source */ @@ -182,7 +181,7 @@ declare class ImageComponentType extends ReactNative.NativeComponent< */ let Image = ( props: ImagePropsType, - forwardedRef: ?React.Ref<'RCTTextInlineImage' | 'RKImage'>, + forwardedRef: ?React.Ref<'RCTTextInlineImage' | 'ImageViewNativeComponent'>, ) => { let source = resolveAssetSource(props.source); const defaultSource = resolveAssetSource(props.defaultSource); @@ -250,9 +249,9 @@ let Image = ( {hasTextAncestor => hasTextAncestor ? ( - + ) : ( - + ) } @@ -263,10 +262,9 @@ let Image = ( Image = React.forwardRef(Image); /** - * Prefetches a remote image for later use by downloading it to the disk - * cache + * Retrieve the width and height (in pixels) of an image prior to displaying it * - * See https://facebook.github.io/react-native/docs/image.html#prefetch + * See https://facebook.github.io/react-native/docs/image.html#getsize */ Image.getSize = getSize; diff --git a/Libraries/Image/Image.js b/Libraries/Image/Image.js index d96e6daeb8860e..0aec13a86e8f25 100644 --- a/Libraries/Image/Image.js +++ b/Libraries/Image/Image.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. @@ -12,10 +12,10 @@ 'use strict'; -const ImageProps = require('ImageProps'); +const DeprecatedImagePropType = require('DeprecatedImagePropType'); const NativeModules = require('NativeModules'); const React = require('React'); -const ReactNative = require('ReactNative'); +const ReactNative = require('ReactNative'); // eslint-disable-line no-unused-vars const StyleSheet = require('StyleSheet'); const flattenStyle = require('flattenStyle'); @@ -26,6 +26,7 @@ const ImageViewManager = NativeModules.ImageViewManager; const RCTImageView = requireNativeComponent('RCTImageView'); +import type {ImageStyleProp} from 'StyleSheet'; import type {ImageProps as ImagePropsType} from 'ImageProps'; function getSize( @@ -47,13 +48,20 @@ function prefetch(url: string) { return ImageViewManager.prefetchImage(url); } +async function queryCache( + urls: Array, +): Promise> { + return await ImageViewManager.queryCache(urls); +} + declare class ImageComponentType extends ReactNative.NativeComponent< ImagePropsType, > { static getSize: typeof getSize; static prefetch: typeof prefetch; + static queryCache: typeof queryCache; static resolveAssetSource: typeof resolveAssetSource; - static propTypes: typeof ImageProps; + static propTypes: typeof DeprecatedImagePropType; } /** @@ -74,12 +82,14 @@ let Image = ( }; let sources; - let style; + let style: ImageStyleProp; if (Array.isArray(source)) { + // $FlowFixMe flattenStyle is not strong enough style = flattenStyle([styles.base, props.style]) || {}; sources = source; } else { const {width, height, uri} = source; + // $FlowFixMe flattenStyle is not strong enough style = flattenStyle([{width, height}, styles.base, props.style]) || {}; sources = [source]; @@ -133,6 +143,13 @@ Image.getSize = getSize; */ Image.prefetch = prefetch; +/** + * Performs cache interrogation. + * + * See https://facebook.github.io/react-native/docs/image.html#querycache + */ +Image.queryCache = queryCache; + /** * Resolves an asset reference into an object. * @@ -140,7 +157,7 @@ Image.prefetch = prefetch; */ Image.resolveAssetSource = resolveAssetSource; -Image.propTypes = ImageProps; +Image.propTypes = DeprecatedImagePropType; const styles = StyleSheet.create({ base: { diff --git a/Libraries/Image/ImageBackground.js b/Libraries/Image/ImageBackground.js index a128880a17807c..7d04576dcc0c92 100644 --- a/Libraries/Image/ImageBackground.js +++ b/Libraries/Image/ImageBackground.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. diff --git a/Libraries/Image/ImageEditor.js b/Libraries/Image/ImageEditor.js index 65edcccf12204f..53785b680c15c1 100644 --- a/Libraries/Image/ImageEditor.js +++ b/Libraries/Image/ImageEditor.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. @@ -16,25 +16,25 @@ type ImageCropData = { * The top-left corner of the cropped image, specified in the original * image's coordinate space. */ - offset: { + offset: {| x: number, y: number, - }, + |}, /** * The size (dimensions) of the cropped image, specified in the original * image's coordinate space. */ - size: { + size: {| width: number, height: number, - }, + |}, /** * (Optional) size to scale the cropped image to. */ - displaySize?: ?{ + displaySize?: ?{| width: number, height: number, - }, + |}, /** * (Optional) the resizing mode to use when scaling the image. If the * `displaySize` param is not specified, this has no effect. diff --git a/Libraries/Image/ImageProps.js b/Libraries/Image/ImageProps.js index 54f6250e1f1458..99591c48f604b9 100644 --- a/Libraries/Image/ImageProps.js +++ b/Libraries/Image/ImageProps.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. @@ -10,35 +10,42 @@ 'use strict'; -const EdgeInsetsPropType = require('EdgeInsetsPropType'); -const ImageSourcePropType = require('ImageSourcePropType'); -const ImageStylePropTypes = require('ImageStylePropTypes'); -const PropTypes = require('prop-types'); -const StyleSheetPropType = require('StyleSheetPropType'); - +import type {SyntheticEvent, LayoutEvent} from 'CoreEventTypes'; +import type {EdgeInsetsProp} from 'EdgeInsetsPropType'; +import type {ImageSource} from 'ImageSource'; +import type {ViewStyleProp, ImageStyleProp} from 'StyleSheet'; import type {DimensionValue} from 'StyleSheetTypes'; import type {ViewProps} from 'ViewPropTypes'; -import type {ImageSource} from 'ImageSource'; -import type {EdgeInsetsProp} from 'EdgeInsetsPropType'; -import type {SyntheticEvent} from 'CoreEventTypes'; -import type {ImageStyleProp} from 'StyleSheet'; -type OnLoadEvent = SyntheticEvent< +export type ImageLoadEvent = SyntheticEvent< $ReadOnly<{| - // Only on Android - uri?: string, - source: $ReadOnly<{| width: number, height: number, url: string, |}>, + uri?: string, // Only on Android |}>, >; type IOSImageProps = $ReadOnly<{| + /** + * A static image to display while loading the image source. + * + * See https://facebook.github.io/react-native/docs/image.html#defaultsource + */ defaultSource?: ?ImageSource, + /** + * Invoked when a partial load of the image is complete. + * + * See https://facebook.github.io/react-native/docs/image.html#onpartialload + */ onPartialLoad?: ?() => void, + /** + * Invoked on download progress with `{nativeEvent: {loaded, total}}`. + * + * See https://facebook.github.io/react-native/docs/image.html#onprogress + */ onProgress?: ?( event: SyntheticEvent<$ReadOnly<{|loaded: number, total: number|}>>, ) => void, @@ -51,142 +58,111 @@ type AndroidImageProps = $ReadOnly<{| |}>; export type ImageProps = {| - ...ViewProps, + ...$Diff>, ...IOSImageProps, ...AndroidImageProps, - blurRadius?: number, - capInsets?: ?EdgeInsetsProp, - onError?: ?(event: SyntheticEvent<$ReadOnly<{||}>>) => void, - onLoad?: ?(event: OnLoadEvent) => void, - onLoadEnd?: ?() => void, - onLoadStart?: ?() => void, - resizeMethod?: ?('auto' | 'resize' | 'scale'), - source?: ?ImageSource, - style?: ImageStyleProp, - - // Can be set via props or style, for now - height?: DimensionValue, - width?: DimensionValue, - resizeMode?: ?('cover' | 'contain' | 'stretch' | 'repeat' | 'center'), - - src?: empty, - children?: empty, -|}; - -module.exports = { - /** - * See https://facebook.github.io/react-native/docs/image.html#style - */ - style: StyleSheetPropType(ImageStylePropTypes), - /** - * The image source (either a remote URL or a local file resource). - * - * See https://facebook.github.io/react-native/docs/image.html#source - */ - source: ImageSourcePropType, - /** - * A static image to display while loading the image source. - * - * See https://facebook.github.io/react-native/docs/image.html#defaultsource - */ - defaultSource: PropTypes.oneOfType([ - PropTypes.shape({ - uri: PropTypes.string, - width: PropTypes.number, - height: PropTypes.number, - scale: PropTypes.number, - }), - PropTypes.number, - ]), /** * When true, indicates the image is an accessibility element. * * See https://facebook.github.io/react-native/docs/image.html#accessible */ - accessible: PropTypes.bool, + accessible?: ?boolean, + /** * The text that's read by the screen reader when the user interacts with * the image. * * See https://facebook.github.io/react-native/docs/image.html#accessibilitylabel */ - accessibilityLabel: PropTypes.node, + accessibilityLabel?: ?Stringish, + /** * blurRadius: the blur radius of the blur filter added to the image * * See https://facebook.github.io/react-native/docs/image.html#blurradius */ - blurRadius: PropTypes.number, + blurRadius?: ?number, + /** * See https://facebook.github.io/react-native/docs/image.html#capinsets */ - capInsets: EdgeInsetsPropType, + capInsets?: ?EdgeInsetsProp, + /** - * See https://facebook.github.io/react-native/docs/image.html#resizemethod + * Invoked on load error with `{nativeEvent: {error}}`. + * + * See https://facebook.github.io/react-native/docs/image.html#onerror */ - resizeMethod: PropTypes.oneOf(['auto', 'resize', 'scale']), + onError?: ?(event: SyntheticEvent<$ReadOnly<{||}>>) => void, + /** - * Determines how to resize the image when the frame doesn't match the raw - * image dimensions. + * Invoked on mount and layout changes with + * `{nativeEvent: {layout: {x, y, width, height}}}`. * - * See https://facebook.github.io/react-native/docs/image.html#resizemode + * See https://facebook.github.io/react-native/docs/image.html#onlayout */ - resizeMode: PropTypes.oneOf([ - 'cover', - 'contain', - 'stretch', - 'repeat', - 'center', - ]), + + onLayout?: ?(event: LayoutEvent) => mixed, + /** - * A unique identifier for this element to be used in UI Automation - * testing scripts. + * Invoked when load completes successfully. * - * See https://facebook.github.io/react-native/docs/image.html#testid + * See https://facebook.github.io/react-native/docs/image.html#onload */ - testID: PropTypes.string, + onLoad?: ?(event: ImageLoadEvent) => void, + /** - * Invoked on mount and layout changes with - * `{nativeEvent: {layout: {x, y, width, height}}}`. + * Invoked when load either succeeds or fails. * - * See https://facebook.github.io/react-native/docs/image.html#onlayout + * See https://facebook.github.io/react-native/docs/image.html#onloadend */ - onLayout: PropTypes.func, + onLoadEnd?: ?() => void, + /** * Invoked on load start. * * See https://facebook.github.io/react-native/docs/image.html#onloadstart */ - onLoadStart: PropTypes.func, + onLoadStart?: ?() => void, + /** - * Invoked on download progress with `{nativeEvent: {loaded, total}}`. - * - * See https://facebook.github.io/react-native/docs/image.html#onprogress + * See https://facebook.github.io/react-native/docs/image.html#resizemethod */ - onProgress: PropTypes.func, + resizeMethod?: ?('auto' | 'resize' | 'scale'), + /** - * Invoked on load error with `{nativeEvent: {error}}`. + * The image source (either a remote URL or a local file resource). * - * See https://facebook.github.io/react-native/docs/image.html#onerror + * See https://facebook.github.io/react-native/docs/image.html#source */ - onError: PropTypes.func, + source?: ?ImageSource, + /** - * Invoked when a partial load of the image is complete. - * - * See https://facebook.github.io/react-native/docs/image.html#onpartialload + * See https://facebook.github.io/react-native/docs/image.html#style */ - onPartialLoad: PropTypes.func, + style?: ?ImageStyleProp, + + // Can be set via props or style, for now + height?: ?DimensionValue, + width?: ?DimensionValue, + /** - * Invoked when load completes successfully. + * Determines how to resize the image when the frame doesn't match the raw + * image dimensions. * - * See https://facebook.github.io/react-native/docs/image.html#onload + * See https://facebook.github.io/react-native/docs/image.html#resizemode */ - onLoad: PropTypes.func, + resizeMode?: ?('cover' | 'contain' | 'stretch' | 'repeat' | 'center'), + /** - * Invoked when load either succeeds or fails. + * A unique identifier for this element to be used in UI Automation + * testing scripts. * - * See https://facebook.github.io/react-native/docs/image.html#onloadend + * See https://facebook.github.io/react-native/docs/image.html#testid */ - onLoadEnd: PropTypes.func, -}; + testID?: ?string, + + src?: empty, + children?: empty, +|}; diff --git a/Libraries/Image/ImageResizeMode.js b/Libraries/Image/ImageResizeMode.js index 48779e383f3119..1dad3309b1588d 100644 --- a/Libraries/Image/ImageResizeMode.js +++ b/Libraries/Image/ImageResizeMode.js @@ -1,52 +1,36 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. * - * @flow + * @flow strict * @format */ -'use strict'; -/* $FlowFixMe(>=0.54.0 site=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. */ -const keyMirror = require('fbjs/lib/keyMirror'); +'use strict'; /** - * ImageResizeMode - Enum for different image resizing modes, set via - * `resizeMode` style property on `` components. + * ImageResizeMode defines valid values for different image resizing modes set + * via the `resizeMode` style property on ``. */ -const ImageResizeMode = keyMirror({ - /** - * contain - The image will be resized such that it will be completely - * visible, contained within the frame of the View. - */ - contain: null, - /** - * cover - The image will be resized such that the entire area of the view - * is covered by the image, potentially clipping parts of the image. - */ - cover: null, - /** - * stretch - The image will be stretched to fill the entire frame of the - * view without clipping. This may change the aspect ratio of the image, - * distorting it. - */ - stretch: null, - /** - * center - The image will be scaled down such that it is completely visible, - * if bigger than the area of the view. - * The image will not be scaled up. - */ - center: null, +export type ImageResizeMode = + // Resize by scaling down such that it is completely visible, if bigger than + // the area of the view. The image will not be scaled up. + | 'center' + + // Resize such that it will be completely visible, contained within the frame + // of the View. + | 'contain' + + // Resize such that the entire area of the view is covered by the image, + // potentially clipping parts of the image. + | 'cover' - /** - * repeat - The image will be repeated to cover the frame of the View. The - * image will keep it's size and aspect ratio. - */ - repeat: null, -}); + // Resize by repeating to cover the frame of the View. The image will keep its + // size and aspect ratio. + | 'repeat' -module.exports = ImageResizeMode; + // Resize by stretching it to fill the entire frame of the view without + // clipping. This may change the aspect ratio of the image, distorting it. + | 'stretch'; diff --git a/Libraries/Image/ImageSource.js b/Libraries/Image/ImageSource.js index 5c3c84df901209..0e03dc78c0f5d1 100644 --- a/Libraries/Image/ImageSource.js +++ b/Libraries/Image/ImageSource.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. @@ -14,15 +14,73 @@ // that might have more keys. This also has to be inexact to support taking // instances of classes like FBIcon. // https://fburl.com/8lynhvtw -type ImageURISource = $ReadOnly<{ +export type ImageURISource = $ReadOnly<{ + /** + * `uri` is a string representing the resource identifier for the image, which + * could be an http address, a local file path, or the name of a static image + * resource (which should be wrapped in the `require('./path/to/image.png')` + * function). + */ uri?: ?string, + + /** + * `bundle` is the iOS asset bundle which the image is included in. This + * will default to [NSBundle mainBundle] if not set. + * @platform ios + */ bundle?: ?string, + + /** + * `method` is the HTTP Method to use. Defaults to GET if not specified. + */ method?: ?string, + + /** + * `headers` is an object representing the HTTP headers to send along with the + * request for a remote image. + */ headers?: ?Object, + + /** + * `body` is the HTTP body to send with the request. This must be a valid + * UTF-8 string, and will be sent exactly as specified, with no + * additional encoding (e.g. URL-escaping or base64) applied. + */ body?: ?string, + + /** + * `cache` determines how the requests handles potentially cached + * responses. + * + * - `default`: Use the native platforms default strategy. `useProtocolCachePolicy` on iOS. + * + * - `reload`: The data for the URL will be loaded from the originating source. + * No existing cache data should be used to satisfy a URL load request. + * + * - `force-cache`: The existing cached data will be used to satisfy the request, + * regardless of its age or expiration date. If there is no existing data in the cache + * corresponding the request, the data is loaded from the originating source. + * + * - `only-if-cached`: The existing cache data will be used to satisfy a request, regardless of + * its age or expiration date. If there is no existing data in the cache corresponding + * to a URL load request, no attempt is made to load the data from the originating source, + * and the load is considered to have failed. + * + * @platform ios + */ cache?: ?('default' | 'reload' | 'force-cache' | 'only-if-cached'), + + /** + * `width` and `height` can be specified if known at build time, in which case + * these will be used to set the default `` component dimensions. + */ width?: ?number, height?: ?number, + + /** + * `scale` is used to indicate the scale factor of the image. Defaults to 1.0 if + * unspecified, meaning that one image pixel equates to one display point / DIP. + */ scale?: ?number, }>; diff --git a/Libraries/Image/ImageSourcePropType.js b/Libraries/Image/ImageSourcePropType.js deleted file mode 100644 index 6f67113fe1bf18..00000000000000 --- a/Libraries/Image/ImageSourcePropType.js +++ /dev/null @@ -1,90 +0,0 @@ -/** - * Copyright (c) 2015-present, Facebook, Inc. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @no-flow - * @format - */ -'use strict'; - -const PropTypes = require('prop-types'); - -const ImageURISourcePropType = PropTypes.shape({ - /** - * `uri` is a string representing the resource identifier for the image, which - * could be an http address, a local file path, or the name of a static image - * resource (which should be wrapped in the `require('./path/to/image.png')` - * function). - */ - uri: PropTypes.string, - /** - * `bundle` is the iOS asset bundle which the image is included in. This - * will default to [NSBundle mainBundle] if not set. - * @platform ios - */ - bundle: PropTypes.string, - /** - * `method` is the HTTP Method to use. Defaults to GET if not specified. - */ - method: PropTypes.string, - /** - * `headers` is an object representing the HTTP headers to send along with the - * request for a remote image. - */ - headers: PropTypes.objectOf(PropTypes.string), - /** - * `body` is the HTTP body to send with the request. This must be a valid - * UTF-8 string, and will be sent exactly as specified, with no - * additional encoding (e.g. URL-escaping or base64) applied. - */ - body: PropTypes.string, - /** - * `cache` determines how the requests handles potentially cached - * responses. - * - * - `default`: Use the native platforms default strategy. `useProtocolCachePolicy` on iOS. - * - * - `reload`: The data for the URL will be loaded from the originating source. - * No existing cache data should be used to satisfy a URL load request. - * - * - `force-cache`: The existing cached data will be used to satisfy the request, - * regardless of its age or expiration date. If there is no existing data in the cache - * corresponding the request, the data is loaded from the originating source. - * - * - `only-if-cached`: The existing cache data will be used to satisfy a request, regardless of - * its age or expiration date. If there is no existing data in the cache corresponding - * to a URL load request, no attempt is made to load the data from the originating source, - * and the load is considered to have failed. - * - * @platform ios - */ - cache: PropTypes.oneOf([ - 'default', - 'reload', - 'force-cache', - 'only-if-cached', - ]), - /** - * `width` and `height` can be specified if known at build time, in which case - * these will be used to set the default `` component dimensions. - */ - width: PropTypes.number, - height: PropTypes.number, - /** - * `scale` is used to indicate the scale factor of the image. Defaults to 1.0 if - * unspecified, meaning that one image pixel equates to one display point / DIP. - */ - scale: PropTypes.number, -}); - -const ImageSourcePropType = PropTypes.oneOfType([ - ImageURISourcePropType, - // Opaque type returned by require('./image.jpg') - PropTypes.number, - // Multiple sources - PropTypes.arrayOf(ImageURISourcePropType), -]); - -module.exports = ImageSourcePropType; diff --git a/Libraries/Image/ImageStore.js b/Libraries/Image/ImageStore.js index 5373020376a5f1..60273b79f201f2 100644 --- a/Libraries/Image/ImageStore.js +++ b/Libraries/Image/ImageStore.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. diff --git a/Libraries/Image/ImageViewNativeComponent.js b/Libraries/Image/ImageViewNativeComponent.js new file mode 100644 index 00000000000000..47f8d531f756d8 --- /dev/null +++ b/Libraries/Image/ImageViewNativeComponent.js @@ -0,0 +1,17 @@ +/** + * 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'; + +const requireNativeComponent = require('requireNativeComponent'); + +const ImageViewNativeComponent = requireNativeComponent('RCTImageView'); + +module.exports = ImageViewNativeComponent; diff --git a/Libraries/Image/RCTGIFImageDecoder.h b/Libraries/Image/RCTGIFImageDecoder.h index 1f942aef4c8ce6..f9cc0eef4ebf94 100644 --- a/Libraries/Image/RCTGIFImageDecoder.h +++ b/Libraries/Image/RCTGIFImageDecoder.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. diff --git a/Libraries/Image/RCTGIFImageDecoder.m b/Libraries/Image/RCTGIFImageDecoder.m index 81a2787777d293..cf7119d4509472 100644 --- a/Libraries/Image/RCTGIFImageDecoder.m +++ b/Libraries/Image/RCTGIFImageDecoder.m @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. @@ -32,7 +32,17 @@ - (RCTImageLoaderCancellationBlock)decodeImageData:(NSData *)imageData { CGImageSourceRef imageSource = CGImageSourceCreateWithData((CFDataRef)imageData, NULL); NSDictionary *properties = (__bridge_transfer NSDictionary *)CGImageSourceCopyProperties(imageSource, NULL); - NSUInteger loopCount = [properties[(id)kCGImagePropertyGIFDictionary][(id)kCGImagePropertyGIFLoopCount] unsignedIntegerValue]; + CGFloat loopCount = 0; + if ([[properties[(id)kCGImagePropertyGIFDictionary] allKeys] containsObject:(id)kCGImagePropertyGIFLoopCount]) { + loopCount = [properties[(id)kCGImagePropertyGIFDictionary][(id)kCGImagePropertyGIFLoopCount] unsignedIntegerValue]; + if (loopCount == 0) { + // A loop count of 0 means infinite + loopCount = HUGE_VALF; + } else { + // A loop count of 1 means it should repeat twice, 2 means, thrice, etc. + loopCount += 1; + } + } UIImage *image = nil; size_t imageCount = CGImageSourceGetCount(imageSource); @@ -88,11 +98,12 @@ - (RCTImageLoaderCancellationBlock)decodeImageData:(NSData *)imageData // Create animation CAKeyframeAnimation *animation = [CAKeyframeAnimation animationWithKeyPath:@"contents"]; animation.calculationMode = kCAAnimationDiscrete; - animation.repeatCount = loopCount == 0 ? HUGE_VALF : loopCount; + animation.repeatCount = loopCount; animation.keyTimes = keyTimes; animation.values = images; animation.duration = duration; animation.removedOnCompletion = NO; + animation.fillMode = kCAFillModeForwards; image.reactKeyframeAnimation = animation; } else { diff --git a/Libraries/Image/RCTImageBlurUtils.h b/Libraries/Image/RCTImageBlurUtils.h index 0bd7070c495716..c7eb462a8ff477 100644 --- a/Libraries/Image/RCTImageBlurUtils.h +++ b/Libraries/Image/RCTImageBlurUtils.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013-present, Facebook, Inc. + * 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. diff --git a/Libraries/Image/RCTImageBlurUtils.m b/Libraries/Image/RCTImageBlurUtils.m index a27ae047ebd0ef..6f3a5e6362d2d3 100644 --- a/Libraries/Image/RCTImageBlurUtils.m +++ b/Libraries/Image/RCTImageBlurUtils.m @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. diff --git a/Libraries/Image/RCTImageCache.h b/Libraries/Image/RCTImageCache.h index c0d24ad25a2d41..b7acc1126ca6cd 100644 --- a/Libraries/Image/RCTImageCache.h +++ b/Libraries/Image/RCTImageCache.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. diff --git a/Libraries/Image/RCTImageCache.m b/Libraries/Image/RCTImageCache.m index 89695282fae6ed..b7db10db6ed5b2 100644 --- a/Libraries/Image/RCTImageCache.m +++ b/Libraries/Image/RCTImageCache.m @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. @@ -18,27 +18,29 @@ #import "RCTImageUtils.h" -static const NSUInteger RCTMaxCachableDecodedImageSizeInBytes = 1048576; // 1MB +static const NSUInteger RCTMaxCachableDecodedImageSizeInBytes = 2097152; // 2 MB static NSString *RCTCacheKeyForImage(NSString *imageTag, CGSize size, CGFloat scale, - RCTResizeMode resizeMode, NSString *responseDate) + RCTResizeMode resizeMode) { - return [NSString stringWithFormat:@"%@|%g|%g|%g|%lld|%@", - imageTag, size.width, size.height, scale, (long long)resizeMode, responseDate]; + return [NSString stringWithFormat:@"%@|%g|%g|%g|%lld", + imageTag, size.width, size.height, scale, (long long)resizeMode]; } @implementation RCTImageCache { NSOperationQueue *_imageDecodeQueue; NSCache *_decodedImageCache; + NSMutableDictionary *_cacheStaleTimes; } - (instancetype)init { _decodedImageCache = [NSCache new]; - _decodedImageCache.totalCostLimit = 5 * 1024 * 1024; // 5MB - #if !TARGET_OS_OSX // TODO(macOS ISS#2323203) + _decodedImageCache.totalCostLimit = 20 * 1024 * 1024; // 20 MB + _cacheStaleTimes = [[NSMutableDictionary alloc] init]; + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(clearCache) name:UIApplicationDidReceiveMemoryWarningNotification @@ -61,6 +63,9 @@ - (void)dealloc - (void)clearCache { [_decodedImageCache removeAllObjects]; + @synchronized(_cacheStaleTimes) { + [_cacheStaleTimes removeAllObjects]; + } } #endif // TODO(macOS ISS#2323203) @@ -83,9 +88,19 @@ - (UIImage *)imageForUrl:(NSString *)url size:(CGSize)size scale:(CGFloat)scale resizeMode:(RCTResizeMode)resizeMode - responseDate:(NSString *)responseDate { - NSString *cacheKey = RCTCacheKeyForImage(url, size, scale, resizeMode, responseDate); + NSString *cacheKey = RCTCacheKeyForImage(url, size, scale, resizeMode); + @synchronized(_cacheStaleTimes) { + id staleTime = _cacheStaleTimes[cacheKey]; + if (staleTime) { + if ([[NSDate new] compare:(NSDate *)staleTime] == NSOrderedDescending) { + // cached image has expired, clear it out to make room for others + [_cacheStaleTimes removeObjectForKey:cacheKey]; + [_decodedImageCache removeObjectForKey:cacheKey]; + return nil; + } + } + } return [_decodedImageCache objectForKey:cacheKey]; } @@ -95,9 +110,46 @@ - (void)addImageToCache:(UIImage *)image scale:(CGFloat)scale resizeMode:(RCTResizeMode)resizeMode responseDate:(NSString *)responseDate + cacheControl:(NSString *)cacheControl { - NSString *cacheKey = RCTCacheKeyForImage(url, size, scale, resizeMode, responseDate); - return [self addImageToCache:image forKey:cacheKey]; + NSString *cacheKey = RCTCacheKeyForImage(url, size, scale, resizeMode); + BOOL shouldCache = YES; + NSDate *staleTime; + NSArray *components = [cacheControl componentsSeparatedByString:@","]; + for (NSString *component in components) { + if ([component containsString:@"no-cache"] || [component containsString:@"no-store"] || [component hasSuffix:@"max-age=0"]) { + shouldCache = NO; + break; + } else { + NSRange range = [component rangeOfString:@"max-age="]; + if (range.location != NSNotFound) { + NSInteger seconds = [[component substringFromIndex:range.location + range.length] integerValue]; + NSDate *originalDate = [self dateWithHeaderString:responseDate]; + staleTime = [originalDate dateByAddingTimeInterval:(NSTimeInterval)seconds]; + } + } + } + if (shouldCache) { + if (staleTime) { + @synchronized(_cacheStaleTimes) { + _cacheStaleTimes[cacheKey] = staleTime; + } + } + return [self addImageToCache:image forKey:cacheKey]; + } +} + +- (NSDate *)dateWithHeaderString:(NSString *)headerDateString { + static NSDateFormatter *formatter; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + formatter = [[NSDateFormatter alloc] init]; + formatter.locale = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US_POSIX"]; + formatter.dateFormat = @"EEE',' dd MMM yyyy HH':'mm':'ss 'GMT'"; + formatter.timeZone = [NSTimeZone timeZoneForSecondsFromGMT:0]; + }); + + return [formatter dateFromString:headerDateString]; } @end diff --git a/Libraries/Image/RCTImageEditingManager.h b/Libraries/Image/RCTImageEditingManager.h index dda409af33fc22..684855f999e3b1 100644 --- a/Libraries/Image/RCTImageEditingManager.h +++ b/Libraries/Image/RCTImageEditingManager.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. diff --git a/Libraries/Image/RCTImageEditingManager.m b/Libraries/Image/RCTImageEditingManager.m index 2a7d33cbcb13fd..c38e74ac0b93ad 100644 --- a/Libraries/Image/RCTImageEditingManager.m +++ b/Libraries/Image/RCTImageEditingManager.m @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. diff --git a/Libraries/Image/RCTImageLoader.h b/Libraries/Image/RCTImageLoader.h index e44b4af26f1b6f..e9851af08fe6c9 100644 --- a/Libraries/Image/RCTImageLoader.h +++ b/Libraries/Image/RCTImageLoader.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. @@ -24,15 +24,15 @@ typedef dispatch_block_t RCTImageLoaderCancellationBlock; - (UIImage *)imageForUrl:(NSString *)url size:(CGSize)size scale:(CGFloat)scale - resizeMode:(RCTResizeMode)resizeMode - responseDate:(NSString *)responseDate; + resizeMode:(RCTResizeMode)resizeMode; - (void)addImageToCache:(UIImage *)image URL:(NSString *)url size:(CGSize)size scale:(CGFloat)scale resizeMode:(RCTResizeMode)resizeMode - responseDate:(NSString *)responseDate; + responseDate:(NSString *)responseDate + cacheControl:(NSString *)cacheControl; @end @@ -129,6 +129,14 @@ typedef dispatch_block_t RCTImageLoaderCancellationBlock; */ - (RCTImageLoaderCancellationBlock)getImageSizeForURLRequest:(NSURLRequest *)imageURLRequest block:(void(^)(NSError *error, CGSize size))completionBlock; +/** + * Determines whether given image URLs are cached locally. The `requests` array is expected + * to contain objects convertible to NSURLRequest. The return value maps URLs to strings: + * "disk" for images known to be cached in non-volatile storage, "memory" for images known + * to be cached in memory. Dictionary items corresponding to images that are not known to be + * cached are simply missing. + */ +- (NSDictionary *)getImageCacheStatus:(NSArray *)requests; /** * Allows developers to set their own caching implementation for diff --git a/Libraries/Image/RCTImageLoader.m b/Libraries/Image/RCTImageLoader.m index 7ec9df6176a0af..1436cc9a69f806 100644 --- a/Libraries/Image/RCTImageLoader.m +++ b/Libraries/Image/RCTImageLoader.m @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. @@ -322,7 +322,7 @@ - (RCTImageLoaderCancellationBlock)_loadImageOrDataWithURLRequest:(NSURLRequest resizeMode:(RCTResizeMode)resizeMode progressBlock:(RCTImageLoaderProgressBlock)progressHandler partialLoadBlock:(RCTImageLoaderPartialLoadBlock)partialLoadHandler - completionBlock:(void (^)(NSError *error, id imageOrData, BOOL cacheResult, NSString *fetchDate))completionBlock + completionBlock:(void (^)(NSError *error, id imageOrData, BOOL cacheResult, NSString *fetchDate, NSString *cacheControl))completionBlock { { NSMutableURLRequest *mutableRequest = [request mutableCopy]; @@ -345,15 +345,15 @@ - (RCTImageLoaderCancellationBlock)_loadImageOrDataWithURLRequest:(NSURLRequest BOOL requiresScheduling = [loadHandler respondsToSelector:@selector(requiresScheduling)] ? [loadHandler requiresScheduling] : YES; + BOOL cacheResult = [loadHandler respondsToSelector:@selector(shouldCacheLoadedImages)] ? + [loadHandler shouldCacheLoadedImages] : YES; + __block atomic_bool cancelled = ATOMIC_VAR_INIT(NO); // TODO: Protect this variable shared between threads. __block dispatch_block_t cancelLoad = nil; - void (^completionHandler)(NSError *, id, NSString *) = ^(NSError *error, id imageOrData, NSString *fetchDate) { + void (^completionHandler)(NSError *, id, NSString *, NSString *) = ^(NSError *error, id imageOrData, NSString *fetchDate, NSString *cacheControl) { cancelLoad = nil; - BOOL cacheResult = [loadHandler respondsToSelector:@selector(shouldCacheLoadedImages)] ? - [loadHandler shouldCacheLoadedImages] : YES; - // If we've received an image, we should try to set it synchronously, // if it's data, do decoding on a background thread. if (RCTIsMainQueue() && ![imageOrData isKindOfClass:[UIImage class]]) { @@ -361,11 +361,11 @@ - (RCTImageLoaderCancellationBlock)_loadImageOrDataWithURLRequest:(NSURLRequest // expecting it, and may do expensive post-processing in the callback dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ if (!atomic_load(&cancelled)) { - completionBlock(error, imageOrData, cacheResult, fetchDate); + completionBlock(error, imageOrData, cacheResult, fetchDate, cacheControl); } }); } else if (!atomic_load(&cancelled)) { - completionBlock(error, imageOrData, cacheResult, fetchDate); + completionBlock(error, imageOrData, cacheResult, fetchDate, cacheControl); } }; @@ -379,7 +379,7 @@ - (RCTImageLoaderCancellationBlock)_loadImageOrDataWithURLRequest:(NSURLRequest progressHandler:progressHandler partialLoadHandler:partialLoadHandler completionHandler:^(NSError *error, UIImage *image){ - completionHandler(error, image, nil); + completionHandler(error, image, nil, nil); }]; } @@ -403,13 +403,25 @@ - (RCTImageLoaderCancellationBlock)_loadImageOrDataWithURLRequest:(NSURLRequest progressHandler:progressHandler partialLoadHandler:partialLoadHandler completionHandler:^(NSError *error, UIImage *image) { - completionHandler(error, image, nil); + completionHandler(error, image, nil, nil); }]; } else { - // Use networking module to load image - cancelLoad = [strongSelf _loadURLRequest:request - progressBlock:progressHandler - completionBlock:completionHandler]; + UIImage *image; + if (cacheResult) { + image = [[strongSelf imageCache] imageForUrl:request.URL.absoluteString + size:size + scale:scale + resizeMode:resizeMode]; + } + + if (image) { + completionHandler(nil, image, nil, nil); + } else { + // Use networking module to load image + cancelLoad = [strongSelf _loadURLRequest:request + progressBlock:progressHandler + completionBlock:completionHandler]; + } } }); @@ -428,7 +440,7 @@ - (RCTImageLoaderCancellationBlock)_loadImageOrDataWithURLRequest:(NSURLRequest - (RCTImageLoaderCancellationBlock)_loadURLRequest:(NSURLRequest *)request progressBlock:(RCTImageLoaderProgressBlock)progressHandler - completionBlock:(void (^)(NSError *error, id imageOrData, NSString *fetchDate))completionHandler + completionBlock:(void (^)(NSError *error, id imageOrData, NSString *fetchDate, NSString *cacheControl))completionHandler { // Check if networking module is available if (RCT_DEBUG && ![_bridge respondsToSelector:@selector(networking)]) { @@ -450,18 +462,19 @@ - (RCTImageLoaderCancellationBlock)_loadURLRequest:(NSURLRequest *)request RCTURLRequestCompletionBlock processResponse = ^(NSURLResponse *response, NSData *data, NSError *error) { // Check for system errors if (error) { - completionHandler(error, nil, nil); + completionHandler(error, nil, nil, nil); return; } else if (!response) { - completionHandler(RCTErrorWithMessage(@"Response metadata error"), nil, nil); + completionHandler(RCTErrorWithMessage(@"Response metadata error"), nil, nil, nil); return; } else if (!data) { - completionHandler(RCTErrorWithMessage(@"Unknown image download error"), nil, nil); + completionHandler(RCTErrorWithMessage(@"Unknown image download error"), nil, nil, nil); return; } // Check for http errors NSString *responseDate; + NSString *cacheControl; if ([response isKindOfClass:[NSHTTPURLResponse class]]) { NSInteger statusCode = ((NSHTTPURLResponse *)response).statusCode; if (statusCode != 200) { @@ -469,15 +482,16 @@ - (RCTImageLoaderCancellationBlock)_loadURLRequest:(NSURLRequest *)request NSDictionary *userInfo = @{NSLocalizedDescriptionKey: errorMessage}; completionHandler([[NSError alloc] initWithDomain:NSURLErrorDomain code:statusCode - userInfo:userInfo], nil, nil); + userInfo:userInfo], nil, nil, nil); return; } responseDate = ((NSHTTPURLResponse *)response).allHeaderFields[@"Date"]; + cacheControl = ((NSHTTPURLResponse *)response).allHeaderFields[@"Cache-Control"]; } // Call handler - completionHandler(nil, data, responseDate); + completionHandler(nil, data, responseDate, cacheControl); }; // Download image @@ -499,7 +513,7 @@ - (RCTImageLoaderCancellationBlock)_loadURLRequest:(NSURLRequest *)request } else { someError = RCTErrorWithMessage(@"Unknown image download error"); } - completionHandler(someError, nil, nil); + completionHandler(someError, nil, nil, nil); [strongSelf dequeueTasks]; return; } @@ -565,7 +579,7 @@ - (RCTImageLoaderCancellationBlock)loadImageWithURLRequest:(NSURLRequest *)image }; __weak RCTImageLoader *weakSelf = self; - void (^completionHandler)(NSError *, id, BOOL, NSString *) = ^(NSError *error, id imageOrData, BOOL cacheResult, NSString *fetchDate) { + void (^completionHandler)(NSError *, id, BOOL, NSString *, NSString *) = ^(NSError *error, id imageOrData, BOOL cacheResult, NSString *fetchDate, NSString *cacheControl) { __typeof(self) strongSelf = weakSelf; if (atomic_load(&cancelled) || !strongSelf) { return; @@ -577,20 +591,6 @@ - (RCTImageLoaderCancellationBlock)loadImageWithURLRequest:(NSURLRequest *)image return; } - // Check decoded image cache - if (cacheResult) { - UIImage *image = [[strongSelf imageCache] imageForUrl:imageURLRequest.URL.absoluteString - size:size - scale:scale - resizeMode:resizeMode - responseDate:fetchDate]; - if (image) { - cancelLoad = nil; - completionBlock(nil, image); - return; - } - } - RCTImageLoaderCompletionBlock decodeCompletionHandler = ^(NSError *error_, UIImage *image) { if (cacheResult && image) { // Store decoded image in cache @@ -599,7 +599,8 @@ - (RCTImageLoaderCancellationBlock)loadImageWithURLRequest:(NSURLRequest *)image size:size scale:scale resizeMode:resizeMode - responseDate:fetchDate]; + responseDate:fetchDate + cacheControl:cacheControl]; } cancelLoad = nil; @@ -735,7 +736,7 @@ - (RCTImageLoaderCancellationBlock)decodeImageData:(NSData *)data - (RCTImageLoaderCancellationBlock)getImageSizeForURLRequest:(NSURLRequest *)imageURLRequest block:(void(^)(NSError *error, CGSize size))callback { - void (^completion)(NSError *, id, BOOL, NSString *) = ^(NSError *error, id imageOrData, BOOL cacheResult, NSString *fetchDate) { + void (^completion)(NSError *, id, BOOL, NSString *, NSString *) = ^(NSError *error, id imageOrData, BOOL cacheResult, NSString *fetchDate, NSString *cacheControl) { CGSize size; if ([imageOrData isKindOfClass:[NSData class]]) { NSDictionary *meta = RCTGetImageMetadata(imageOrData); @@ -783,45 +784,69 @@ - (RCTImageLoaderCancellationBlock)getImageSizeForURLRequest:(NSURLRequest *)ima completionBlock:completion]; } -#pragma mark - RCTURLRequestHandler - -- (BOOL)canHandleRequest:(NSURLRequest *)request +- (NSDictionary *)getImageCacheStatus:(NSArray *)requests { - NSURL *requestURL = request.URL; - - // If the data being loaded is a video, return NO - // Even better may be to implement this on the RCTImageURLLoader that would try to load it, - // but we'd have to run the logic both in RCTPhotoLibraryImageLoader and - // RCTAssetsLibraryRequestHandler. Once we drop iOS7 though, we'd drop - // RCTAssetsLibraryRequestHandler and can move it there. - static NSRegularExpression *videoRegex = nil; - if (!videoRegex) { - NSError *error = nil; - videoRegex = [NSRegularExpression regularExpressionWithPattern:@"(?:&|^)ext=MOV(?:&|$)" - options:NSRegularExpressionCaseInsensitive - error:&error]; - if (error) { - RCTLogError(@"%@", error); + NSMutableDictionary *results = [NSMutableDictionary dictionary]; + for (id request in requests) { + NSURLRequest *urlRequest = [RCTConvert NSURLRequest:request]; + if (urlRequest) { + NSCachedURLResponse *cachedResponse = [NSURLCache.sharedURLCache cachedResponseForRequest:urlRequest]; + if (cachedResponse) { + if (cachedResponse.storagePolicy == NSURLCacheStorageAllowedInMemoryOnly) { + [results setObject:@"memory" forKey:urlRequest.URL.absoluteString]; + } else { + [results setObject:@"disk" forKey:urlRequest.URL.absoluteString]; + } } } + } + return results; +} - NSString *query = requestURL.query; - if (query != nil && [videoRegex firstMatchInString:query - options:0 - range:NSMakeRange(0, query.length)]) { - return NO; - } +#pragma mark - RCTURLRequestHandler - for (id loader in _loaders) { - // Don't use RCTImageURLLoader protocol for modules that already conform to - // RCTURLRequestHandler as it's inefficient to decode an image and then - // convert it back into data - if (![loader conformsToProtocol:@protocol(RCTURLRequestHandler)] && - [loader canLoadImageURL:requestURL]) { - return YES; - } +- (BOOL)canHandleRequest:(NSURLRequest *)request +{ + NSURL *requestURL = request.URL; + + // If the data being loaded is a video, return NO + // Even better may be to implement this on the RCTImageURLLoader that would try to load it, + // but we'd have to run the logic both in RCTPhotoLibraryImageLoader and + // RCTAssetsLibraryRequestHandler. Once we drop iOS7 though, we'd drop + // RCTAssetsLibraryRequestHandler and can move it there. + static NSRegularExpression *videoRegex; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + NSError *error = nil; + videoRegex = [NSRegularExpression regularExpressionWithPattern:@"(?:&|^)ext=MOV(?:&|$)" + options:NSRegularExpressionCaseInsensitive + error:&error]; + if (error) { + RCTLogError(@"%@", error); } + }); + + NSString *query = requestURL.query; + if ( + query != nil && + [videoRegex firstMatchInString:query + options:0 + range:NSMakeRange(0, query.length)] + ) { return NO; + } + + for (id loader in _loaders) { + // Don't use RCTImageURLLoader protocol for modules that already conform to + // RCTURLRequestHandler as it's inefficient to decode an image and then + // convert it back into data + if (![loader conformsToProtocol:@protocol(RCTURLRequestHandler)] && + [loader canLoadImageURL:requestURL]) { + return YES; + } + } + + return NO; } - (id)sendRequest:(NSURLRequest *)request withDelegate:(id)delegate diff --git a/Libraries/Image/RCTImageShadowView.h b/Libraries/Image/RCTImageShadowView.h index 168f0f4c1de86d..f79281e731ad99 100644 --- a/Libraries/Image/RCTImageShadowView.h +++ b/Libraries/Image/RCTImageShadowView.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. diff --git a/Libraries/Image/RCTImageShadowView.m b/Libraries/Image/RCTImageShadowView.m index c9ba82e32188cc..9102dc1b3b0b73 100644 --- a/Libraries/Image/RCTImageShadowView.m +++ b/Libraries/Image/RCTImageShadowView.m @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. diff --git a/Libraries/Image/RCTImageStoreManager.h b/Libraries/Image/RCTImageStoreManager.h index f790ccd5dff984..5d37eed2caecc5 100644 --- a/Libraries/Image/RCTImageStoreManager.h +++ b/Libraries/Image/RCTImageStoreManager.h @@ -1,4 +1,4 @@ -// Copyright (c) 2004-present, Facebook, Inc. +// 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. diff --git a/Libraries/Image/RCTImageStoreManager.m b/Libraries/Image/RCTImageStoreManager.m index d74b7c596cf44e..1cecbf1c3fed76 100644 --- a/Libraries/Image/RCTImageStoreManager.m +++ b/Libraries/Image/RCTImageStoreManager.m @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. diff --git a/Libraries/Image/RCTImageUtils.h b/Libraries/Image/RCTImageUtils.h index 645e99ba4ee326..49091ac22f0206 100644 --- a/Libraries/Image/RCTImageUtils.h +++ b/Libraries/Image/RCTImageUtils.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013-present, Facebook, Inc. + * 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. diff --git a/Libraries/Image/RCTImageUtils.m b/Libraries/Image/RCTImageUtils.m index 14a3010206470a..4a5cd006dc6d3a 100644 --- a/Libraries/Image/RCTImageUtils.m +++ b/Libraries/Image/RCTImageUtils.m @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. diff --git a/Libraries/Image/RCTImageView.h b/Libraries/Image/RCTImageView.h index 9931c6715a8d7e..77129f8b815730 100644 --- a/Libraries/Image/RCTImageView.h +++ b/Libraries/Image/RCTImageView.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. diff --git a/Libraries/Image/RCTImageView.m b/Libraries/Image/RCTImageView.m index 54e33d23958c7f..bdd58abf7a5215 100644 --- a/Libraries/Image/RCTImageView.m +++ b/Libraries/Image/RCTImageView.m @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. diff --git a/Libraries/Image/RCTImageViewManager.h b/Libraries/Image/RCTImageViewManager.h index f718a70246ef41..9aef96cd72a957 100644 --- a/Libraries/Image/RCTImageViewManager.h +++ b/Libraries/Image/RCTImageViewManager.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. diff --git a/Libraries/Image/RCTImageViewManager.m b/Libraries/Image/RCTImageViewManager.m index be9a3619f0407f..65e6be858641eb 100644 --- a/Libraries/Image/RCTImageViewManager.m +++ b/Libraries/Image/RCTImageViewManager.m @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. @@ -84,4 +84,11 @@ - (RCTPlatformView *)view // TODO(macOS ISS#2323203) }]; } +RCT_EXPORT_METHOD(queryCache:(NSArray *)requests + resolve:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject) +{ + resolve([self.bridge.imageLoader getImageCacheStatus:requests]); +} + @end diff --git a/Libraries/Image/RCTLocalAssetImageLoader.h b/Libraries/Image/RCTLocalAssetImageLoader.h index 4cd79bd403c5a2..df3918ad548c1a 100644 --- a/Libraries/Image/RCTLocalAssetImageLoader.h +++ b/Libraries/Image/RCTLocalAssetImageLoader.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. diff --git a/Libraries/Image/RCTLocalAssetImageLoader.m b/Libraries/Image/RCTLocalAssetImageLoader.m index 091cd70e0eafef..68407f38064ab0 100644 --- a/Libraries/Image/RCTLocalAssetImageLoader.m +++ b/Libraries/Image/RCTLocalAssetImageLoader.m @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. diff --git a/Libraries/Image/RCTResizeMode.h b/Libraries/Image/RCTResizeMode.h index d6b57333338140..f175d958fa33e7 100644 --- a/Libraries/Image/RCTResizeMode.h +++ b/Libraries/Image/RCTResizeMode.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. diff --git a/Libraries/Image/RCTResizeMode.m b/Libraries/Image/RCTResizeMode.m index 1094b7ff96e8c9..34027f8e8a2ec0 100644 --- a/Libraries/Image/RCTResizeMode.m +++ b/Libraries/Image/RCTResizeMode.m @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. diff --git a/Libraries/Image/RelativeImageStub.js b/Libraries/Image/RelativeImageStub.js index dcdeb9b916ac45..f5592d18167102 100644 --- a/Libraries/Image/RelativeImageStub.js +++ b/Libraries/Image/RelativeImageStub.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. diff --git a/Libraries/Image/TextInlineImageNativeComponent.js b/Libraries/Image/TextInlineImageNativeComponent.js new file mode 100644 index 00000000000000..6cbe56362576f9 --- /dev/null +++ b/Libraries/Image/TextInlineImageNativeComponent.js @@ -0,0 +1,17 @@ +/** + * 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'; + +const requireNativeComponent = require('requireNativeComponent'); + +const TextInlineImage = requireNativeComponent('RCTTextInlineImage'); + +module.exports = TextInlineImage; diff --git a/Libraries/Image/__tests__/assetRelativePathInSnapshot.js b/Libraries/Image/__tests__/assetRelativePathInSnapshot.js index 973d7171c0cd56..13cb6ac075f81e 100644 --- a/Libraries/Image/__tests__/assetRelativePathInSnapshot.js +++ b/Libraries/Image/__tests__/assetRelativePathInSnapshot.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2017-present, Facebook, Inc. + * 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. diff --git a/Libraries/Image/__tests__/resolveAssetSource-test.js b/Libraries/Image/__tests__/resolveAssetSource-test.js index c22f32a6520413..fb297899f6655a 100644 --- a/Libraries/Image/__tests__/resolveAssetSource-test.js +++ b/Libraries/Image/__tests__/resolveAssetSource-test.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. diff --git a/Libraries/Image/nativeImageSource.js b/Libraries/Image/nativeImageSource.js index d703aedb3a837d..33bc5de87bcd9b 100644 --- a/Libraries/Image/nativeImageSource.js +++ b/Libraries/Image/nativeImageSource.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. diff --git a/Libraries/Image/resolveAssetSource.js b/Libraries/Image/resolveAssetSource.js index 9c811e574400b1..ebd19e3354fe6e 100644 --- a/Libraries/Image/resolveAssetSource.js +++ b/Libraries/Image/resolveAssetSource.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. diff --git a/Libraries/Inspector/BorderBox.js b/Libraries/Inspector/BorderBox.js index 2110953dd36029..93d0dd158e14d1 100644 --- a/Libraries/Inspector/BorderBox.js +++ b/Libraries/Inspector/BorderBox.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. diff --git a/Libraries/Inspector/BoxInspector.js b/Libraries/Inspector/BoxInspector.js index f2b5e44df433b9..6097402a91c0c2 100644 --- a/Libraries/Inspector/BoxInspector.js +++ b/Libraries/Inspector/BoxInspector.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. @@ -87,12 +87,6 @@ const styles = StyleSheet.create({ textAlign: 'left', top: -3, }, - buffer: { - fontSize: 10, - color: 'yellow', - flex: 1, - textAlign: 'center', - }, innerText: { color: 'yellow', fontSize: 12, diff --git a/Libraries/Inspector/ElementBox.js b/Libraries/Inspector/ElementBox.js index ee7ccdf3259b8f..d360485bcbe5f5 100644 --- a/Libraries/Inspector/ElementBox.js +++ b/Libraries/Inspector/ElementBox.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. diff --git a/Libraries/Inspector/ElementProperties.js b/Libraries/Inspector/ElementProperties.js index 1e360944716fd2..9b6c222ed5babd 100644 --- a/Libraries/Inspector/ElementProperties.js +++ b/Libraries/Inspector/ElementProperties.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. @@ -11,7 +11,6 @@ 'use strict'; const BoxInspector = require('BoxInspector'); -const PropTypes = require('prop-types'); const React = require('React'); const StyleInspector = require('StyleInspector'); const StyleSheet = require('StyleSheet'); @@ -24,32 +23,23 @@ const flattenStyle = require('flattenStyle'); const mapWithSeparator = require('mapWithSeparator'); const openFileInEditor = require('openFileInEditor'); -import type {DangerouslyImpreciseStyleProp} from 'StyleSheet'; +import type {ViewStyleProp} from 'StyleSheet'; -class ElementProperties extends React.Component<{ - hierarchy: Array<$FlowFixMe>, - style?: DangerouslyImpreciseStyleProp, - source?: { +type Props = $ReadOnly<{| + hierarchy: Array<{|name: string|}>, + style?: ?ViewStyleProp, + source?: ?{ fileName?: string, lineNumber?: number, }, -}> { - static propTypes = { - hierarchy: PropTypes.array.isRequired, - style: PropTypes.oneOfType([ - PropTypes.object, - PropTypes.array, - PropTypes.number, - ]), - source: PropTypes.shape({ - fileName: PropTypes.string, - lineNumber: PropTypes.number, - }), - }; + frame?: ?Object, + selection?: ?number, + setSelection?: number => mixed, +|}>; +class ElementProperties extends React.Component { render() { const style = flattenStyle(this.props.style); - // $FlowFixMe found when converting React.createClass to ES6 const selection = this.props.selection; let openFileButton; const source = this.props.source; @@ -96,10 +86,7 @@ class ElementProperties extends React.Component<{ {openFileButton} - { - // $FlowFixMe found when converting React.createClass to ES6 - - } + {} diff --git a/Libraries/Inspector/Inspector.js b/Libraries/Inspector/Inspector.js index a5ab122b0cde5b..86d519258b62ed 100644 --- a/Libraries/Inspector/Inspector.js +++ b/Libraries/Inspector/Inspector.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. @@ -21,10 +21,6 @@ const Touchable = require('Touchable'); const UIManager = require('UIManager'); const View = require('View'); -/* $FlowFixMe(>=0.54.0 site=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. */ -const emptyObject = require('fbjs/lib/emptyObject'); const invariant = require('fbjs/lib/invariant'); export type ReactRenderer = { @@ -131,7 +127,7 @@ class Inspector extends React.Component< hierarchy: [], inspected: { frame: {left, top, width, height}, - style: props ? props.style : emptyObject, + style: props ? props.style : {}, }, }); }); diff --git a/Libraries/Inspector/InspectorOverlay.js b/Libraries/Inspector/InspectorOverlay.js index 4de9cb2ab8183e..79e2156111c1e2 100644 --- a/Libraries/Inspector/InspectorOverlay.js +++ b/Libraries/Inspector/InspectorOverlay.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. @@ -12,33 +12,29 @@ const Dimensions = require('Dimensions'); const ElementBox = require('ElementBox'); -const PropTypes = require('prop-types'); const React = require('React'); const StyleSheet = require('StyleSheet'); const UIManager = require('UIManager'); const View = require('View'); +import type {ViewStyleProp} from 'StyleSheet'; + type EventLike = { nativeEvent: Object, }; -class InspectorOverlay extends React.Component<{ - inspected?: { - frame?: Object, - style?: any, - }, - inspectedViewTag?: number, - onTouchViewTag: (tag: number, frame: Object, pointerY: number) => void, -}> { - static propTypes = { - inspected: PropTypes.shape({ - frame: PropTypes.object, - style: PropTypes.any, - }), - inspectedViewTag: PropTypes.number, - onTouchViewTag: PropTypes.func.isRequired, - }; +type Inspected = $ReadOnly<{| + frame?: Object, + style?: ViewStyleProp, +|}>; + +type Props = $ReadOnly<{| + inspected?: Inspected, + inspectedViewTag?: ?number, + onTouchViewTag: (tag: number, frame: Object, pointerY: number) => mixed, +|}>; +class InspectorOverlay extends React.Component { findViewForTouchEvent = (e: EventLike) => { const {locationX, locationY} = e.nativeEvent.touches[0]; UIManager.findSubviewIn( diff --git a/Libraries/Inspector/InspectorPanel.js b/Libraries/Inspector/InspectorPanel.js index d1b6d0eaf003bf..42c191d7ed530c 100644 --- a/Libraries/Inspector/InspectorPanel.js +++ b/Libraries/Inspector/InspectorPanel.js @@ -1,5 +1,5 @@ /** - * Copyright (c) 2015-present, Facebook, Inc. + * 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. @@ -14,14 +14,43 @@ const ElementProperties = require('ElementProperties'); const NetworkOverlay = require('NetworkOverlay'); const PerformanceOverlay = require('PerformanceOverlay'); const React = require('React'); -const PropTypes = require('prop-types'); const ScrollView = require('ScrollView'); const StyleSheet = require('StyleSheet'); const Text = require('Text'); const TouchableHighlight = require('TouchableHighlight'); const View = require('View'); -class InspectorPanel extends React.Component<$FlowFixMeProps> { +import type {ViewStyleProp} from 'StyleSheet'; + +type Props = $ReadOnly<{| + devtoolsIsOpen: boolean, + inspecting: boolean, + setInspecting: (val: boolean) => void, + perfing: boolean, + setPerfing: (val: boolean) => void, + touchTargeting: boolean, + setTouchTargeting: (val: boolean) => void, + networking: boolean, + setNetworking: (val: boolean) => void, + hierarchy?: ?Array<{|name: string|}>, + selection?: ?number, + setSelection: number => mixed, + inspected?: ?$ReadOnly<{| + style?: ?ViewStyleProp, + frame?: ?$ReadOnly<{| + top?: ?number, + left?: ?number, + width?: ?number, + height: ?number, + |}>, + source?: ?{| + fileName?: string, + lineNumber?: number, + |}, + |}>, +|}>; + +class InspectorPanel extends React.Component { renderWaiting() { if (this.props.inspecting) { return ( @@ -40,6 +69,7 @@ class InspectorPanel extends React.Component<$FlowFixMeProps> { style={this.props.inspected.style} frame={this.props.inspected.frame} source={this.props.inspected.source} + // $FlowFixMe: Hierarchy should be non-nullable hierarchy={this.props.hierarchy} selection={this.props.selection} setSelection={this.props.setSelection} @@ -57,22 +87,22 @@ class InspectorPanel extends React.Component<$FlowFixMeProps> { {!this.props.devtoolsIsOpen && contents} -