Compare commits

...
Author SHA1 Message Date
Mike Grabowski 78f3de0abc [0.56.1] Bump version numbers 2018-09-10 11:49:48 +02:00
Janic DuplessisandMike Grabowski 634c366984 Fix currentlyFocusedField by Removing this usage in TextInputState (#19834)
Summary:
I broke `currentlyFocusedField` when adding it back in ce3b7b8204 because `this` no longer refers to the proper object because it is assigned here https://github.com/facebook/react-native/commit/ce3b7b8204dad0fd62a76a0ce66472eca4b25bc8#diff-b48972356bc8dca4a00747d002fc3dd5R330. This code was pretty prone to breaking so I simply removed the `this` usage and rely on a top level variable instead. Also moved everything to named functions.
Pull Request resolved: https://github.com/facebook/react-native/pull/19834

Differential Revision: D8943088

Pulled By: hramos

fbshipit-source-id: 24d1470f6117138a5978fb7e467147847a9f3658
2018-09-10 11:49:40 +02:00
Mike Grabowski 3c6a916536 [0.56.0] Bump version numbers 2018-07-04 16:51:44 +02:00
Hector Ramos 93379b696b [0.56.0-rc.5] Bump version numbers 2018-07-03 17:26:24 -07:00
Sam GoldmanandHector Ramos 48341c8bb0 Deploy Flow v0.75.0 to fbsource
Summary:
bypass-lint
allow-large-files

Reviewed By: gabelevi

Differential Revision: D8579147

fbshipit-source-id: 12280dd4872551247ff9baafab3d766d3d7a544a
2018-07-03 17:26:08 -07:00
Hector Ramos ba9d41d645 Revert "[0.56.0-rc.5] Bump version numbers"
This reverts commit 30476703a8.
2018-07-03 17:24:51 -07:00
Hector Ramos 30476703a8 [0.56.0-rc.5] Bump version numbers 2018-07-03 17:14:07 -07:00
Rubén NorteandHector Ramos 600747ffd1 Hotfix to include react-native-windows in hasteImpl accepted paths (#20007)
Summary:
Closes https://github.com/facebook/react-native/pull/20007

We removed support for providesModule annotations and maintained support for Haste names in installed modules via `providesModuleNodeModules`, but our default `hasteImpl` doesn't take them into account. We need to find a better way to override core components from plugins but meanwhile this adds an exception for react-native-windows in the default `hasteImpl` to unblock their upgrade to the latest RC.

Fixes https://github.com/facebook/metro/issues/188

Reviewed By: mjesun

Differential Revision: D8695207

fbshipit-source-id: 2ad6cb1e93e600880a148776ac45f6ebd7d205d3
2018-07-03 17:13:39 -07:00
Michał MokijewskiandHector Ramos 3861dbef5b fix undefined_arch error in Xcode 10 beta (#19841)
Summary:
Fixes #19774

I spotted that in  Xcode 10 beta `CURRENT_ARCH` is set to string `undefined_arch`.  This PR will add fallback based on platform name (simulators are `x86_64` and everything since iPhone 5s is `arm64`).
Closes https://github.com/facebook/react-native/pull/19841

Differential Revision: D8619897

Pulled By: hramos

fbshipit-source-id: ed2ebaca105c6dcb40099f1a4aebe34d0660130c
2018-07-03 17:13:33 -07:00
mmacdougallandHector Ramos ca515e99a3 - Correct fishhook import in RCTReconnectingWebSocket Fixes #16039 (#16271)
Summary:
RCTReconnectingWebSocket is not compiling correctly because of an incorrect import (https://github.com/facebook/react-native/issues/16039).

Everything build and run as usual.

[IOS] [BUGFIX] [Fishhook] - Correct fishhook import in RCTReconnectingWebSocket Fixes #16039
Closes https://github.com/facebook/react-native/pull/16271

Differential Revision: D8679758

Pulled By: hramos

fbshipit-source-id: b05dda3a01a68ace87f11889b84ce6b323e5c16a
2018-07-03 17:13:25 -07:00
Shane OsbourneandHector Ramos 537731f8a5 fix: account for ListHeaderComponent length when calculating offset… (#17415)
Summary:
… in VirtualizedList - fixes #16612

Issue is detailed in #16612

<!--
Thank you for sending the PR! We appreciate you spending the time to work on these changes.

Help us understand your motivation by explaining why you decided to make this change.

You can learn more about contributing to React Native here: http://facebook.github.io/react-native/docs/contributing.html

Happy contributing!

-->

I need `onViewableItemsChanged` to account for the length of any ListHeaderComponents

I couldn't find any tests that currently cover the use-case of a VirtualizedList + ListComponent + scroll with onViewableItemsChanged, so I have not added any tests - all previous tests pass however.

<!--
Help reviewers and the release process by writing your own release notes

**INTERNAL and MINOR tagged notes will not be included in the next version's final release notes.**

  CATEGORY
[----------]        TYPE
[ CLI      ]   [-------------]      LOCATION
[ DOCS     ]   [ BREAKING    ]   [-------------]
[ GENERAL  ]   [ BUGFIX      ]   [-{Component}-]
[ INTERNAL ]   [ ENHANCEMENT ]   [ {File}      ]
[ IOS      ]   [ FEATURE     ]   [ {Directory} ]   |-----------|
[ ANDROID  ]   [ MINOR       ]   [ {Framework} ] - | {Message} |
[----------]   [-------------]   [-------------]   |-----------|

[CATEGORY] [TYPE] [LOCATION] - MESSAGE

 EXAMPLES:

 [IOS] [BREAKING] [FlatList] - Change a thing that breaks other things
 [ANDROID] [BUGFIX] [TextInput] - Did a thing to TextInput
 [CLI] [FEATURE] [local-cli/info/info.js] - CLI easier to do things with
 [DOCS] [BUGFIX] [GettingStarted.md] - Accidentally a thing/word
 [GENERAL] [ENHANCEMENT] [Yoga] - Added new yoga thing/position
 [INTERNAL] [FEATURE] [./scripts] - Added thing to script that nobody will see
-->

[GENERAL][BUGFIX][VirtualizedList] - account for `ListHeaderComponent` length
Closes https://github.com/facebook/react-native/pull/17415

Differential Revision: D8683555

Pulled By: hramos

fbshipit-source-id: 05df7b79c16e3c07c12468e782f3c4b0bdce7403
2018-07-03 17:13:20 -07:00
DulmandakhandHector Ramos 5ae80f91fb gradle to set project-wide properties (#19845)
Summary:
Change HelloWorld app template to use project-wide properties. See https://developer.android.com/studio/build/gradle-tips#configure-project-wide-properties.

RN community and third-party native module developers adopted this, so it'll make RN package development and usage easy.

CI is green https://circleci.com/gh/dulmandakh/react-native/507
Closes https://github.com/facebook/react-native/pull/19845

Differential Revision: D8675341

Pulled By: hramos

fbshipit-source-id: 4ed06cd7ef7ae70f153d7f335ef8a9d1371f6ce0
2018-07-03 17:13:06 -07:00
Greg PriceandHector Ramos 1b4187fc41 Fix extreme TextInput slowness on Android (#19645)
Summary:
This reverts 5898817fc "Implement letterSpacing on Android >= 5.0".
Testing shows that that commit is the cause of #19126, where in a
controlled TextInput after some text is first added, then deleted,
further interaction with the TextInput becomes extremely slow.

Fixes #19126.

Tried the repro case from #19126 without this change, then with it.
The issue reproduces, then doesn't.
Closes https://github.com/facebook/react-native/pull/19645

Differential Revision: D8675230

Pulled By: hramos

fbshipit-source-id: e2c2d352ee781898721b2dff4738572d1a6b7471
2018-07-03 17:13:00 -07:00
DulmandakhandHector Ramos 8bd43449f0 bump glog to 0.3.5 (#19890)
Summary:
bump glog to 0.3.5.

Version 0.3.4 added support for libc++ or clang. Starting with revision 11, Android NDK recommends and defaults to clang, so it'll add support for it.

notable changes in 0.3.4 and 0.3.5:
* add libc++ support
* reduce dynamic allocation from 3 to 1 per log message
* style fix for C++11
* Add CMake support
Closes https://github.com/facebook/react-native/pull/19890

Differential Revision: D8662179

Pulled By: hramos

fbshipit-source-id: ae2554d36e5b922e8649fc2ac7afc273a34cc127
2018-07-03 17:12:53 -07:00
Tim WangandHector Ramos 8aaf73b4b0 Upgrade Jest to version 23.2.0 (#19876)
Summary:
@public

[Jest 23.2.0](https://github.com/facebook/jest/blob/master/CHANGELOG.md#2320) landed fix for `MockNativeMethods` access in react-native jest preset.

[GENERAL] [BUGFIX] [./package.json] - Upgrade Jest to version 23.2.0 and resolve `MockNativeMethods` access in `react-native` jest preset.

Closes https://github.com/facebook/react-native/pull/19876

Reviewed By: mjesun

Differential Revision: D8618905

Pulled By: hramos

fbshipit-source-id: 8463868b1e5dbcf430c76c0551e58d38e4c85a04
2018-07-03 17:12:44 -07:00
DouglasandHector Ramos af76473c2e Suppress spurious warning about RCTCxxModule (#19880)
Summary:
<!--
  Required: Write your motivation here.
  If this PR fixes an issue, type "Fixes #issueNumber" to automatically close the issue when the PR is merged.
-->

On a relatively stock / default setup of RN on iOS you'll see the warning "Class RCTCxxModule was not exported. Did you forget to use RCT_EXPORT_MODULE()?" pop up on every launch. This change resolves that issue.

Fixes #14806 .

This supersedes PR #19794 .

Try a fresh project by following the RN iOS tutorial, and observe that there are no more warnings after making this change.

[IOS] [MINOR] [CxxBridge] - Fix "Class RCTCxxModule was not exported"
Closes https://github.com/facebook/react-native/pull/19880

Differential Revision: D8653809

Pulled By: hramos

fbshipit-source-id: c48529c2d74ddd40a90bc0e06e405078e25b72e3
2018-07-03 17:11:25 -07:00
Michał MokijewskiandHector Ramos 302699a472 Make run-ios command play nicely with multiple Xcode versions (#19781)
Summary:
I started using Xcode 10 beta and spotted that even though react-native cli is using cli tools from Xcode 10 for building it tries to open simulator from Xcode 9.4. Turned out that path to simulator app is hardcoded and doesn’t care about active developer directory.

1. You have to have more than one Xcode version (ie. 9.4 and 10 beta).
2. Change active developer directory to Xcode beta (`xcode-select -s /Applications/Xcode-beta.app/Contents/Developer`).
3. Without fix `react-native run-ios` will open simulator from Xcode 9.4, with fix it'll open simulator from active developer directory.

[CLI][IOS] [BUGFIX] [./local-cli] - use simulator from active developer directory
Closes https://github.com/facebook/react-native/pull/19781

Differential Revision: D8475915

Pulled By: TheSavior

fbshipit-source-id: d607f1f9eb9e565d4a017c21de50b5e569d171f9
2018-07-03 17:11:19 -07:00
DulmandakhandHector Ramos 8ea8dd6d48 deprecate ReactFragmentActivity (#19741)
Summary:
Android Support Library page says https://developer.android.com/topic/libraries/support-library/
> Caution: Starting with Support Library release 26.0.0 (July 2017), the minimum supported API level across most support libraries has increased to Android 4.0 (API level 14) for most library packages. For more information, see Version Support and Package Names in this document.

_android.support.v4.app.FragmentActivity_ is used to support **Fragment**s on Android API versions below 11. Now, we support only API version 14 and above, it's ok to remove _ReactFragmentActivity_ that extends _FragmentActivity_.

Once ReactFragmentActivity removed, we can remove some codes that use _android.support.v4_ to work support _ReactFragmentActivity_ on **unsupported** Android versions.

CI is failing for unknown reasons: https://circleci.com/gh/dulmandakh/react-native/278
> Received 'killed' signal

Everything will build and work just fine, except showing _ ReactFragmentActivity_ as deprecated
Closes https://github.com/facebook/react-native/pull/19741

Differential Revision: D8454968

Pulled By: hramos

fbshipit-source-id: e5f901438ef764163af013fe854904a28c73070a
2018-07-03 17:11:09 -07:00
Mike Grabowski b4b0610167 [0.56.0-rc.4] Bump version numbers 2018-06-27 18:25:44 +02:00
Jens PanneelandMike Grabowski 5b7a817723 Feature/add decimal pad to android (#19714)
Summary:
For a current use-case we need the a keyboard with characters 0-9 and a decimal point (or comma depending on language settings)

This exists on iOS as UIKeyboardType "decimalPad" and this is what react-native maps to for both "numeric" and "decimal-pad". This also exists on Android as inputType "numberDecimal", but is currently not accessible through react-native.

This PR maps the value "decimal-pad" of the keyboardType property of TextInput to the Android inputType "numberDecimal", effectively making "decimal-pad" cross platform without breaking anything.

* https://facebook.github.io/react-native/docs/textinput.html#keyboardtype
* https://developer.apple.com/documentation/uikit/uikeyboardtype
* https://developer.android.com/reference/android/widget/TextView#attr_android:inputType

There is this bug in some Samsung keyboards where both the - sign and decimal sign disappear when the keyboardType is set to "number" and both the "signed" and "decimal" flags are set. (Like is the case when using the react-native keyboardType prop "numeric".) https://androidforums.com/threads/numeric-soft-keyboard-missing-minus-sign-in-android-8-0-samsung-a5.1272628/

For developers that need decimal numbers but not negative ones, using "decimal-pad" will provide a workaround. I reproduced this on a Samsung A5 only, but maybe other phones have this exact issue. https://github.com/facebook/react-native/issues/12988 https://github.com/facebook/react-native/issues/12977 https://github.com/facebook/react-native/issues/17473 https://github.com/facebook/react-native/issues/17474

* Added testcase consistent with existing keyboardType tests
* Also added testcase for the related, but missing number-pad

This PR follows the same approach as the recently merged PR introducing "number-pad" https://github.com/facebook/react-native/pull/18350/commits/b638847a46491bd75e7ce7928c73f7cb78399195

Documentation PR: https://github.com/facebook/react-native-website/pull/405

 [ANDROID] [ENHANCEMENT] [TextInput] - Added "decimal-pad" keyboard type
Closes https://github.com/facebook/react-native/pull/19714

Differential Revision: D8429185

Pulled By: mdvacca

fbshipit-source-id: 6b56da2088f2be427ebffa04c4e17c91ffb9f7d9
2018-06-27 18:25:24 +02:00
Kevin GozaliandMike Grabowski b348aa14d4 iOS: Avoid double reload event when reloading JS
Summary:
@public
The bridge may send the reload event twice when reloading JS in some rare condition. The 2nd one was actually when the "new" bridge wasn't valid yet, so log an error if that happens. This may happen if the connection to Metro server gets into a weird state. Restarting Metro would solve the problem.

The issue was that `RCTBridgeWillReloadNotification` fired twice for each reload with metro connected.

Reviewed By: mmmulani

Differential Revision: D8509448

fbshipit-source-id: 647fb98c0a97503409a10451b8f152145947ae20
2018-06-27 18:24:23 +02:00
DulmandakhandMike Grabowski 5ae9799041 bump NDK APP_PLATFORM to android-16 (#19830)
Summary:
This PR will bump NDK APP_PLATFORM to android-16. Below is the excerpt from NDK documentation

> This variable contains the minimum Android platform version you want to support. For example, a value of android-15 specifies that your library uses APIs that are not available below Android 4.0.3 (API level 15) and can't be used on devices running a lower platform version. For a complete list of platform names and corresponding Android system images, see Android NDK Native APIs.
Closes https://github.com/facebook/react-native/pull/19830

Differential Revision: D8620017

Pulled By: hramos

fbshipit-source-id: 0b5578f130938e3ddae03fb855784193183243cf
2018-06-27 18:23:46 +02:00
DulmandakhandMike Grabowski c159447447 bump build tools to 26.0.3 (#19831)
Summary:
This will bump android build tools to 26.0.3, and will remove warning about newer version of build tools in Android Studio, thus improve developer experience.
Closes https://github.com/facebook/react-native/pull/19831

Differential Revision: D8620094

Pulled By: hramos

fbshipit-source-id: fa1c6739bb7556736c1b323acea88fe87e82f4d7
2018-06-27 18:23:30 +02:00
Vojtech NovakandMike Grabowski 6d27bd182f fix permission requests on pre-M android (#19734)
Summary:
On pre-M devices, `PermissionsAndroid.request` currently returns a boolean, whereas on newer, it returns GRANTED, DENIED or other constants defined in `PermissionsModule.java`

given the example form the [docs](https://facebook.github.io/react-native/docs/permissionsandroid.html) which I guess many people use, this will lead to code that does not work before M (it will tell you that permissions are not given even if they are in the manifest).

I believe the author of [this](https://github.com/facebook/react-native/commit/51efaab1209a41254c90dcba596d49e3cbc2d925) forgot to change the resolved value in this one place but changed it in other places, eg [here](https://github.com/facebook/react-native/commit/51efaab1209a41254c90dcba596d49e3cbc2d925#diff-2a74096453bc8faa5d4a1599ad0ab33fL99).

The docs are written correctly:

> On devices before SDK version 23, the permissions are automatically granted if they appear in the manifest, so check and request should always be true.

but the code is not right because we'd need to check for `if (granted === PermissionsAndroid.RESULTS.GRANTED || granted === true) {`

Also, the behavior is done correctly in [requestMultiplePermissions](https://github.com/facebook/react-native/blob/26684cf3adf4094eb6c405d345a75bf8c7c0bf88/ReactAndroid/src/main/java/com/facebook/react/modules/permissions/PermissionsModule.java#L148) so returning a boolean is an inconsistency.

I tested this locally. The code is the same as on line [148](https://github.com/facebook/react-native/blob/26684cf3adf4094eb6c405d345a75bf8c7c0bf88/ReactAndroid/src/main/java/com/facebook/react/modules/permissions/PermissionsModule.java#L148) where it is done correctly.

[ANDROID] [BUGFIX] [PermissionAndroid] - return GRANTED / DENIED instead of true / false on pre-M android

<!--
  **INTERNAL and MINOR tagged notes will not be included in the next version's final release notes.**

    CATEGORY
  [----------]      TYPE
  [ CLI      ] [-------------]    LOCATION
  [ DOCS     ] [ BREAKING    ] [-------------]
  [ GENERAL  ] [ BUGFIX      ] [ {Component} ]
  [ INTERNAL ] [ ENHANCEMENT ] [ {Filename}  ]
  [ IOS      ] [ FEATURE     ] [ {Directory} ]   |-----------|
  [ ANDROID  ] [ MINOR       ] [ {Framework} ] - | {Message} |
  [----------] [-------------] [-------------]   |-----------|

 EXAMPLES:

 [IOS] [BREAKING] [FlatList] - Change a thing that breaks other things
 [ANDROID] [BUGFIX] [TextInput] - Did a thing to TextInput
 [CLI] [FEATURE] [local-cli/info/info.js] - CLI easier to do things with
 [DOCS] [BUGFIX] [GettingStarted.md] - Accidentally a thing/word
 [GENERAL] [ENHANCEMENT] [Yoga] - Added new yoga thing/position
 [INTERNAL] [FEATURE] [./scripts] - Added thing to script that nobody will see
-->
Closes https://github.com/facebook/react-native/pull/19734

Differential Revision: D8450402

Pulled By: hramos

fbshipit-source-id: 46b0b7f83f81d817d60234f155d43de7f57248c7
2018-06-27 18:18:38 +02:00
Hector Ramos ce739139f3 [0.56.0-rc.3] Bump version numbers 2018-06-22 09:39:25 -07:00
Hector Ramos 1980dd771a Remove pull request check
The publish script will fail on forked PRs anyway as the $CIRCLE_NPM_TOKEN envvar will be missing or incorrect.
2018-06-22 09:39:10 -07:00
Hector Ramos 3d946718c5 Revert "[0.56.0-rc.3] Bump version numbers"
This reverts commit 21d0eedd27.
2018-06-22 09:37:06 -07:00
Mike Grabowski 21d0eedd27 [0.56.0-rc.3] Bump version numbers 2018-06-21 18:19:16 +02:00
Tim YungandMike Grabowski 72d22e8828 React sync for revisions c0fe8d6...ae14317
Summary:
This sync includes the following changes:
- **[ae14317d6](https://github.com/facebook/react/commit/ae14317d6)**: Inline fbjs/lib/emptyFunction (#13054) //<Dan Abramov>//
- **[72434a768](https://github.com/facebook/react/commit/72434a768)**: Remove or inline some fbjs dependencies (#13046) //<Dan Abramov>//
- **[64c54edea](https://github.com/facebook/react/commit/64c54edea)**: Adding movementX and movementY to synthenticMouseEvent fixes #6723 (#9018) //<Jason Williams>//
- **[9bd4d1fae](https://github.com/facebook/react/commit/9bd4d1fae)**: Synchronously restart when an error is thrown during async rendering (#13041) //<Andrew Clark>//
- **[9bda7b28f](https://github.com/facebook/react/commit/9bda7b28f)**: Suspended high pri work forces lower priority work to expire early  (#12965) //<Andrew Clark>//
- **[2e7577907](https://github.com/facebook/react/commit/2e7577907)**: Fix incorrect data in compositionend event with Korean IME on IE11 (#10217) (#12563) //<Crux>//
- **[bc963f353](https://github.com/facebook/react/commit/bc963f353)**: setJSResponder in Fabric renderer (#13031) //<Sebastian Markbåge>//
- **[051637da6](https://github.com/facebook/react/commit/051637da6)**: Extract Fabric event handlers from canonical props (#13024) //<Sebastian Markbåge>//
- **[2a8085980](https://github.com/facebook/react/commit/2a8085980)**: Remove rAF fork (#12980) //<Flarnie Marchan>//
- **[e0c78344e](https://github.com/facebook/react/commit/e0c78344e)**: Retry on error if there's lower priority pending work (#12957) //<Andrew Clark>//
- **[9725065eb](https://github.com/facebook/react/commit/9725065eb)**: Update bundle sizes for 16.4.1 release //<Dan Abramov>//
- **[0b87b2790](https://github.com/facebook/react/commit/0b87b2790)**: Updating package versions for release 16.4.1 //<Dan Abramov>//
- **[036ae3c6e](https://github.com/facebook/react/commit/036ae3c6e)**: Use native event dispatching instead of Simulate or SimulateNative (#13023) //<Philipp Spieß>//
- **[945fc1bfc](https://github.com/facebook/react/commit/945fc1bfc)**: Call gDSFP with the right state in react-test-render (#13030) //<Rafał Ruciński>//
- **[392530104](https://github.com/facebook/react/commit/392530104)**: Remove feature flag around 'getDerivedStateFromProps' bug fix (#13022) //<Flarnie Marchan>//
- **[1594409fa](https://github.com/facebook/react/commit/1594409fa)**: Scheduler depends on common packages (#13020) //<Dan Abramov>//
- **[d5c11193e](https://github.com/facebook/react/commit/d5c11193e)**: Added production profiling bundle type (#12886) //<Brian Vaughn>//
- **[ec60457bc](https://github.com/facebook/react/commit/ec60457bc)**: Popping context is O(1) in SSR (#13019) //<Dan Abramov>//
- **[30bc8ef79](https://github.com/facebook/react/commit/30bc8ef79)**: Allow multiple root children in test renderer traversal API (#13017) //<Dan Abramov>//
- **[d480782c4](https://github.com/facebook/react/commit/d480782c4)**: Don’t error when returning an empty Fragment (#12966) //<Philipp Spieß>//
- **[4ac6f133a](https://github.com/facebook/react/commit/4ac6f133a)**: Fallback to event.srcElement for IE9 (#12976) //<Nathan Hunzaker>//
- **[23be4102d](https://github.com/facebook/react/commit/23be4102d)**: Fixed an issue with nested contexts unwinding when server rendering. Issue #12984 (#12985) //<Eric Soderberg>//
- **[d0d428064](https://github.com/facebook/react/commit/d0d428064)**: Remove old reference to inst._wrapperState (#12987) //<Nathan Hunzaker>//
- **[c78957eac](https://github.com/facebook/react/commit/c78957eac)**: Fix an SVG focusing crash in IE11 (#12996) //<Jifa Jiang>//
- **[bfb12ebb5](https://github.com/facebook/react/commit/bfb12ebb5)**: delete a couple of redundant lines in performWorkOnRoot() in ReactFiberScheduler.js (#13003) //<Nathan Quarles>//
- **[394b17eed](https://github.com/facebook/react/commit/394b17eed)**: Update custom renderer docs //<Dan Abramov>//
- **[188c4252a](https://github.com/facebook/react/commit/188c4252a)**: Fix react-dom ReferenceError requestAnimationFrame in non-browser env (#13000) (#13001) //<Ivan Babak>//
- **[9cf3733a9](https://github.com/facebook/react/commit/9cf3733a9)**: update comment in computeAsyncExpiration() to reflect code (#12994) //<Nathan Quarles>//
- **[c5a733e1e](https://github.com/facebook/react/commit/c5a733e1e)**: Fix links of docs on the comment (#12795) //<Ende93>//
- **[36546b513](https://github.com/facebook/react/commit/36546b513)**: Set the correct initial value on input range (#12939) //<Maxime Nory>//
- **[15767a8f8](https://github.com/facebook/react/commit/15767a8f8)**: [scheduler] 5/n Error handling in scheduler (#12920) //<Flarnie Marchan>//
- **[3118ed9d6](https://github.com/facebook/react/commit/3118ed9d6)**: Expose unstable_interactiveUpdates on ReactDOM (#12943) //<Andrew Clark>//
- **[524a74331](https://github.com/facebook/react/commit/524a74331)**: Fix for Flow issues in SimpleCacheProvider (#12942) //<Flarnie Marchan>//
- **[ae57b125c](https://github.com/facebook/react/commit/ae57b125c)**: [simple-cache-provider] Use LRU cache eviction (#12851) //<Andrew Clark>//
- **[e0a03c1b4](https://github.com/facebook/react/commit/e0a03c1b4)**: Extend input type check in selection capabilities (#12062) (#12135) //<Spyros Ioakeimidis>//
- **[79a740c6e](https://github.com/facebook/react/commit/79a740c6e)**: Rename variables to remove references to 'global' global (#12931) //<Flarnie Marchan>//
- **[ff724d3c2](https://github.com/facebook/react/commit/ff724d3c2)**: [scheduler] 4/n Allow splitting out `schedule` in fb-www, prepare to fix polyfill issue internally (#12900) //<Flarnie Marchan>//
- **[83f76e4db](https://github.com/facebook/react/commit/83f76e4db)**: ForwardRefs supports propTypes (#12911) //<Brian Vaughn>//
- **[8aeea5afa](https://github.com/facebook/react/commit/8aeea5afa)**: Do not assign node.value on input creation if no change will occur (#12925) //<Nathan Hunzaker>//
- **[aa85b0fd5](https://github.com/facebook/react/commit/aa85b0fd5)**: Upgrade to Jest 23 (#12894) //<Simen Bekkhus>//
- **[61777a78f](https://github.com/facebook/react/commit/61777a78f)**: [scheduler] 3/n Use a linked list instead of map and queue for callback storage (#12893) //<Flarnie Marchan>//
- **[e7bd3d59a](https://github.com/facebook/react/commit/e7bd3d59a)**: No longer expose ReactNativeComponentTree (#12904) //<Sebastian Markbåge>//
- **[f35d989be](https://github.com/facebook/react/commit/f35d989be)**: TestRenderer warns if flushThrough is passed the wrong params (#12909) //<Brian Vaughn>//
- **[557870067](https://github.com/facebook/react/commit/557870067)**: Record "actual" times for all Fibers within a Profiler tree (alt) (#12910) //<Brian Vaughn>//
- **[76e07071a](https://github.com/facebook/react/commit/76e07071a)**: [scheduler] 2/n Adding 'schedule' fixture (#12884) //<Flarnie Marchan>//
- **[345e0a71a](https://github.com/facebook/react/commit/345e0a71a)**: Improve tests for 'schedule' module (#12880) //<Flarnie Marchan>//
- **[8765d6089](https://github.com/facebook/react/commit/8765d6089)**: Update bundle sizes for 16.4.0 release //<Andrew Clark>//
- **[d427a563d](https://github.com/facebook/react/commit/d427a563d)**: Updating package versions for release 16.4.0 //<Andrew Clark>//
- **[53852a887](https://github.com/facebook/react/commit/53852a887)**: add functional components warning about legacy context api (#12892) //<Chang Yan>//
- **[fe747a51c](https://github.com/facebook/react/commit/fe747a51c)**: Add React.Timeout to getComponentName (#12890) //<Toru Kobayashi>//
- **[c601f7a64](https://github.com/facebook/react/commit/c601f7a64)**: add siblings Timeout components test case (#12862) //<Chang Yan>//
- **[735035837](https://github.com/facebook/react/commit/735035837)**: add legacy context API warning in strict mode (#12849) //<Chang Yan>//
- **[e88579184](https://github.com/facebook/react/commit/e88579184)**: Fix a regression that caused us to listen to extra events at the top (#12878) //<Dan Abramov>//
- **[7c0aca289](https://github.com/facebook/react/commit/7c0aca289)**: Rollup freeze: false (#12879) //<Brian Vaughn>//
- **[33289b530](https://github.com/facebook/react/commit/33289b530)**: Tests and fixes for 'timing out' behavior (#12858) //<Flarnie Marchan>//
- **[ad27845cc](https://github.com/facebook/react/commit/ad27845cc)**: Fix double-firing submit events (#12877) //<Sophie Alpert>//
- **[dd5fad296](https://github.com/facebook/react/commit/dd5fad296)**: Update Flow to 0.70 (#12875) //<Dan Abramov>//
- **[13003654e](https://github.com/facebook/react/commit/13003654e)**: Pass "start time" and "commit time" to Profiler callback (#12852) //<Brian Vaughn>//
- **[dc3b144f4](https://github.com/facebook/react/commit/dc3b144f4)**: Treat Rollup "warnings" as errors (#12868) //<Dan Abramov>//
- **[d7b9b4921](https://github.com/facebook/react/commit/d7b9b4921)**: Fix react native example links in README of 'react-reconciler' (#12871) //<Kevin (Kun) "Kassimo" Qian>//
- **[9bed4a6ae](https://github.com/facebook/react/commit/9bed4a6ae)**: https in reactProdInvariant text (#12869) //<Sophie Alpert>//
- **[47b003a82](https://github.com/facebook/react/commit/47b003a82)**: Resolve host configs at build time (#12792) //<Dan Abramov>//

Release Notes:
[GENERAL] [FEATURE] [React] - React sync for revisions c0fe8d6...ae14317

Reviewed By: bvaughn

Differential Revision: D8458731

fbshipit-source-id: afefaa50685d43e70c8ea85c70d2e29dee311cbb
2018-06-21 18:18:48 +02:00
Eli WhiteandHector Ramos 27a497dd5a Update react-native init's flowconfig
Summary:
Fixes https://github.com/facebook/react-native/issues/19766

On a clean project flow was complaining about `Cannot resolve module X` because of the removal of `providesModule`. This resolves the errors.

Reviewed By: rubennorte

Differential Revision: D8500303

fbshipit-source-id: 4e129ee4382f8ff36ab126e9f6c6530254cd382e
2018-06-18 17:47:15 -07:00
Hector Ramos d9d324073f [0.56.0-rc.2] Bump version numbers 2018-06-15 10:18:02 -07:00
Hector Ramos 053f580a1d Revert "[0.56.0-rc.2] Bump version numbers"
This reverts commit d91c9d97b8.
2018-06-15 10:17:38 -07:00
Hector Ramos 9ead7d6147 Fix config error in circle 2018-06-15 10:17:29 -07:00
Hector Ramos d91c9d97b8 [0.56.0-rc.2] Bump version numbers 2018-06-15 10:15:41 -07:00
Hector Ramos 93b722f2a0 Only deploy releases on stable branches 2018-06-15 10:13:47 -07:00
Hector Ramos 9821241b79 Revert "[0.56.0-rc.2] Bump version numbers"
This reverts commit 541c6e9783.
2018-06-15 10:12:55 -07:00
Hector Ramos 541c6e9783 [0.56.0-rc.2] Bump version numbers 2018-06-15 10:11:38 -07:00
Hector Ramos cf71637a65 Revert "[0.56.0-rc.2] Bump version numbers"
This reverts commit 55eef9b58f.
2018-06-15 10:11:25 -07:00
hamaronandHector Ramos 3fc653e140 iOS: Fixed the bug where a Backspace event was emitted when entering characters after clearing a text in TextInput by an empty string (#18627)
Summary:
The bug #18374 was caused by the loose condition to execute `stringByReplacingCharactersInRange` in the method `textInputShouldChangeTextInRange` . As a result, `findMismatch` wrongly returning `true` which ends up the Backspace event being fired in another `textInputShouldChangeTextInRange` call in `textInputDidChange`.

<!--
  Required: Write your motivation here.
  If this PR fixes an issue, type "Fixes #issueNumber" to automatically close the issue when the PR is merged.
-->

1. Pass all the tests by `yarn run test`
2. Run the following code and type any text. (This code is brought from #18374. Thank you michalpetrov!!) And then verify that 'Backspace' events are not emitted after clearing text
and entering any letters.

```javascript
type Props = {};
type State = {
  text: string,
  keys: string
};
export default class App extends Component<Props, State> {
  state = {text: '', keys: ''}
  render() {
    return (
      <View style={styles.container}>
        <TextInput style={styles.textInput} value={this.state.text} onChangeText={this.onChangeText} onKeyPress={this.onKeyPress}/>
        <Button title="Clear" onPress={this.onClear}/>
        <Text>Text: {this.state.text}</Text>
        <Text>Keys: {this.state.keys}</Text>
      </View>
    );
  }

  onChangeText = (text: string) => {
    this.setState({text})
  }

  onKeyPress = ({ nativeEvent }: Object) => {
    this.setState({keys: this.state.keys + nativeEvent.key + ', '})
  }

  onClear = () => {
    this.setState({text: '', keys: ''})
  }
}
```

<!--
  Does this PR require a documentation change?
  Create a PR at https://github.com/facebook/react-native-website and add a link to it here.
-->

<!--
  Required.
  Help reviewers and the release process by writing your own release notes. See below for an example.
-->

[IOS] [BUGFIX] [TextInput] - Fixed the bug where Backspace event was emitted when entering a character after clearing a text in TextInput by an empty string

<!--
  **INTERNAL and MINOR tagged notes will not be included in the next version's final release notes.**

    CATEGORY
  [----------]      TYPE
  [ CLI      ] [-------------]    LOCATION
  [ DOCS     ] [ BREAKING    ] [-------------]
  [ GENERAL  ] [ BUGFIX      ] [ {Component} ]
  [ INTERNAL ] [ ENHANCEMENT ] [ {Filename}  ]
  [ IOS      ] [ FEATURE     ] [ {Directory} ]   |-----------|
  [ ANDROID  ] [ MINOR       ] [ {Framework} ] - | {Message} |
  [----------] [-------------] [-------------]   |-----------|

 EXAMPLES:

 [IOS] [BREAKING] [FlatList] - Change a thing that breaks other things
 [ANDROID] [BUGFIX] [TextInput] - Did a thing to TextInput
 [CLI] [FEATURE] [local-cli/info/info.js] - CLI easier to do things with
 [DOCS] [BUGFIX] [GettingStarted.md] - Accidentally a thing/word
 [GENERAL] [ENHANCEMENT] [Yoga] - Added new yoga thing/position
 [INTERNAL] [FEATURE] [./scripts] - Added thing to script that nobody will see
-->
Closes https://github.com/facebook/react-native/pull/18627

Differential Revision: D8436331

Pulled By: hramos

fbshipit-source-id: ec75a6ca926061cbf7cb106db652f2b4a71c9a0c
2018-06-15 10:08:49 -07:00
Hector Ramos 997e173f24 Revert "Bump soloader to 0.5.0 (#19676)"
This reverts commit e3c5524bc6.
2018-06-15 07:05:38 -07:00
Hector Ramos 55eef9b58f [0.56.0-rc.2] Bump version numbers 2018-06-14 17:35:44 -07:00
DulmandakhandHector Ramos 2adcc9bc5d bump gradle-plugin@2.3.3, gradle@3.5.1, gradle-download-task@3.4.3 (#19697)
Summary:
bump gradle-plugin@2.3.3, gradle@3.5.1, gradle-download-task@3.4.3, as we landed build tools 26.0.2 with https://github.com/facebook/react-native/commit/065c5b6590de18281a8c592a04240751c655c03c

Will improve Android build performance.

Everything will work as normal, but build faster.

<!--
  Required.
  Help reviewers and the release process by writing your own release notes. See below for an example.
-->

[ANDROID] [ENHANCEMENT] [TOOLS] - bump gradle-plugin@2.3.3, gradle@3.5.1, gradle-download-task@3.4.3
Closes https://github.com/facebook/react-native/pull/19697

Differential Revision: D8433743

Pulled By: hramos

fbshipit-source-id: da72aeb314bed7f63807a0c69bebd24c633cc807
2018-06-14 17:16:02 -07:00
DulmandakhandHector Ramos 9b2d3092f9 add google maven repo in android project template (#19712)
Summary:
This PR will add Google maven repo to RN project template that contains com.android.support:appcompat-v7:26.1.0, thus fixes `react-native run-android` using version 0.56.0-rc.1

CI is Green - https://circleci.com/gh/dulmandakh/react-native/235

new Android projects will build and run just fine.
Closes https://github.com/facebook/react-native/pull/19712

Differential Revision: D8433730

Pulled By: hramos

fbshipit-source-id: b7d5a1cd5a97b1c4aad2a307158d6dbfcf9a42a5
2018-06-14 16:40:56 -07:00
Héctor Ramos 2645956953 Publish releases automatically, update docs (#19715)
Summary:
Now that tests are green, we can return to automatic publishing to npm based on git tags. As long as all tests are passing, deploying a new release of React Native is as easy as tagging a commit. I've updated `Releases.md` to reflect today's release process.

Future Work: Include information about updating the website, as this is no longer done automatically.
Closes https://github.com/facebook/react-native/pull/19715

Differential Revision: D8429834

Pulled By: hramos

fbshipit-source-id: 2c6f2c80ac43c4e6d20c01e06ba14a7e4b16180d
2018-06-14 15:31:44 -07:00
Eli WhiteandHector Ramos 2beaa39101 Support animated values for border dimensions
Summary:
The flow types for these were too restrictive.

Fixes https://github.com/facebook/react-native/issues/19093

Reviewed By: yungsters

Differential Revision: D8409550

fbshipit-source-id: e4774e8856efc998ff1fa6cdcbe7b0cb6db2c4e3
2018-06-14 15:28:49 -07:00
Tim YungandHector Ramos c1c32276bc YellowBox: Restore ES5 Compatibility
Reviewed By: sahrens

Differential Revision: D8421561

fbshipit-source-id: c2b8d430f4d0c9ce0d5177f0af5eb5f404916024
2018-06-14 13:13:22 -07:00
Tim YungandHector Ramos d047d2c227 YellowBox: Define in __DEV__ Only
Summary: This makes it so that `YellowBox` and its dependencies are completely stripped from production bundles.

Reviewed By: sahrens

Differential Revision: D8402545

fbshipit-source-id: 6993521280a02dfe5eab8863d12c46781f35444f
2018-06-14 13:12:34 -07:00
Hector Ramos e07bbbe24d [0.56.0-rc.1] Bump version numbers 2018-06-13 13:03:08 -07:00
DulmandakhandHector Ramos 579eb3f9fe use android build-tools 26.0.2 and set compileSdk to 26 (#19662)
Summary:
Android Target API Level 26 will be required starting from August 2018, it's so soon 😄.Read https://android-developers.googleblog.com/2017/12/improving-app-security-and-performance.html

This PR uses android build tools 26.0.2, support library 26.1.0 (with android lifecycle) and setting compileSdkVersion to 26, but leaving minSdkVersion and targetSdkVersion intact, which will make targeting 26 easy.

Circle CI: https://circleci.com/gh/dulmandakh/react-native/209

Everything will build and work just fine.

[ANDROID] [ENHANCEMENT] [TOOLS] - Use android build-tools 26.0.2 and set compileSdk to 26, and use support library version 26.1.0.
Closes https://github.com/facebook/react-native/pull/19662

Differential Revision: D8398855

Pulled By: hramos

fbshipit-source-id: a4066eb04cb5f947efe1f3202b638c1092b79aae
2018-06-13 12:46:58 -07:00
Héctor Ramos a59e19240a Bump soloader to 0.5.0 (#19676)
Summary:
Closes https://github.com/facebook/react-native/pull/19676

0.5.0 adds compatibility for Android P.

Reviewed By: mdvacca

Differential Revision: D8379610

fbshipit-source-id: cbef6c2e5e82e2d9e17756b00d210fecb04e8a40
2018-06-13 10:07:45 -07:00
Tim YungandHector Ramos 204207f4c9 YellowBox: Apply SafeAreaView in Header
Summary: Uses `SafeAreaView` in the YellowBox inspector header so that it does not collide with the status bar.

Reviewed By: sahrens

Differential Revision: D8374861

fbshipit-source-id: e67358ac9268db8291cacf79df402f3bd5a2173d
2018-06-13 10:03:08 -07:00
Tim YungandHector Ramos 8bdef5d2c0 RN: A wild YellowBox has appeared!
Summary:
Replaces the existing `YellowBox` with a modern one.

Here are the notable changes:

- Sort warnings by recency (with most recent on top).
- Group warnings by format string if present.
- Present stack traces similar to RedBox.
- Show status of loading source maps.
- Support inspecting each occurrence of a warning.
- Fixed a bunch of edge cases and race conditions.

Reviewed By: TheSavior

Differential Revision: D8345180

fbshipit-source-id: b9e10d526b262c3985bbea639ba2ea0e7cad5081
2018-06-13 10:00:16 -07:00
Tim YungandHector Ramos 71f56fc2e3 Jest: Upgrade Flow Definition in RN + Metro
Reviewed By: sahrens

Differential Revision: D8371076

fbshipit-source-id: 12d03c545ca190a5fda1ff319e5ea906173d2241
2018-06-13 09:58:43 -07:00
Hector Ramos d642e60291 [0.56.0-rc] Bump version numbers 2018-06-11 09:46:55 -07:00
80 changed files with 37276 additions and 25137 deletions
+2 -1
View File
@@ -1,12 +1,13 @@
[android]
target = Google Inc.:Google APIs:23
target = android-26
[download]
max_number_of_retries = 3
[maven_repositories]
central = https://repo1.maven.org/maven2
google = https://maven.google.com
[alias]
rntester = //RNTester/android/app:app
+20 -25
View File
@@ -456,18 +456,15 @@ jobs:
- restore-cache: *restore-cache-android-packages
- run: *install-android-packages
- save-cache: *save-cache-android-packages
# Install Android NDK
- run: *create-ndk-directory
- restore-cache: *restore-cache-ndk
- run: *install-ndk
- save-cache: *save-cache-ndk
# Fetch dependencies using BUCK
- restore-cache: *restore-cache-buck
- run: *install-buck
- save-cache: *save-cache-buck
- run: buck fetch ReactAndroid/src/test/java/com/facebook/react/modules
- run: buck fetch ReactAndroid/src/main/java/com/facebook/react
@@ -477,24 +474,18 @@ jobs:
- restore-cache: *restore-cache-gradle-downloads
- run: *gradle-download-deps
- save-cache: *save-cache-gradle-downloads
- restore-cache: *restore-yarn-cache
- run: *yarn
- save-cache: *save-yarn-cache
- run:
name: Publish React Native Package
command: |
if [ -z "$CIRCLE_PULL_REQUEST" ]; then
echo "//registry.npmjs.org/:_authToken=${CIRCLE_NPM_TOKEN}" > ~/.npmrc
git config --global user.email "reactjs-bot@users.noreply.github.com"
git config --global user.name "npm Deployment Script"
echo "machine github.com login reactjs-bot password $GITHUB_TOKEN" > ~/.netrc
node ./scripts/publish-npm.js
else
echo "Skipping deploy."
fi
echo "//registry.npmjs.org/:_authToken=${CIRCLE_NPM_TOKEN}" > ~/.npmrc
git config --global user.email "reactjs-bot@users.noreply.github.com"
git config --global user.name "npm Deployment Script"
echo "machine github.com login reactjs-bot password $GITHUB_TOKEN" > ~/.netrc
node ./scripts/publish-npm.js
# Set up an Android environment for downstream jobs
test_android:
@@ -652,6 +643,21 @@ workflows:
requires:
- checkout_code
# Only runs on vX.X.X tags if all tests are green
- publish_npm_package:
filters:
branches:
only:
- /.*-stable/
tags:
only: /v[0-9]+(\.[0-9]+)*(\-rc(\.[0-9]+)?)?/
requires:
- test_javascript
- test_ios
- test_tvos
- test_end_to_end
- analyze
# Only runs on PRs
analyze:
jobs:
@@ -665,17 +671,6 @@ workflows:
requires:
- checkout_code
# Only runs on NN-stable branches
deploy:
jobs:
# If we are on a stable branch, wait for approval to deploy to npm
- approve_publish_npm_package:
filters: *filter-only-stable
type: approval
- publish_npm_package:
requires:
- approve_publish_npm_package
# These tests are flaky or are yet to be fixed. They are placed on their own
# workflow to avoid marking benign PRs as broken.
+1 -1
View File
@@ -74,4 +74,4 @@ suppress_comment=\\(.\\|\n\\)*\\$FlowFixedInNextDeploy
suppress_comment=\\(.\\|\n\\)*\\$FlowExpectedError
[version]
^0.74.0
^0.75.0
+2 -2
View File
@@ -86,12 +86,12 @@ export type KeyboardType =
| 'numeric'
| 'phone-pad'
| 'number-pad'
| 'decimal-pad'
// iOS-only
| 'ascii-capable'
| 'numbers-and-punctuation'
| 'url'
| 'name-phone-pad'
| 'decimal-pad'
| 'twitter'
| 'web-search'
// Android-only
@@ -388,6 +388,7 @@ const TextInput = createReactClass({
* - `default`
* - `numeric`
* - `number-pad`
* - `decimal-pad`
* - `email-address`
* - `phone-pad`
*
@@ -399,7 +400,6 @@ const TextInput = createReactClass({
* - `numbers-and-punctuation`
* - `url`
* - `name-phone-pad`
* - `decimal-pad`
* - `twitter`
* - `web-search`
*
@@ -18,73 +18,74 @@
const Platform = require('Platform');
const UIManager = require('UIManager');
let currentlyFocusedID: ?number = null;
const inputs = new Set();
const TextInputState = {
/**
* Internal state
*/
_currentlyFocusedID: (null: ?number),
/**
* Returns the ID of the currently focused text field, if one exists
* If no text field is focused it returns null
*/
function currentlyFocusedField(): ?number {
return currentlyFocusedID;
}
/**
* Returns the ID of the currently focused text field, if one exists
* If no text field is focused it returns null
*/
currentlyFocusedField: function(): ?number {
return this._currentlyFocusedID;
},
/**
* @param {number} TextInputID id of the text field to focus
* Focuses the specified text field
* noop if the text field was already focused
*/
focusTextInput: function(textFieldID: ?number) {
if (this._currentlyFocusedID !== textFieldID && textFieldID !== null) {
this._currentlyFocusedID = textFieldID;
if (Platform.OS === 'ios') {
UIManager.focus(textFieldID);
} else if (Platform.OS === 'android') {
UIManager.dispatchViewManagerCommand(
textFieldID,
UIManager.AndroidTextInput.Commands.focusTextInput,
null,
);
}
/**
* @param {number} TextInputID id of the text field to focus
* Focuses the specified text field
* noop if the text field was already focused
*/
function focusTextInput(textFieldID: ?number) {
if (currentlyFocusedID !== textFieldID && textFieldID !== null) {
currentlyFocusedID = textFieldID;
if (Platform.OS === 'ios') {
UIManager.focus(textFieldID);
} else if (Platform.OS === 'android') {
UIManager.dispatchViewManagerCommand(
textFieldID,
UIManager.AndroidTextInput.Commands.focusTextInput,
null,
);
}
},
}
}
/**
* @param {number} textFieldID id of the text field to unfocus
* Unfocuses the specified text field
* noop if it wasn't focused
*/
blurTextInput: function(textFieldID: ?number) {
if (this._currentlyFocusedID === textFieldID && textFieldID !== null) {
this._currentlyFocusedID = null;
if (Platform.OS === 'ios') {
UIManager.blur(textFieldID);
} else if (Platform.OS === 'android') {
UIManager.dispatchViewManagerCommand(
textFieldID,
UIManager.AndroidTextInput.Commands.blurTextInput,
null,
);
}
/**
* @param {number} textFieldID id of the text field to unfocus
* Unfocuses the specified text field
* noop if it wasn't focused
*/
function blurTextInput(textFieldID: ?number) {
if (currentlyFocusedID === textFieldID && textFieldID !== null) {
currentlyFocusedID = null;
if (Platform.OS === 'ios') {
UIManager.blur(textFieldID);
} else if (Platform.OS === 'android') {
UIManager.dispatchViewManagerCommand(
textFieldID,
UIManager.AndroidTextInput.Commands.blurTextInput,
null,
);
}
},
}
}
registerInput: function(textFieldID: number) {
inputs.add(textFieldID);
},
function registerInput(textFieldID: number) {
inputs.add(textFieldID);
}
unregisterInput: function(textFieldID: number) {
inputs.delete(textFieldID);
},
function unregisterInput(textFieldID: number) {
inputs.delete(textFieldID);
}
isTextInput: function(textFieldID: number) {
return inputs.has(textFieldID);
},
function isTextInput(textFieldID: number) {
return inputs.has(textFieldID);
}
module.exports = {
currentlyFocusedField,
focusTextInput,
blurTextInput,
registerInput,
unregisterInput,
isTextInput,
};
module.exports = TextInputState;
+4 -4
View File
@@ -1,17 +1,17 @@
/**
* @generated by scripts/bump-oss-version.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.
*
* @format
* @generated by scripts/bump-oss-version.js
* @flow
*/
exports.version = {
major: 0,
minor: 0,
patch: 0,
minor: 56,
patch: 1,
prerelease: null,
};
+3 -1
View File
@@ -1217,7 +1217,9 @@ class VirtualizedList extends React.PureComponent<Props, State> {
}
_selectOffset(metrics: $ReadOnly<{x: number, y: number}>): number {
return !this.props.horizontal ? metrics.y : metrics.x;
return (
(!this.props.horizontal ? metrics.y : metrics.x) - this._headerLength
);
}
_maybeCallOnEndReached() {
+7
View File
@@ -127,4 +127,11 @@ const styles = StyleSheet.create({
},
});
if (__DEV__) {
if (!global.__RCTProfileIsProfiling) {
const YellowBox = require('YellowBox');
YellowBox.install();
}
}
module.exports = AppContainer;
-554
View File
@@ -1,554 +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 EventEmitter = require('EventEmitter');
const Platform = require('Platform');
const React = require('React');
const SafeAreaView = require('SafeAreaView');
const StyleSheet = require('StyleSheet');
const RCTLog = require('RCTLog');
const infoLog = require('infoLog');
const openFileInEditor = require('openFileInEditor');
const parseErrorStack = require('parseErrorStack');
const stringifySafe = require('stringifySafe');
const symbolicateStackTrace = require('symbolicateStackTrace');
import type EmitterSubscription from 'EmitterSubscription';
import type {StackFrame} from 'parseErrorStack';
type WarningInfo = {
count: number,
stacktrace: Array<StackFrame>,
symbolicated: boolean,
};
const _warningEmitter = new EventEmitter();
const _warningMap: Map<string, WarningInfo> = new Map();
const IGNORED_WARNINGS: Array<string> = [];
/**
* YellowBox renders warnings at the bottom of the app being developed.
*
* Warnings help guard against subtle yet significant issues that can impact the
* quality of the app. This "in your face" style of warning allows developers to
* notice and correct these issues as quickly as possible.
*
* By default, the warning box is enabled in `__DEV__`. Set the following flag
* to disable it (and call `console.warn` to update any rendered <YellowBox>):
*
* console.disableYellowBox = true;
* console.warn('YellowBox is disabled.');
*
* Ignore specific warnings by calling:
*
* YellowBox.ignoreWarnings(['Warning: ...']);
*
* (DEPRECATED) Warnings can be ignored programmatically by setting the array:
*
* console.ignoredYellowBox = ['Warning: ...'];
*
* Strings in `console.ignoredYellowBox` can be a prefix of the warning that
* should be ignored.
*/
if (__DEV__) {
const {error, warn} = console;
(console: any).error = function() {
error.apply(console, arguments);
// Show yellow box for the `warning` module.
if (
typeof arguments[0] === 'string' &&
arguments[0].startsWith('Warning: ')
) {
updateWarningMap.apply(null, arguments);
}
};
(console: any).warn = function() {
warn.apply(console, arguments);
updateWarningMap.apply(null, arguments);
};
if (Platform.isTesting) {
(console: any).disableYellowBox = true;
}
RCTLog.setWarningHandler((...args) => {
updateWarningMap.apply(null, args);
});
}
/**
* Simple function for formatting strings.
*
* Replaces placeholders with values passed as extra arguments
*
* @param {string} format the base string
* @param ...args the values to insert
* @return {string} the replaced string
*/
function sprintf(format, ...args) {
let index = 0;
return format.replace(/%s/g, match => args[index++]);
}
function updateWarningMap(...args): void {
/* $FlowFixMe(>=0.68.0 site=react_native_fb) This comment suppresses an error
* found when Flow v0.68 was deployed. To see the error delete this comment
* and run Flow. */
if (console.disableYellowBox) {
return;
}
let warning;
if (typeof args[0] === 'string') {
const [format, ...formatArgs] = args;
const argCount = (format.match(/%s/g) || []).length;
warning = [
sprintf(format, ...formatArgs.slice(0, argCount).map(stringifySafe)),
...formatArgs.slice(argCount).map(stringifySafe),
].join(' ');
} else {
warning = args.map(stringifySafe).join(' ');
}
if (warning.startsWith('(ADVICE)')) {
return;
}
const warningInfo = _warningMap.get(warning);
if (warningInfo) {
warningInfo.count += 1;
} else {
const error: any = new Error();
error.framesToPop = 2;
_warningMap.set(warning, {
count: 1,
stacktrace: parseErrorStack(error),
symbolicated: false,
});
}
_warningEmitter.emit('warning', _warningMap);
}
function ensureSymbolicatedWarning(warning: string): void {
const prevWarningInfo = _warningMap.get(warning);
if (!prevWarningInfo || prevWarningInfo.symbolicated) {
return;
}
prevWarningInfo.symbolicated = true;
symbolicateStackTrace(prevWarningInfo.stacktrace).then(
stack => {
const nextWarningInfo = _warningMap.get(warning);
if (nextWarningInfo) {
nextWarningInfo.stacktrace = stack;
_warningEmitter.emit('warning', _warningMap);
}
},
error => {
const nextWarningInfo = _warningMap.get(warning);
if (nextWarningInfo) {
infoLog('Failed to symbolicate warning, "%s":', warning, error);
_warningEmitter.emit('warning', _warningMap);
}
},
);
}
function isWarningIgnored(warning: string): boolean {
const isIgnored = IGNORED_WARNINGS.some((ignoredWarning: string) =>
warning.includes(ignoredWarning),
);
if (isIgnored) {
return true;
}
// DEPRECATED
return (
/* $FlowFixMe(>=0.68.0 site=react_native_fb) This comment suppresses an
* error found when Flow v0.68 was deployed. To see the error delete this
* comment and run Flow. */
Array.isArray(console.ignoredYellowBox) &&
console.ignoredYellowBox.some(ignorePrefix =>
warning.startsWith(String(ignorePrefix)),
)
);
}
const WarningRow = ({count, warning, onPress}) => {
const Text = require('Text');
const TouchableHighlight = require('TouchableHighlight');
const View = require('View');
const countText =
count > 1 ? (
<Text style={styles.listRowCount}>{'(' + count + ') '}</Text>
) : null;
return (
<View style={styles.listRow}>
<TouchableHighlight
activeOpacity={0.5}
onPress={onPress}
style={styles.listRowContent}
underlayColor="transparent">
<Text style={styles.listRowText} numberOfLines={2}>
{countText}
{warning}
</Text>
</TouchableHighlight>
</View>
);
};
type StackRowProps = {frame: StackFrame};
const StackRow = ({frame}: StackRowProps) => {
const Text = require('Text');
const TouchableHighlight = require('TouchableHighlight');
const {file, lineNumber} = frame;
let fileName;
if (file) {
const fileParts = file.split('/');
fileName = fileParts[fileParts.length - 1];
} else {
fileName = '<unknown file>';
}
return (
<TouchableHighlight
activeOpacity={0.5}
style={styles.openInEditorButton}
underlayColor="transparent"
onPress={openFileInEditor.bind(null, file, lineNumber)}>
<Text style={styles.inspectorCountText}>
{fileName}:{lineNumber}
</Text>
</TouchableHighlight>
);
};
const WarningInspector = ({
warningInfo,
warning,
stacktraceVisible,
onDismiss,
onMinimize,
toggleStacktrace,
}) => {
const ScrollView = require('ScrollView');
const Text = require('Text');
const TouchableHighlight = require('TouchableHighlight');
const View = require('View');
const {count, stacktrace} = warningInfo || {};
const countSentence =
'Warning encountered ' + count + ' time' + (count - 1 ? 's' : '') + '.';
let stacktraceList;
if (stacktraceVisible && stacktrace) {
stacktraceList = (
<View style={styles.stacktraceList}>
{stacktrace.map((frame, ii) => <StackRow frame={frame} key={ii} />)}
</View>
);
}
return (
<View style={styles.inspector}>
<SafeAreaView style={styles.safeArea}>
<View style={styles.inspectorCount}>
<Text style={styles.inspectorCountText}>{countSentence}</Text>
<TouchableHighlight
onPress={toggleStacktrace}
underlayColor="transparent">
<Text style={styles.inspectorButtonText}>
{stacktraceVisible ? '\u{25BC}' : '\u{25B6}'} Stacktrace
</Text>
</TouchableHighlight>
</View>
<ScrollView style={styles.inspectorWarning}>
{stacktraceList}
<Text style={styles.inspectorWarningText}>{warning}</Text>
</ScrollView>
<View style={styles.inspectorButtons}>
<TouchableHighlight
activeOpacity={0.5}
onPress={onMinimize}
style={styles.inspectorButton}
underlayColor="transparent">
<Text style={styles.inspectorButtonText}>Minimize</Text>
</TouchableHighlight>
<TouchableHighlight
activeOpacity={0.5}
onPress={onDismiss}
style={styles.inspectorButton}
underlayColor="transparent">
<Text style={styles.inspectorButtonText}>Dismiss</Text>
</TouchableHighlight>
</View>
</SafeAreaView>
</View>
);
};
class YellowBox extends React.Component<
mixed,
{
stacktraceVisible: boolean,
inspecting: ?string,
warningMap: Map<any, any>,
},
> {
_listener: ?EmitterSubscription;
dismissWarning: (warning: ?string) => void;
constructor(props: mixed, context: mixed) {
super(props, context);
this.state = {
inspecting: null,
stacktraceVisible: false,
warningMap: _warningMap,
};
this.dismissWarning = warning => {
const {inspecting, warningMap} = this.state;
if (warning) {
warningMap.delete(warning);
} else {
warningMap.clear();
}
this.setState({
inspecting: warning && inspecting !== warning ? inspecting : null,
warningMap,
});
};
}
static ignoreWarnings(warnings: Array<string>): void {
warnings.forEach((warning: string) => {
if (IGNORED_WARNINGS.indexOf(warning) === -1) {
IGNORED_WARNINGS.push(warning);
}
});
}
componentDidMount() {
let scheduled = null;
this._listener = _warningEmitter.addListener('warning', warningMap => {
// Use `setImmediate` because warnings often happen during render, but
// state cannot be set while rendering.
scheduled =
scheduled ||
setImmediate(() => {
scheduled = null;
this.setState({
warningMap,
});
});
});
}
componentDidUpdate() {
const {inspecting} = this.state;
if (inspecting != null) {
ensureSymbolicatedWarning(inspecting);
}
}
componentWillUnmount() {
if (this._listener) {
this._listener.remove();
}
}
render() {
/* $FlowFixMe(>=0.68.0 site=react_native_fb) This comment suppresses an
* error found when Flow v0.68 was deployed. To see the error delete this
* comment and run Flow. */
if (console.disableYellowBox || this.state.warningMap.size === 0) {
return null;
}
const ScrollView = require('ScrollView');
const View = require('View');
const Text = require('Text');
const TouchableHighlight = require('TouchableHighlight');
const {inspecting, stacktraceVisible} = this.state;
const inspector =
inspecting !== null ? (
<WarningInspector
warningInfo={this.state.warningMap.get(inspecting)}
warning={inspecting}
stacktraceVisible={stacktraceVisible}
onDismiss={() => this.dismissWarning(inspecting)}
onMinimize={() => this.setState({inspecting: null})}
toggleStacktrace={() =>
this.setState({stacktraceVisible: !stacktraceVisible})
}
/>
) : null;
const rows = [];
this.state.warningMap.forEach((warningInfo, warning) => {
if (!isWarningIgnored(warning)) {
rows.push(
<WarningRow
key={warning}
count={warningInfo.count}
warning={warning}
onPress={() => this.setState({inspecting: warning})}
onDismiss={() => this.dismissWarning(warning)}
/>,
);
}
});
const listStyle = [
styles.list,
// Additional `0.4` so the 5th row can peek into view.
{height: Math.min(rows.length, 4.4) * (rowGutter + rowHeight)},
];
return (
<View style={inspector ? styles.fullScreen : listStyle}>
{!inspector &&
rows.length > 0 && (
<TouchableHighlight
style={styles.dismissAllContainer}
onPress={() => this.dismissWarning(null)}>
<Text style={styles.dismissAll}>Dismiss All</Text>
</TouchableHighlight>
)}
<ScrollView style={listStyle} scrollsToTop={false}>
{rows}
</ScrollView>
{inspector}
</View>
);
}
}
const backgroundColor = opacity => 'rgba(250, 186, 48, ' + opacity + ')';
const textColor = 'white';
const rowGutter = 1;
const rowHeight = 46;
// For unknown reasons, setting elevation: Number.MAX_VALUE causes remote debugging to
// hang on iOS (some sort of overflow maybe). Setting it to Number.MAX_SAFE_INTEGER fixes the iOS issue, but since
// elevation is an android-only style property we might as well remove it altogether for iOS.
// See: https://github.com/facebook/react-native/issues/12223
const elevation =
Platform.OS === 'android' ? Number.MAX_SAFE_INTEGER : undefined;
const styles = StyleSheet.create({
fullScreen: {
height: '100%',
width: '100%',
elevation: elevation,
position: 'absolute',
},
inspector: {
backgroundColor: backgroundColor(0.95),
height: '100%',
paddingTop: 5,
elevation: elevation,
},
inspectorButtons: {
flexDirection: 'row',
},
inspectorButton: {
flex: 1,
paddingVertical: 22,
backgroundColor: backgroundColor(1),
},
safeArea: {
flex: 1,
},
stacktraceList: {
paddingBottom: 5,
},
inspectorButtonText: {
color: textColor,
fontSize: 14,
opacity: 0.8,
textAlign: 'center',
},
openInEditorButton: {
paddingTop: 5,
paddingBottom: 5,
},
inspectorCount: {
padding: 15,
paddingBottom: 0,
flexDirection: 'row',
justifyContent: 'space-between',
},
inspectorCountText: {
color: textColor,
fontSize: 14,
},
inspectorWarning: {
flex: 1,
paddingHorizontal: 15,
},
inspectorWarningText: {
color: textColor,
fontSize: 16,
fontWeight: '600',
},
list: {
backgroundColor: 'transparent',
position: 'absolute',
left: 0,
right: 0,
bottom: 0,
elevation: elevation,
},
listRow: {
backgroundColor: backgroundColor(0.95),
height: rowHeight,
marginTop: rowGutter,
},
listRowContent: {
flex: 1,
},
listRowCount: {
color: 'rgba(255, 255, 255, 0.5)',
},
listRowText: {
color: textColor,
position: 'absolute',
left: 0,
top: Platform.OS === 'android' ? 5 : 7,
marginLeft: 15,
marginRight: 15,
},
dismissAllContainer: {
height: 20,
justifyContent: 'center',
marginTop: -30,
marginRight: 5,
backgroundColor: backgroundColor(0.95),
alignSelf: 'flex-end',
paddingHorizontal: 10,
borderRadius: 10,
},
dismissAll: {
color: 'white',
},
});
module.exports = YellowBox;
+1 -1
View File
@@ -1 +1 @@
c0fe8d6f6942f5cbc93c09825e803ba8cf950522
ae14317d6810d5b07d01308a2116a707e5e09983
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -1,18 +0,0 @@
/**
* Copyright (c) 2013-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 {
__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED,
} = require('ReactNative');
module.exports =
__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.ReactNativeComponentTree;
@@ -89,7 +89,6 @@ export type NativeMethodsMixinType = {
type SecretInternalsType = {
NativeMethodsMixin: NativeMethodsMixinType,
ReactNativeComponentTree: any,
computeComponentStackForErrorReporting(tag: number): string,
// TODO (bvaughn) Decide which additional types to expose here?
// And how much information to fill in for the above types.
@@ -97,7 +96,6 @@ type SecretInternalsType = {
type SecretInternalsFabricType = {
NativeMethodsMixin: NativeMethodsMixinType,
ReactNativeComponentTree: any,
};
/**
+20 -20
View File
@@ -92,10 +92,10 @@ export type ____LayoutStyle_Internal = $ReadOnly<{|
export type ____TransformStyle_Internal = $ReadOnly<{|
transform?: $ReadOnlyArray<
| {|+perspective: number | AnimatedNode|}
| {|+rotate: string|}
| {|+rotateX: string|}
| {|+rotateY: string|}
| {|+rotateZ: string|}
| {|+rotate: string | AnimatedNode|}
| {|+rotateX: string | AnimatedNode|}
| {|+rotateY: string | AnimatedNode|}
| {|+rotateZ: string | AnimatedNode|}
| {|+scale: number | AnimatedNode|}
| {|+scaleX: number | AnimatedNode|}
| {|+scaleY: number | AnimatedNode|}
@@ -138,23 +138,23 @@ export type ____ViewStyle_Internal = $ReadOnly<{|
borderRightColor?: ColorValue,
borderStartColor?: ColorValue,
borderTopColor?: ColorValue,
borderRadius?: number,
borderBottomEndRadius?: number,
borderBottomLeftRadius?: number,
borderBottomRightRadius?: number,
borderBottomStartRadius?: number,
borderTopEndRadius?: number,
borderTopLeftRadius?: number,
borderTopRightRadius?: number,
borderTopStartRadius?: number,
borderRadius?: number | AnimatedNode,
borderBottomEndRadius?: number | AnimatedNode,
borderBottomLeftRadius?: number | AnimatedNode,
borderBottomRightRadius?: number | AnimatedNode,
borderBottomStartRadius?: number | AnimatedNode,
borderTopEndRadius?: number | AnimatedNode,
borderTopLeftRadius?: number | AnimatedNode,
borderTopRightRadius?: number | AnimatedNode,
borderTopStartRadius?: number | AnimatedNode,
borderStyle?: 'solid' | 'dotted' | 'dashed',
borderWidth?: number,
borderBottomWidth?: number,
borderEndWidth?: number,
borderLeftWidth?: number,
borderRightWidth?: number,
borderStartWidth?: number,
borderTopWidth?: number,
borderWidth?: number | AnimatedNode,
borderBottomWidth?: number | AnimatedNode,
borderEndWidth?: number | AnimatedNode,
borderLeftWidth?: number | AnimatedNode,
borderRightWidth?: number | AnimatedNode,
borderStartWidth?: number | AnimatedNode,
borderTopWidth?: number | AnimatedNode,
opacity?: number | AnimatedNode,
elevation?: number,
|}>;
@@ -289,7 +289,12 @@ RCT_NOT_IMPLEMENTED(- (instancetype)initWithFrame:(CGRect)frame)
NSString *previousText = [_predictedText substringWithRange:range] ?: @"";
if (_predictedText) {
// After clearing the text by replacing it with an empty string, `_predictedText`
// still preserves the deleted text.
// As the first character in the TextInput always comes with the range value (0, 0),
// we should check the range value in order to avoid appending a character to the deleted string
// (which caused the issue #18374)
if (!NSEqualRanges(range, NSMakeRange(0, 0)) && _predictedText) {
_predictedText = [_predictedText stringByReplacingCharactersInRange:range withString:text];
} else {
_predictedText = text;
+3
View File
@@ -20,6 +20,7 @@ const deepFreezeAndThrowOnMutationInDev = require('deepFreezeAndThrowOnMutationI
* - Less chance of typos.
*/
const UTFSequence = deepFreezeAndThrowOnMutationInDev({
BOM: '\ufeff', // byte order mark
BULLET: '\u2022', // bullet: &#8226;
BULLET_SP: '\u00A0\u2022\u00A0', // &nbsp;&#8226;&nbsp;
MIDDOT: '\u00B7', // normal middle dot: &middot;
@@ -31,6 +32,8 @@ const UTFSequence = deepFreezeAndThrowOnMutationInDev({
NDASH_SP: '\u00A0\u2013\u00A0', // &nbsp;&ndash;&nbsp;
NBSP: '\u00A0', // non-breaking space: &nbsp;
PIZZA: '\uD83C\uDF55',
TRIANGLE_LEFT: '\u25c0', // black left-pointing triangle
TRIANGLE_RIGHT: '\u25b6', // black right-pointing triangle
});
module.exports = UTFSequence;
@@ -9,7 +9,12 @@
#import <React/RCTConvert.h>
#import <React/RCTDefines.h>
#if __has_include(<React/fishhook.h>)
#import <React/fishhook.h>
#else
#import <fishhook/fishhook.h>
#endif
#if __has_include(<os/log.h>) && defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 100300 /* __IPHONE_10_3 */
#import <os/log.h>
@@ -0,0 +1,146 @@
/**
* 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 strict-local
* @format
*/
'use strict';
const React = require('React');
const Text = require('Text');
const UTFSequence = require('UTFSequence');
const stringifySafe = require('stringifySafe');
import type {TextStyleProp} from 'StyleSheet';
export type Category = string;
export type Message = $ReadOnly<{|
content: string,
substitutions: $ReadOnlyArray<
$ReadOnly<{|
length: number,
offset: number,
|}>,
>,
|}>;
const SUBSTITUTION = UTFSequence.BOM + '%s';
const YellowBoxCategory = {
parse(
args: $ReadOnlyArray<mixed>,
): $ReadOnly<{|
category: Category,
message: Message,
|}> {
const categoryParts = [];
const contentParts = [];
const substitutionOffsets = [];
const remaining = [...args];
if (typeof remaining[0] === 'string') {
const formatString = String(remaining.shift());
const formatStringParts = formatString.split('%s');
const substitutionCount = formatStringParts.length - 1;
const substitutions = remaining.splice(0, substitutionCount);
let categoryString = '';
let contentString = '';
let substitutionIndex = 0;
for (const formatStringPart of formatStringParts) {
categoryString += formatStringPart;
contentString += formatStringPart;
if (substitutionIndex < substitutionCount) {
if (substitutionIndex < substitutions.length) {
const substitution = stringifySafe(
substitutions[substitutionIndex],
);
substitutionOffsets.push({
length: substitution.length,
offset: contentString.length,
});
categoryString += SUBSTITUTION;
contentString += substitution;
} else {
substitutionOffsets.push({
length: 2,
offset: contentString.length,
});
categoryString += '%s';
contentString += '%s';
}
substitutionIndex++;
}
}
categoryParts.push(categoryString);
contentParts.push(contentString);
}
const remainingArgs = remaining.map(stringifySafe);
categoryParts.push(...remainingArgs);
contentParts.push(...remainingArgs);
return {
category: categoryParts.join(' '),
message: {
content: contentParts.join(' '),
substitutions: substitutionOffsets,
},
};
},
render(
{content, substitutions}: Message,
substitutionStyle: TextStyleProp,
): React.Node {
const elements = [];
const lastOffset = substitutions.reduce(
(prevOffset, substitution, index) => {
const key = String(index);
if (substitution.offset > prevOffset) {
const prevPart = content.substr(
prevOffset,
substitution.offset - prevOffset,
);
elements.push(<Text key={key}>{prevPart}</Text>);
}
const substititionPart = content.substr(
substitution.offset,
substitution.length,
);
elements.push(
<Text key={key + '.5'} style={substitutionStyle}>
{substititionPart}
</Text>,
);
return substitution.offset + substitution.length;
},
0,
);
if (lastOffset < content.length - 1) {
const lastPart = content.substr(lastOffset);
elements.push(<Text key="-1">{lastPart}</Text>);
}
return elements;
},
};
module.exports = YellowBoxCategory;
@@ -0,0 +1,141 @@
/**
* 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 strict-local
* @format
*/
'use strict';
const YellowBoxWarning = require('YellowBoxWarning');
import type {Category} from 'YellowBoxCategory';
export type Registry = Map<Category, $ReadOnlyArray<YellowBoxWarning>>;
export type Observer = (registry: Registry) => void;
export type Subscription = $ReadOnly<{|
unsubscribe: () => void,
|}>;
const observers: Set<{observer: Observer}> = new Set();
const ignorePatterns: Set<string> = new Set();
const registry: Registry = new Map();
let disabled = false;
let projection = new Map();
let updateTimeout = null;
function isWarningIgnored(warning: YellowBoxWarning): boolean {
for (const pattern of ignorePatterns) {
if (warning.message.content.includes(pattern)) {
return true;
}
}
return false;
}
function handleUpdate(): void {
projection = new Map();
if (!disabled) {
for (const [category, warnings] of registry) {
const filtered = warnings.filter(warning => !isWarningIgnored(warning));
if (filtered.length > 0) {
projection.set(category, filtered);
}
}
}
if (updateTimeout == null) {
updateTimeout = setImmediate(() => {
updateTimeout = null;
for (const {observer} of observers) {
observer(projection);
}
});
}
}
const YellowBoxRegistry = {
add({
args,
framesToPop,
}: $ReadOnly<{|
args: $ReadOnlyArray<mixed>,
framesToPop: number,
|}>): void {
if (typeof args[0] === 'string' && args[0].startsWith('(ADVICE)')) {
return;
}
const {category, message, stack} = YellowBoxWarning.parse({
args,
framesToPop: framesToPop + 1,
});
let warnings = registry.get(category);
if (warnings == null) {
warnings = [];
}
warnings = [...warnings, new YellowBoxWarning(message, stack)];
registry.delete(category);
registry.set(category, warnings);
handleUpdate();
},
delete(category: Category): void {
if (registry.has(category)) {
registry.delete(category);
handleUpdate();
}
},
clear(): void {
if (registry.size > 0) {
registry.clear();
handleUpdate();
}
},
addIgnorePatterns(patterns: $ReadOnlyArray<string>): void {
const newPatterns = patterns.filter(
pattern => !ignorePatterns.has(pattern),
);
if (newPatterns.length === 0) {
return;
}
for (const pattern of newPatterns) {
ignorePatterns.add(pattern);
}
handleUpdate();
},
setDisabled(value: boolean): void {
if (value === disabled) {
return;
}
disabled = value;
handleUpdate();
},
isDisabled(): boolean {
return disabled;
},
observe(observer: Observer): Subscription {
const subscription = {observer};
observers.add(subscription);
observer(projection);
return {
unsubscribe(): void {
observers.delete(subscription);
},
};
},
};
module.exports = YellowBoxRegistry;
@@ -0,0 +1,75 @@
/**
* 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 strict-local
* @format
*/
'use strict';
const symbolicateStackTrace = require('symbolicateStackTrace');
import type {StackFrame} from 'parseErrorStack';
type CacheKey = string;
export type Stack = Array<StackFrame>;
const cache: Map<CacheKey, Promise<Stack>> = new Map();
const YellowBoxSymbolication = {
symbolicate(stack: Stack): Promise<Stack> {
const key = getCacheKey(stack);
let promise = cache.get(key);
if (promise == null) {
promise = symbolicateStackTrace(stack).then(sanitize);
cache.set(key, promise);
}
return promise;
},
};
const getCacheKey = (stack: Stack): CacheKey => {
return JSON.stringify(stack);
};
/**
* Sanitize because sometimes, `symbolicateStackTrace` gives us invalid values.
*/
const sanitize = (maybeStack: mixed): Stack => {
if (!Array.isArray(maybeStack)) {
throw new Error('Expected stack to be an array.');
}
const stack = [];
for (const maybeFrame of maybeStack) {
if (typeof maybeFrame !== 'object' || maybeFrame == null) {
throw new Error('Expected each stack frame to be an object.');
}
if (typeof maybeFrame.column !== 'number' && maybeFrame.column != null) {
throw new Error('Expected stack frame `column` to be a nullable number.');
}
if (typeof maybeFrame.file !== 'string') {
throw new Error('Expected stack frame `file` to be a string.');
}
if (typeof maybeFrame.lineNumber !== 'number') {
throw new Error('Expected stack frame `lineNumber` to be a number.');
}
if (typeof maybeFrame.methodName !== 'string') {
throw new Error('Expected stack frame `methodName` to be a string.');
}
stack.push({
column: maybeFrame.column,
file: maybeFrame.file,
lineNumber: maybeFrame.lineNumber,
methodName: maybeFrame.methodName,
});
}
return stack;
};
module.exports = YellowBoxSymbolication;
@@ -0,0 +1,108 @@
/**
* 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 YellowBoxCategory = require('YellowBoxCategory');
const YellowBoxSymbolication = require('YellowBoxSymbolication');
const parseErrorStack = require('parseErrorStack');
import type {Category, Message} from 'YellowBoxCategory';
import type {Stack} from 'YellowBoxSymbolication';
export type SymbolicationRequest = $ReadOnly<{|
abort: () => void,
|}>;
class YellowBoxWarning {
static parse({
args,
framesToPop,
}: $ReadOnly<{|
args: $ReadOnlyArray<mixed>,
framesToPop: number,
|}>): {|
category: Category,
message: Message,
stack: Stack,
|} {
return {
...YellowBoxCategory.parse(args),
stack: createStack({framesToPop: framesToPop + 1}),
};
}
message: Message;
stack: Stack;
symbolicated:
| $ReadOnly<{|error: null, stack: null, status: 'NONE'|}>
| $ReadOnly<{|error: null, stack: null, status: 'PENDING'|}>
| $ReadOnly<{|error: null, stack: Stack, status: 'COMPLETE'|}>
| $ReadOnly<{|error: Error, stack: null, status: 'FAILED'|}> = {
error: null,
stack: null,
status: 'NONE',
};
constructor(message: Message, stack: Stack) {
this.message = message;
this.stack = stack;
}
getAvailableStack(): Stack {
return this.symbolicated.status === 'COMPLETE'
? this.symbolicated.stack
: this.stack;
}
symbolicate(callback: () => void): SymbolicationRequest {
let aborted = false;
if (this.symbolicated.status !== 'COMPLETE') {
const updateStatus = (error: ?Error, stack: ?Stack): void => {
if (error != null) {
this.symbolicated = {error, stack: null, status: 'FAILED'};
} else if (stack != null) {
this.symbolicated = {error: null, stack, status: 'COMPLETE'};
} else {
this.symbolicated = {error: null, stack: null, status: 'PENDING'};
}
if (!aborted) {
callback();
}
};
updateStatus(null, null);
YellowBoxSymbolication.symbolicate(this.stack).then(
stack => {
updateStatus(null, stack);
},
error => {
updateStatus(error, null);
},
);
}
return {
abort(): void {
aborted = true;
},
};
}
}
function createStack({framesToPop}: $ReadOnly<{|framesToPop: number|}>): Stack {
const error: any = new Error();
error.framesToPop = framesToPop + 1;
return parseErrorStack(error);
}
module.exports = YellowBoxWarning;
@@ -0,0 +1,100 @@
/**
* 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.
*
* @emails oncall+react_native
* @format
* @flow strict-local
*/
'use strict';
const YellowBoxCategory = require('YellowBoxCategory');
describe('YellowBoxCategory', () => {
it('parses strings', () => {
expect(YellowBoxCategory.parse(['A'])).toEqual({
category: 'A',
message: {
content: 'A',
substitutions: [],
},
});
});
it('parses strings with arguments', () => {
expect(YellowBoxCategory.parse(['A', 'B', 'C'])).toEqual({
category: 'A "B" "C"',
message: {
content: 'A "B" "C"',
substitutions: [],
},
});
});
it('parses formatted strings', () => {
expect(YellowBoxCategory.parse(['%s', 'A'])).toEqual({
category: '\ufeff%s',
message: {
content: '"A"',
substitutions: [
{
length: 3,
offset: 0,
},
],
},
});
});
it('parses formatted strings with insufficient arguments', () => {
expect(YellowBoxCategory.parse(['%s %s', 'A'])).toEqual({
category: '\ufeff%s %s',
message: {
content: '"A" %s',
substitutions: [
{
length: 3,
offset: 0,
},
{
length: 2,
offset: 4,
},
],
},
});
});
it('parses formatted strings with excess arguments', () => {
expect(YellowBoxCategory.parse(['%s', 'A', 'B'])).toEqual({
category: '\ufeff%s "B"',
message: {
content: '"A" "B"',
substitutions: [
{
length: 3,
offset: 0,
},
],
},
});
});
it('treats "%s" in arguments as literals', () => {
expect(YellowBoxCategory.parse(['%s', '%s', 'A'])).toEqual({
category: '\ufeff%s "A"',
message: {
content: '"%s" "A"',
substitutions: [
{
length: 4,
offset: 0,
},
],
},
});
});
});
@@ -0,0 +1,267 @@
/**
* 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.
*
* @emails oncall+react_native
* @format
* @flow strict-local
*/
'use strict';
const YellowBoxCategory = require('YellowBoxCategory');
const YellowBoxRegistry = require('YellowBoxRegistry');
const registry = () => {
const observer = jest.fn();
YellowBoxRegistry.observe(observer).unsubscribe();
return observer.mock.calls[0][0];
};
const observe = () => {
const observer = jest.fn();
return {
observer,
subscription: YellowBoxRegistry.observe(observer),
};
};
describe('YellowBoxRegistry', () => {
beforeEach(() => {
jest.resetModules();
});
it('adds and deletes warnings', () => {
YellowBoxRegistry.add({args: ['A'], framesToPop: 0});
const {category: categoryA} = YellowBoxCategory.parse(['A']);
expect(registry().size).toBe(1);
expect(registry().get(categoryA)).not.toBe(undefined);
YellowBoxRegistry.delete(categoryA);
expect(registry().size).toBe(0);
expect(registry().get(categoryA)).toBe(undefined);
});
it('clears all warnings', () => {
YellowBoxRegistry.add({args: ['A'], framesToPop: 0});
YellowBoxRegistry.add({args: ['B'], framesToPop: 0});
YellowBoxRegistry.add({args: ['C'], framesToPop: 0});
expect(registry().size).toBe(3);
YellowBoxRegistry.clear();
expect(registry().size).toBe(0);
});
it('sorts warnings in chronological order', () => {
YellowBoxRegistry.add({args: ['A'], framesToPop: 0});
YellowBoxRegistry.add({args: ['B'], framesToPop: 0});
YellowBoxRegistry.add({args: ['C'], framesToPop: 0});
const {category: categoryA} = YellowBoxCategory.parse(['A']);
const {category: categoryB} = YellowBoxCategory.parse(['B']);
const {category: categoryC} = YellowBoxCategory.parse(['C']);
expect(Array.from(registry().keys())).toEqual([
categoryA,
categoryB,
categoryC,
]);
YellowBoxRegistry.add({args: ['A'], framesToPop: 0});
// Expect `A` to be hoisted to the end of the registry.
expect(Array.from(registry().keys())).toEqual([
categoryB,
categoryC,
categoryA,
]);
});
it('ignores warnings matching patterns', () => {
YellowBoxRegistry.add({args: ['A!'], framesToPop: 0});
YellowBoxRegistry.add({args: ['B?'], framesToPop: 0});
YellowBoxRegistry.add({args: ['C!'], framesToPop: 0});
expect(registry().size).toBe(3);
YellowBoxRegistry.addIgnorePatterns(['!']);
expect(registry().size).toBe(1);
YellowBoxRegistry.addIgnorePatterns(['?']);
expect(registry().size).toBe(0);
});
it('ignores all warnings when disabled', () => {
YellowBoxRegistry.add({args: ['A!'], framesToPop: 0});
YellowBoxRegistry.add({args: ['B?'], framesToPop: 0});
YellowBoxRegistry.add({args: ['C!'], framesToPop: 0});
expect(registry().size).toBe(3);
YellowBoxRegistry.setDisabled(true);
expect(registry().size).toBe(0);
YellowBoxRegistry.setDisabled(false);
expect(registry().size).toBe(3);
});
it('groups warnings by simple categories', () => {
YellowBoxRegistry.add({args: ['A'], framesToPop: 0});
expect(registry().size).toBe(1);
YellowBoxRegistry.add({args: ['A'], framesToPop: 0});
expect(registry().size).toBe(1);
YellowBoxRegistry.add({args: ['B'], framesToPop: 0});
expect(registry().size).toBe(2);
});
it('groups warnings by format string categories', () => {
YellowBoxRegistry.add({args: ['%s', 'A'], framesToPop: 0});
expect(registry().size).toBe(1);
YellowBoxRegistry.add({args: ['%s', 'B'], framesToPop: 0});
expect(registry().size).toBe(1);
YellowBoxRegistry.add({args: ['A'], framesToPop: 0});
expect(registry().size).toBe(2);
YellowBoxRegistry.add({args: ['B'], framesToPop: 0});
expect(registry().size).toBe(3);
});
it('groups warnings with consideration for arguments', () => {
YellowBoxRegistry.add({args: ['A', 'B'], framesToPop: 0});
expect(registry().size).toBe(1);
YellowBoxRegistry.add({args: ['A', 'B'], framesToPop: 0});
expect(registry().size).toBe(1);
YellowBoxRegistry.add({args: ['A', 'C'], framesToPop: 0});
expect(registry().size).toBe(2);
YellowBoxRegistry.add({args: ['%s', 'A', 'A'], framesToPop: 0});
expect(registry().size).toBe(3);
YellowBoxRegistry.add({args: ['%s', 'B', 'A'], framesToPop: 0});
expect(registry().size).toBe(3);
YellowBoxRegistry.add({args: ['%s', 'B', 'B'], framesToPop: 0});
expect(registry().size).toBe(4);
});
it('ignores warnings starting with "(ADVICE)"', () => {
YellowBoxRegistry.add({args: ['(ADVICE) ...'], framesToPop: 0});
expect(registry().size).toBe(0);
});
it('does not ignore warnings formatted to start with "(ADVICE)"', () => {
YellowBoxRegistry.add({args: ['%s ...', '(ADVICE)'], framesToPop: 0});
expect(registry().size).toBe(1);
});
it('immediately updates new observers', () => {
const {observer} = observe();
expect(observer.mock.calls.length).toBe(1);
expect(observer.mock.calls[0][0]).toBe(registry());
});
it('sends batched updates asynchoronously', () => {
const {observer} = observe();
expect(observer.mock.calls.length).toBe(1);
YellowBoxRegistry.add({args: ['A'], framesToPop: 0});
YellowBoxRegistry.add({args: ['B'], framesToPop: 0});
jest.runAllImmediates();
expect(observer.mock.calls.length).toBe(2);
});
it('stops sending updates to unsubscribed observers', () => {
const {observer, subscription} = observe();
subscription.unsubscribe();
expect(observer.mock.calls.length).toBe(1);
expect(observer.mock.calls[0][0]).toBe(registry());
});
it('updates observers when a warning is added or deleted', () => {
const {observer} = observe();
expect(observer.mock.calls.length).toBe(1);
YellowBoxRegistry.add({args: ['A'], framesToPop: 0});
jest.runAllImmediates();
expect(observer.mock.calls.length).toBe(2);
const {category: categoryA} = YellowBoxCategory.parse(['A']);
YellowBoxRegistry.delete(categoryA);
jest.runAllImmediates();
expect(observer.mock.calls.length).toBe(3);
// Does nothing when category does not exist.
YellowBoxRegistry.delete(categoryA);
jest.runAllImmediates();
expect(observer.mock.calls.length).toBe(3);
});
it('updates observers when cleared', () => {
const {observer} = observe();
expect(observer.mock.calls.length).toBe(1);
YellowBoxRegistry.add({args: ['A'], framesToPop: 0});
jest.runAllImmediates();
expect(observer.mock.calls.length).toBe(2);
YellowBoxRegistry.clear();
jest.runAllImmediates();
expect(observer.mock.calls.length).toBe(3);
// Does nothing when already empty.
YellowBoxRegistry.clear();
jest.runAllImmediates();
expect(observer.mock.calls.length).toBe(3);
});
it('updates observers when an ignore pattern is added', () => {
const {observer} = observe();
expect(observer.mock.calls.length).toBe(1);
YellowBoxRegistry.addIgnorePatterns(['?']);
jest.runAllImmediates();
expect(observer.mock.calls.length).toBe(2);
YellowBoxRegistry.addIgnorePatterns(['!']);
jest.runAllImmediates();
expect(observer.mock.calls.length).toBe(3);
// Does nothing for an existing ignore pattern.
YellowBoxRegistry.addIgnorePatterns(['!']);
jest.runAllImmediates();
expect(observer.mock.calls.length).toBe(3);
});
it('updates observers when disabled or enabled', () => {
const {observer} = observe();
expect(observer.mock.calls.length).toBe(1);
YellowBoxRegistry.setDisabled(true);
jest.runAllImmediates();
expect(observer.mock.calls.length).toBe(2);
// Does nothing when already disabled.
YellowBoxRegistry.setDisabled(true);
jest.runAllImmediates();
expect(observer.mock.calls.length).toBe(2);
YellowBoxRegistry.setDisabled(false);
jest.runAllImmediates();
expect(observer.mock.calls.length).toBe(3);
// Does nothing when already enabled.
YellowBoxRegistry.setDisabled(false);
jest.runAllImmediates();
expect(observer.mock.calls.length).toBe(3);
});
});
@@ -0,0 +1,52 @@
/**
* 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.
*
* @emails oncall+react_native
* @format
* @flow
*/
'use strict';
import type {StackFrame} from 'parseErrorStack';
jest.mock('symbolicateStackTrace');
const YellowBoxSymbolication = require('YellowBoxSymbolication');
const symbolicateStackTrace: JestMockFn<
$ReadOnlyArray<Array<StackFrame>>,
Promise<Array<StackFrame>>,
> = (require('symbolicateStackTrace'): any);
const createStack = methodNames =>
methodNames.map(methodName => ({
column: null,
file: 'file://path/to/file.js',
lineNumber: 1,
methodName,
}));
describe('YellowBoxSymbolication', () => {
beforeEach(() => {
jest.resetModules();
symbolicateStackTrace.mockImplementation(async stack => stack);
});
it('symbolicates different stacks', () => {
YellowBoxSymbolication.symbolicate(createStack(['A', 'B', 'C']));
YellowBoxSymbolication.symbolicate(createStack(['D', 'E', 'F']));
expect(symbolicateStackTrace.mock.calls.length).toBe(2);
});
it('batch symbolicates equivalent stacks', () => {
YellowBoxSymbolication.symbolicate(createStack(['A', 'B', 'C']));
YellowBoxSymbolication.symbolicate(createStack(['A', 'B', 'C']));
expect(symbolicateStackTrace.mock.calls.length).toBe(1);
});
});
@@ -0,0 +1,126 @@
/**
* 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.
*
* @emails oncall+react_native
* @format
* @flow
*/
'use strict';
import type {StackFrame} from 'parseErrorStack';
jest.mock('YellowBoxSymbolication');
const YellowBoxSymbolication: {|
symbolicate: JestMockFn<
$ReadOnlyArray<Array<StackFrame>>,
Promise<Array<StackFrame>>,
>,
|} = (require('YellowBoxSymbolication'): any);
const YellowBoxWarning = require('YellowBoxWarning');
const createStack = methodNames =>
methodNames.map(methodName => ({
column: null,
file: 'file://path/to/file.js',
lineNumber: 1,
methodName,
}));
describe('YellowBoxWarning', () => {
beforeEach(() => {
jest.resetModules();
YellowBoxSymbolication.symbolicate.mockImplementation(async stack =>
createStack(stack.map(frame => `S(${frame.methodName})`)),
);
});
it('starts without a symbolicated stack', () => {
const warning = new YellowBoxWarning(
{content: '...', substitutions: []},
createStack(['A', 'B', 'C']),
);
expect(warning.symbolicated).toEqual({
error: null,
stack: null,
status: 'NONE',
});
});
it('updates when symbolication is in progress', () => {
const warning = new YellowBoxWarning(
{content: '...', substitutions: []},
createStack(['A', 'B', 'C']),
);
const callback = jest.fn();
warning.symbolicate(callback);
expect(callback.mock.calls.length).toBe(1);
expect(warning.symbolicated).toEqual({
error: null,
stack: null,
status: 'PENDING',
});
});
it('updates when symbolication finishes', () => {
const warning = new YellowBoxWarning(
{content: '...', substitutions: []},
createStack(['A', 'B', 'C']),
);
const callback = jest.fn();
warning.symbolicate(callback);
jest.runAllTicks();
expect(callback.mock.calls.length).toBe(2);
expect(warning.symbolicated).toEqual({
error: null,
stack: createStack(['S(A)', 'S(B)', 'S(C)']),
status: 'COMPLETE',
});
});
it('updates when symbolication fails', () => {
const error = new Error('...');
YellowBoxSymbolication.symbolicate.mockImplementation(async stack => {
throw error;
});
const warning = new YellowBoxWarning(
{content: '...', substitutions: []},
createStack(['A', 'B', 'C']),
);
const callback = jest.fn();
warning.symbolicate(callback);
jest.runAllTicks();
expect(callback.mock.calls.length).toBe(2);
expect(warning.symbolicated).toEqual({
error,
stack: null,
status: 'FAILED',
});
});
it('does not update aborted requests', () => {
const warning = new YellowBoxWarning(
{content: '...', substitutions: []},
createStack(['A', 'B', 'C']),
);
const callback = jest.fn();
const request = warning.symbolicate(callback);
request.abort();
jest.runAllTicks();
expect(callback.mock.calls.length).toBe(1);
});
});
+53
View File
@@ -0,0 +1,53 @@
/**
* 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 strict-local
* @format
*/
'use strict';
const React = require('React');
const StyleSheet = require('StyleSheet');
const Text = require('Text');
const YellowBoxPressable = require('YellowBoxPressable');
const YellowBoxStyle = require('YellowBoxStyle');
import type {EdgeInsetsProp} from 'EdgeInsetsPropType';
type Props = $ReadOnly<{|
hitSlop?: ?EdgeInsetsProp,
label: string,
onPress: () => void,
|}>;
const YellowBoxButton = (props: Props): React.Node => (
<YellowBoxPressable
hitSlop={props.hitSlop}
onPress={props.onPress}
style={styles.root}>
<Text numberOfLines={1} style={styles.label}>
{props.label}
</Text>
</YellowBoxPressable>
);
const styles = StyleSheet.create({
root: {
borderRadius: 14,
height: 28,
justifyContent: 'center',
paddingHorizontal: 12,
},
label: {
color: YellowBoxStyle.getTextColor(1),
fontSize: 12,
includeFontPadding: false,
lineHeight: 16,
},
});
module.exports = YellowBoxButton;
@@ -0,0 +1,52 @@
/**
* 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 strict-local
* @format
*/
'use strict';
const PixelRatio = require('PixelRatio');
const scale = PixelRatio.get();
/**
* We use inline images for YellowBox in order to avoid display latency due to
* resource contention with symbolicating stack traces.
*
* The following steps were used to create these:
*
* 1. Download SVG files from: https://feathericons.com
* 2. Rasterize SVG files to PNG files at 16dp, 36dp, and 48dp.
* 3. Convert to Base64: https://www.google.com/search?q=base64+image+encoder
*
* @see https://github.com/feathericons/feather
* @copyright 2013-2017 Cole Bemis
* @license MIT
*/
const YellowBoxImageSource = {
alertTriangle:
scale > 2
? 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAYAAABXAvmHAAAB60lEQVRoge2Z3W3DIBSFj9oFPAIjZARGyAiMkBHuJh4hI2QEj5AR3Me+tQ91JALHmD8bKvmTkCr5Auc6/kzUACcnRXzuvL4GoAB8Afjeea9qXADcAfw4475c65orgBl++NeYl5ouUQiHt5tQTRJuwB6b5zLY49QVGn7I0bo+kuv60IQbuHf5CWCIqOkCgX93maia1MkRAUMo+OI+AvUPp7a50EzcUCBF6psJrUkYiZgnZJ7eId8mMeIyhpW5hyLw72LKCXsl86VqwgAKceKapW5e/nZpJnSsuHaTM7muyDq7C63JprJS69YxhNTpSlkpKeLGNHCo0EJChcSNaQA4SGiFtBMXJFSI3YVOPXFB6kMoUl9NaE0Wl4h5KQ0AOwqde+KmNrCL0EKCxJ64qQ0AlYVWSBfXZusgW6Oa0Dni2hiEv0qsoci+yUJrsoikLlKAkP11ygK54taiSOgb/O5b/DMqS+gBZeLWJlnoEX7XwQkBDPIktlEkz7hWrEmxZG4M5L9GXYTk0qxwcopKxa3VABN6cosM/C5LxTUof4ReMKHf1nRlaSnuGsGM7kfU4w8RF5Bz4aNlokLe/HQ/ngl9/Qih4L9k3h4hA1+S3odxu3Q77Hl4r1Hg75n6D01M2Difbp02Mi3ZTk5OLH4BUyEtOlDYuK0AAAAASUVORK5CYII='
: scale > 1
? 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAABVklEQVRYheWX4U3DMBBGH4gBMoJHyAgeoSNkAxjBG5QNOkJHCGzQDcoGZQP4gY3Oqe1cEscS4pNOqs9Jvqvv6ZrCf9fDhnutD4A3H810Br4mcW5l7hLmIdze5mZi+OJD5syeBYzC6CjyR5Ef9zI/CJMb0Im9zufC/qG2eQdchcGQuGYQ+9dJgZvl0B2xbJGrZW6IIevFXp9YVwcyB540syJfFcgSeJb0cVcDcg68XAFQCUhH+ShLBcBGIA158LQFqIB8zBRwEp9fgctcxQld/L2pZxZVAk/KkucjaDGQmoknrz35KEE2sABIRxm8tVIBaZgHb61UQOYmXk7aFgQVJ6QWPCnLAriYAVILnpTxD7yh/9EZiIEE4m+y29uMkGy1nQ6i9wYFRB5PwKdYP/v1msmnUe89gn695bG0iqjdXeMiRu9599csvGKZ0jlu0Ac/7d2rxX9Q37HW6QfX/ZguAAAAAElFTkSuQmCC'
: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAvUlEQVQ4jbWT4Q3CIBCFP40DdANxg24gIzhKuwEjuIFxAkcwTtARGicoG+iPXlMCB8UfvoQc4e7ePV4A/ogWuMlqc0W7AsEo0QMNcPplugMmwMia5KwKWkNIuIkHq3wLXGQ/Sq4IC3wkLpOfmZyKeEpIEKsDYB8VN0Afkfpg30uNiycbdKcNqXEOxdBEWoEAoqta8uZ0iqqkxwGDUrSFAXAHZpOWd/+ubD5Kz335Cx1wZna4Bh54AddauVl8ARfCLO9Xq7xGAAAAAElFTkSuQmCC',
check:
scale > 2
? 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAYAAABXAvmHAAAAqElEQVRoge3YTQ7CIBRF4bPUu/8JS6gTSaqilh95vuR+CaO2cGgYNAUzMzOzFgHlPhRaMkDAcRoltKaTeIxPtQHxGn+Q5AgJx8cQjo8hHB9DOP76Yiu/RcTmN18WLiQCjs3zBkYXVGOeLWd+xcIr5pgyEzDz7FIjISPP/FRPUM+9W4nvYVfuCSXeB3669ldEOzRFfCUSx1cicXwlEsdXIvEPKDMzM7PMbtugw3XTpNA2AAAAAElFTkSuQmCC'
: scale > 1
? 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAf0lEQVRYhe2UvQ2AIBQGL3EBR3AESkv3bxxFN8DmWUgwvkI+En1X0cBd+IMg+DuDyDMCs413kfMiX4EMbD3l8oCaPIU85B4mYLEF5XJscrYFPRGvb/sZ4IlocubJGdH0wj1FSG77XYT0qdUi5O+8jOjyyZQRUnkZ0UUeBMF3OQC/0VsyGlxligAAAABJRU5ErkJggg=='
: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAASElEQVQ4jWNgGJHAgIGBIYESze8ZGBjWU6L5PAMDgwBNNCdAFZJt83qoQmRDSHK2AFQhzBCy/IxsCNkBJsDAwLAfiknWPBIBAETPFeuA4fr6AAAAAElFTkSuQmCC',
loader:
scale > 2
? 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAYAAABXAvmHAAABXElEQVRoge2a3W3DMAyEr+0CHkGjaISOcKN4k6zQETpCR+gGzgbpQ10kcamIpKQ6avQBBPxg3pHwL2UDg/8LASxrcNdKnCwATmssrUyeWgnju/DmXs8tRP+Sh2kgAJga1rFlWj2rcMD5YqQh77QJLbzIORjyRIJQCJW5ngYo5AVlrsgkCGqbsDbAhFfxqZsSZibP0oDXQ43HQPsg82i7sBoR+VcJq2YxKcPo0IoJLRZXmYGC6ezQmQUdVqhPBVH/CNBTSMkLVlzjA8Bbocb7GoPBoADi+umZilYzbrG/JrnljOvy734iu4To/BQaDB6Rl4LciPPF9Lmjhgvi+s7w6tCIGw3WKS0P8fvWNjt0ZkGHFeq7CQXTbkZKGg2JOxrqPUZ3s6ziNdju38IjS/dLi0EQpDLX2gDQYHEX6Hx5/YcA+6H0NgAYPnCMj3x7Mxq4wTGx3Q1E578aDDR8AX0mOGD6BEN/AAAAAElFTkSuQmCC'
: scale > 1
? 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAABN0lEQVRYhe2WzU3EMBCFP34KyJEjJaQDXAIlJJ24BSow2wEdhHSwJSwd7JHbcmC0mOxMnDiWDIInWbHkN29exo4n8IvRAEFGU8OAA04yulyR60Jm7msbyIZloAMGwBfI4UWrWxM08LW/weC4iOMNTog4g0awKjBG827GxBwC3996NHizAifsSrTRmlsZm23CT9adktyXSq6ZUPdxgiXnZzW8CLcLuC3lvqA/gCt5NtjlPQL7TP0Wu1HtRRu4PO3T4TKTz2kG+AG9IN6CR/Su9iojBw69egfghWgL/pGCp+JFVPUqTjWjlsuqeAo1o6rt2C8QcNiV0UxoHPMieojmz0CfMKyhl1hN84xbI3gnz5Ftp7kH3iT5LsFdDUf6pzSJ6r2glIFDbuDNhqRH4I7Pvv4EvG/QqocP2Jh/xzzX/zUAAAAASUVORK5CYII='
: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAsklEQVQ4jaWTYRHCMAyFP7gJmIQ6oChgEpBQKXMwC3MADpAAEiphDuBHC4QuDRu8u9ylyWtem7Rgw2X7GT1wsghb4beAVzhtsfYyJgs44AoEQzBkjrMId1HkKPwyZ6oMSnxYsnk1NqT7yMo34Fzhd9meGJvs7Hh3NhqCLXDI/rT0lKsR+KOJgc9RdaRRarkZvELogYsi8HqxjUhGYE+aQg1jzketwFTZXHbbEpjB8eU7PwAbLiJz46707gAAAABJRU5ErkJggg==',
};
module.exports = YellowBoxImageSource;
@@ -0,0 +1,190 @@
/**
* 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 strict-local
* @format
*/
'use strict';
const Platform = require('Platform');
const React = require('React');
const ScrollView = require('ScrollView');
const StyleSheet = require('StyleSheet');
const Text = require('Text');
const View = require('View');
const YellowBoxCategory = require('YellowBoxCategory');
const YellowBoxInspectorFooter = require('YellowBoxInspectorFooter');
const YellowBoxInspectorHeader = require('YellowBoxInspectorHeader');
const YellowBoxInspectorSourceMapStatus = require('YellowBoxInspectorSourceMapStatus');
const YellowBoxInspectorStackFrame = require('YellowBoxInspectorStackFrame');
const YellowBoxStyle = require('YellowBoxStyle');
const openFileInEditor = require('openFileInEditor');
import type YellowBoxWarning from 'YellowBoxWarning';
import type {SymbolicationRequest} from 'YellowBoxWarning';
type Props = $ReadOnly<{|
onDismiss: () => void,
onMinimize: () => void,
warnings: $ReadOnlyArray<YellowBoxWarning>,
|}>;
type State = {|
selectedIndex: number,
|};
class YellowBoxInspector extends React.Component<Props, State> {
_symbolication: ?SymbolicationRequest;
state = {
selectedIndex: 0,
};
render(): React.Node {
const {warnings} = this.props;
const {selectedIndex} = this.state;
const warning = warnings[selectedIndex];
return (
<View style={styles.root}>
<YellowBoxInspectorHeader
onSelectIndex={this._handleSelectIndex}
selectedIndex={selectedIndex}
warnings={warnings}
/>
<ScrollView
contentContainerStyle={styles.bodyContent}
key={selectedIndex}
style={styles.body}>
<View>
<View style={styles.bodyHeading}>
<Text style={styles.bodyHeadingText}>Warning</Text>
</View>
<Text style={styles.bodyText}>
{YellowBoxCategory.render(
warning.message,
styles.substitutionText,
)}
</Text>
</View>
<View style={styles.bodySection}>
<View style={styles.bodyHeading}>
<Text style={styles.bodyHeadingText}>Stack</Text>
<YellowBoxInspectorSourceMapStatus
status={warning.symbolicated.status}
/>
</View>
{warning.getAvailableStack().map((frame, index) => (
<YellowBoxInspectorStackFrame
key={index}
frame={frame}
onPress={
warning.symbolicated.status === 'COMPLETE'
? () => {
openFileInEditor(frame.file, frame.lineNumber);
}
: null
}
/>
))}
</View>
</ScrollView>
<YellowBoxInspectorFooter
onDismiss={this.props.onDismiss}
onMinimize={this.props.onMinimize}
/>
</View>
);
}
componentDidMount(): void {
this._handleSymbolication();
}
componentDidUpdate(prevProps: Props, prevState: State): void {
if (
prevProps.warnings !== this.props.warnings ||
prevState.selectedIndex !== this.state.selectedIndex
) {
this._cancelSymbolication();
this._handleSymbolication();
}
}
componentWillUnmount(): void {
this._cancelSymbolication();
}
_handleSymbolication(): void {
const warning = this.props.warnings[this.state.selectedIndex];
if (warning.symbolicated.status !== 'COMPLETE') {
this._symbolication = warning.symbolicate(() => {
this.forceUpdate();
});
}
}
_cancelSymbolication(): void {
if (this._symbolication != null) {
this._symbolication.abort();
this._symbolication = null;
}
}
_handleSelectIndex = (selectedIndex: number): void => {
this.setState({selectedIndex});
};
}
const styles = StyleSheet.create({
root: {
elevation: Platform.OS === 'android' ? Number.MAX_SAFE_INTEGER : undefined,
height: '100%',
},
body: {
backgroundColor: YellowBoxStyle.getBackgroundColor(0.95),
borderBottomColor: YellowBoxStyle.getDividerColor(0.95),
borderBottomWidth: StyleSheet.hairlineWidth,
borderTopColor: YellowBoxStyle.getDividerColor(0.95),
borderTopWidth: StyleSheet.hairlineWidth,
flex: 1,
},
bodyContent: {
paddingVertical: 12,
},
bodyHeading: {
alignItems: 'center',
flexDirection: 'row',
marginBottom: 6,
paddingHorizontal: 12,
},
bodyHeadingText: {
color: YellowBoxStyle.getTextColor(1),
flex: 1,
fontSize: 20,
fontWeight: '600',
includeFontPadding: false,
lineHeight: 28,
},
bodyText: {
color: YellowBoxStyle.getTextColor(1),
fontSize: 14,
includeFontPadding: false,
lineHeight: 18,
paddingHorizontal: 12,
},
substitutionText: {
color: YellowBoxStyle.getTextColor(0.6),
},
bodySection: {
marginTop: 20,
},
});
module.exports = YellowBoxInspector;
@@ -0,0 +1,76 @@
/**
* 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 strict-local
* @format
*/
'use strict';
const React = require('React');
const SafeAreaView = require('SafeAreaView');
const StyleSheet = require('StyleSheet');
const Text = require('Text');
const View = require('View');
const YellowBoxPressable = require('YellowBoxPressable');
const YellowBoxStyle = require('YellowBoxStyle');
type Props = $ReadOnly<{|
onDismiss: () => void,
onMinimize: () => void,
|}>;
const YellowBoxInspectorFooter = (props: Props): React.Node => (
<View style={styles.root}>
<YellowBoxPressable
backgroundColor={{
default: 'transparent',
pressed: YellowBoxStyle.getHighlightColor(1),
}}
onPress={props.onMinimize}
style={styles.button}>
<View style={styles.content}>
<Text style={styles.label}>Minimize</Text>
</View>
<SafeAreaView />
</YellowBoxPressable>
<YellowBoxPressable
backgroundColor={{
default: 'transparent',
pressed: YellowBoxStyle.getHighlightColor(1),
}}
onPress={props.onDismiss}
style={styles.button}>
<View style={styles.content}>
<Text style={styles.label}>Dismiss</Text>
</View>
<SafeAreaView />
</YellowBoxPressable>
</View>
);
const styles = StyleSheet.create({
root: {
backgroundColor: YellowBoxStyle.getBackgroundColor(0.95),
flexDirection: 'row',
},
button: {
flex: 1,
},
content: {
alignItems: 'center',
height: 48,
justifyContent: 'center',
},
label: {
color: YellowBoxStyle.getTextColor(1),
fontSize: 14,
includeFontPadding: false,
lineHeight: 18,
},
});
module.exports = YellowBoxInspectorFooter;
@@ -0,0 +1,117 @@
/**
* 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 strict-local
* @format
*/
'use strict';
const Platform = require('Platform');
const React = require('React');
const SafeAreaView = require('SafeAreaView');
const StyleSheet = require('StyleSheet');
const Text = require('Text');
const UTFSequence = require('UTFSequence');
const View = require('View');
const YellowBoxPressable = require('YellowBoxPressable');
const YellowBoxStyle = require('YellowBoxStyle');
import type YellowBoxWarning from 'YellowBoxWarning';
type Props = $ReadOnly<{|
onSelectIndex: (selectedIndex: number) => void,
selectedIndex: number,
warnings: $ReadOnlyArray<YellowBoxWarning>,
|}>;
const YellowBoxInspectorHeader = (props: Props): React.Node => {
const prevIndex = props.selectedIndex - 1;
const nextIndex = props.selectedIndex + 1;
const titleText =
props.warnings.length === 1
? 'Single Occurrence'
: `Occurrence ${props.selectedIndex + 1} of ${props.warnings.length}`;
return (
<SafeAreaView style={styles.root}>
<View style={styles.header}>
<YellowBoxInspectorHeaderButton
disabled={props.warnings[prevIndex] == null}
label={UTFSequence.TRIANGLE_LEFT}
onPress={() => props.onSelectIndex(prevIndex)}
/>
<View style={styles.headerTitle}>
<Text style={styles.headerTitleText}>{titleText}</Text>
</View>
<YellowBoxInspectorHeaderButton
disabled={props.warnings[nextIndex] == null}
label={UTFSequence.TRIANGLE_RIGHT}
onPress={() => props.onSelectIndex(nextIndex)}
/>
</View>
</SafeAreaView>
);
};
const YellowBoxInspectorHeaderButton = (
props: $ReadOnly<{|
disabled: boolean,
label: React.Node,
onPress?: ?() => void,
|}>,
): React.Node => (
<YellowBoxPressable
backgroundColor={{
default: 'transparent',
pressed: YellowBoxStyle.getHighlightColor(1),
}}
onPress={props.disabled ? null : props.onPress}
style={styles.headerButton}>
{props.disabled ? null : (
<Text style={styles.headerButtonText}>{props.label}</Text>
)}
</YellowBoxPressable>
);
const styles = StyleSheet.create({
root: {
backgroundColor: YellowBoxStyle.getBackgroundColor(0.95),
},
header: {
flexDirection: 'row',
height: Platform.select({
android: 48,
ios: 44,
}),
},
headerButton: {
alignItems: 'center',
aspectRatio: 1,
justifyContent: 'center',
},
headerButtonText: {
color: YellowBoxStyle.getTextColor(1),
fontSize: 16,
includeFontPadding: false,
lineHeight: 20,
},
headerTitle: {
alignItems: 'center',
flex: 1,
justifyContent: 'center',
},
headerTitleText: {
color: YellowBoxStyle.getTextColor(1),
fontSize: 16,
fontWeight: '600',
includeFontPadding: false,
lineHeight: 20,
},
});
module.exports = YellowBoxInspectorHeader;
@@ -0,0 +1,149 @@
/**
* 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 Animated = require('Animated');
const Easing = require('Easing');
const React = require('React');
const StyleSheet = require('StyleSheet');
const Text = require('Text');
const View = require('View');
const YellowBoxImageSource = require('YellowBoxImageSource');
const YellowBoxStyle = require('YellowBoxStyle');
import type {CompositeAnimation} from 'AnimatedImplementation';
import type AnimatedInterpolation from 'AnimatedInterpolation';
type Props = $ReadOnly<{|
status: 'COMPLETE' | 'FAILED' | 'NONE' | 'PENDING',
|}>;
type State = {|
animation: ?CompositeAnimation,
rotate: ?AnimatedInterpolation,
|};
class YellowBoxInspectorSourceMapStatus extends React.Component<Props, State> {
state = {
animation: null,
rotate: null,
};
render(): React.Node {
let image;
switch (this.props.status) {
case 'COMPLETE':
image = YellowBoxImageSource.check;
break;
case 'FAILED':
image = YellowBoxImageSource.alertTriangle;
break;
case 'PENDING':
image = YellowBoxImageSource.loader;
break;
}
return image == null ? null : (
<View
style={StyleSheet.compose(
styles.root,
this.props.status === 'PENDING' ? styles.pending : null,
)}>
<Animated.Image
source={{height: 16, uri: image, width: 16}}
style={StyleSheet.compose(
styles.image,
this.state.rotate == null
? null
: {transform: [{rotate: this.state.rotate}]},
)}
/>
<Text style={styles.text}>Source Map</Text>
</View>
);
}
componentDidMount(): void {
this._updateAnimation();
}
componentDidUpdate(): void {
this._updateAnimation();
}
componentWillUnmount(): void {
if (this.state.animation != null) {
this.state.animation.stop();
}
}
_updateAnimation(): void {
if (this.props.status === 'PENDING') {
if (this.state.animation == null) {
const animated = new Animated.Value(0);
const animation = Animated.loop(
Animated.timing(animated, {
duration: 2000,
easing: Easing.linear,
toValue: 1,
useNativeDriver: true,
}),
);
this.setState(
{
animation,
rotate: animated.interpolate({
inputRange: [0, 1],
outputRange: ['0deg', '360deg'],
}),
},
() => {
animation.start();
},
);
}
} else {
if (this.state.animation != null) {
this.state.animation.stop();
this.setState({
animation: null,
rotate: null,
});
}
}
}
}
const styles = StyleSheet.create({
root: {
alignItems: 'center',
backgroundColor: YellowBoxStyle.getTextColor(0.8),
borderRadius: 12,
flexDirection: 'row',
height: 24,
paddingHorizontal: 8,
},
pending: {
backgroundColor: YellowBoxStyle.getTextColor(0.6),
},
image: {
marginEnd: 4,
tintColor: YellowBoxStyle.getBackgroundColor(1),
},
text: {
color: YellowBoxStyle.getBackgroundColor(1),
fontSize: 12,
includeFontPadding: false,
lineHeight: 16,
},
});
module.exports = YellowBoxInspectorSourceMapStatus;
@@ -0,0 +1,81 @@
/**
* 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 strict-local
* @format
*/
'use strict';
const React = require('React');
const StyleSheet = require('StyleSheet');
const Text = require('Text');
const YellowBoxPressable = require('YellowBoxPressable');
const YellowBoxStyle = require('YellowBoxStyle');
import type {PressEvent} from 'CoreEventTypes';
import type {StackFrame} from 'parseErrorStack';
type Props = $ReadOnly<{|
frame: StackFrame,
onPress?: ?(event: PressEvent) => void,
|}>;
const YellowBoxInspectorStackFrame = (props: Props): React.Node => {
const {frame, onPress} = props;
return (
<YellowBoxPressable
backgroundColor={{
default: YellowBoxStyle.getBackgroundColor(0),
pressed: YellowBoxStyle.getHighlightColor(1),
}}
onPress={onPress}
style={styles.frame}>
<Text style={styles.frameName}>{frame.methodName}</Text>
<Text
ellipsizeMode="middle"
numberOfLines={1}
style={styles.frameLocation}>
{`${getFrameLocation(frame.file)}:${frame.lineNumber}${
frame.column == null ? '' : ':' + frame.column
}`}
</Text>
</YellowBoxPressable>
);
};
const getFrameLocation = (uri: string): string => {
const queryIndex = uri.indexOf('?');
const query = queryIndex < 0 ? '' : uri.substr(queryIndex);
const path = queryIndex < 0 ? uri : uri.substr(0, queryIndex);
const file = path.substr(path.lastIndexOf('/') + 1);
return file + query;
};
const styles = StyleSheet.create({
frame: {
paddingHorizontal: 12,
paddingVertical: 4,
},
frameName: {
color: YellowBoxStyle.getTextColor(1),
fontSize: 14,
includeFontPadding: false,
lineHeight: 18,
},
frameLocation: {
color: YellowBoxStyle.getTextColor(0.7),
fontSize: 12,
fontWeight: '300',
includeFontPadding: false,
lineHeight: 16,
},
});
module.exports = YellowBoxInspectorStackFrame;
+142
View File
@@ -0,0 +1,142 @@
/**
* 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 strict-local
* @format
*/
'use strict';
const Dimensions = require('Dimensions');
const React = require('React');
const FlatList = require('FlatList');
const SafeAreaView = require('SafeAreaView');
const StyleSheet = require('StyleSheet');
const View = require('View');
const YellowBoxButton = require('YellowBoxButton');
const YellowBoxInspector = require('YellowBoxInspector');
const YellowBoxListRow = require('YellowBoxListRow');
const YellowBoxStyle = require('YellowBoxStyle');
import type {Category} from 'YellowBoxCategory';
import type {Registry} from 'YellowBoxRegistry';
type Props = $ReadOnly<{|
onDismiss: (category: Category) => void,
onDismissAll: () => void,
registry: Registry,
|}>;
type State = {|
selectedCategory: ?Category,
|};
const VIEWPORT_RATIO = 0.5;
const MAX_ITEMS = Math.floor(
(Dimensions.get('window').height * VIEWPORT_RATIO) /
(YellowBoxListRow.GUTTER + YellowBoxListRow.HEIGHT),
);
class YellowBoxList extends React.Component<Props, State> {
state = {
selectedCategory: null,
};
render(): React.Node {
const selectedWarnings =
this.state.selectedCategory == null
? null
: this.props.registry.get(this.state.selectedCategory);
if (selectedWarnings != null) {
return (
<View style={StyleSheet.absoluteFill}>
<YellowBoxInspector
onDismiss={this._handleInspectorDismiss}
onMinimize={this._handleInspectorMinimize}
warnings={selectedWarnings}
/>
</View>
);
}
const items = [];
for (const [category, warnings] of this.props.registry) {
items.unshift({category, warnings});
}
const listStyle = {
height:
// Additional `0.5` so the (N + 1)th row can peek into view.
Math.min(items.length, MAX_ITEMS + 0.5) *
(YellowBoxListRow.GUTTER + YellowBoxListRow.HEIGHT),
};
return items.length === 0 ? null : (
<View style={styles.list}>
<View pointerEvents="box-none" style={styles.dismissAll}>
<YellowBoxButton
hitSlop={{bottom: 4, left: 4, right: 4, top: 4}}
label="Dismiss All"
onPress={this.props.onDismissAll}
/>
</View>
<FlatList
data={items}
keyExtractor={item => item.category}
renderItem={({item}) => (
<YellowBoxListRow {...item} onPress={this._handleRowPress} />
)}
scrollEnabled={items.length > MAX_ITEMS}
scrollsToTop={false}
style={listStyle}
/>
<SafeAreaView style={styles.safeArea} />
</View>
);
}
_handleInspectorDismiss = () => {
const category = this.state.selectedCategory;
if (category == null) {
return;
}
this.setState({selectedCategory: null}, () => {
this.props.onDismiss(category);
});
};
_handleInspectorMinimize = () => {
this.setState({selectedCategory: null});
};
_handleRowPress = (category: Category) => {
this.setState({selectedCategory: category});
};
}
const styles = StyleSheet.create({
list: {
bottom: 0,
position: 'absolute',
width: '100%',
},
dismissAll: {
bottom: '100%',
flexDirection: 'row',
justifyContent: 'flex-end',
paddingBottom: 4,
paddingEnd: 4,
position: 'absolute',
width: '100%',
},
safeArea: {
backgroundColor: YellowBoxStyle.getBackgroundColor(0.95),
marginTop: StyleSheet.hairlineWidth,
},
});
module.exports = YellowBoxList;
+100
View File
@@ -0,0 +1,100 @@
/**
* 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 strict-local
* @format
*/
'use strict';
const React = require('React');
const StyleSheet = require('StyleSheet');
const Text = require('Text');
const YellowBoxPressable = require('YellowBoxPressable');
const View = require('View');
const YellowBoxCategory = require('YellowBoxCategory');
const YellowBoxStyle = require('YellowBoxStyle');
const YellowBoxWarning = require('YellowBoxWarning');
import type {Category} from 'YellowBoxCategory';
type Props = $ReadOnly<{|
category: Category,
warnings: $ReadOnlyArray<YellowBoxWarning>,
onPress: (category: Category) => void,
|}>;
class YellowBoxListRow extends React.Component<Props> {
static GUTTER = StyleSheet.hairlineWidth;
static HEIGHT = 48;
shouldComponentUpdate(nextProps: Props): boolean {
const prevProps = this.props;
return (
prevProps.category !== nextProps.category ||
prevProps.onPress !== nextProps.onPress ||
prevProps.warnings.length !== nextProps.warnings.length ||
prevProps.warnings.some(
(prevWarning, index) => prevWarning !== nextProps[index],
)
);
}
render(): React.Node {
const {warnings} = this.props;
return (
<YellowBoxPressable onPress={this._handlePress} style={styles.root}>
<View style={styles.content}>
{warnings.length < 2 ? null : (
<Text style={styles.metaText}>{'(' + warnings.length + ') '}</Text>
)}
<Text numberOfLines={2} style={styles.bodyText}>
{YellowBoxCategory.render(
warnings[warnings.length - 1].message,
styles.substitutionText,
)}
</Text>
</View>
</YellowBoxPressable>
);
}
_handlePress = () => {
this.props.onPress(this.props.category);
};
}
const styles = StyleSheet.create({
root: {
height: YellowBoxListRow.HEIGHT,
justifyContent: 'center',
marginTop: YellowBoxListRow.GUTTER,
paddingHorizontal: 12,
},
content: {
alignItems: 'flex-start',
flexDirection: 'row',
},
bodyText: {
color: YellowBoxStyle.getTextColor(1),
flex: 1,
fontSize: 14,
includeFontPadding: false,
lineHeight: 18,
},
metaText: {
color: YellowBoxStyle.getTextColor(0.5),
fontSize: 14,
includeFontPadding: false,
lineHeight: 18,
},
substitutionText: {
color: YellowBoxStyle.getTextColor(0.6),
},
});
module.exports = YellowBoxListRow;
@@ -0,0 +1,86 @@
/**
* 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 strict-local
* @format
*/
'use strict';
const React = require('React');
const StyleSheet = require('StyleSheet');
const TouchableWithoutFeedback = require('TouchableWithoutFeedback');
const View = require('View');
const YellowBoxStyle = require('YellowBoxStyle');
import type {PressEvent} from 'CoreEventTypes';
import type {EdgeInsetsProp} from 'EdgeInsetsPropType';
import type {ViewStyleProp} from 'StyleSheet';
type Props = $ReadOnly<{|
backgroundColor: $ReadOnly<{|
default: string,
pressed: string,
|}>,
children?: React.Node,
hitSlop?: ?EdgeInsetsProp,
onPress?: ?(event: PressEvent) => void,
style?: ViewStyleProp,
|}>;
type State = {|
pressed: boolean,
|};
class YellowBoxPressable extends React.Component<Props, State> {
static defaultProps = {
backgroundColor: {
default: YellowBoxStyle.getBackgroundColor(0.95),
pressed: YellowBoxStyle.getHighlightColor(1),
},
};
state = {
pressed: false,
};
render(): React.Node {
const content = (
<View
style={StyleSheet.compose(
{
backgroundColor: this.state.pressed
? this.props.backgroundColor.pressed
: this.props.backgroundColor.default,
},
this.props.style,
)}>
{this.props.children}
</View>
);
return this.props.onPress == null ? (
content
) : (
<TouchableWithoutFeedback
hitSlop={this.props.hitSlop}
onPress={this.props.onPress}
onPressIn={this._handlePressIn}
onPressOut={this._handlePressOut}>
{content}
</TouchableWithoutFeedback>
);
}
_handlePressIn = () => {
this.setState({pressed: true});
};
_handlePressOut = () => {
this.setState({pressed: false});
};
}
module.exports = YellowBoxPressable;
+31
View File
@@ -0,0 +1,31 @@
/**
* 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 strict-local
* @format
*/
'use strict';
const YellowBoxStyle = {
getBackgroundColor(opacity: number): string {
return `rgba(250, 186, 48, ${opacity})`;
},
getDividerColor(opacity: number): string {
return `rgba(255, 255, 255, ${opacity})`;
},
getHighlightColor(opacity: number): string {
return `rgba(252, 176, 29, ${opacity})`;
},
getTextColor(opacity: number): string {
return `rgba(255, 255, 255, ${opacity})`;
},
};
module.exports = YellowBoxStyle;
+156
View File
@@ -0,0 +1,156 @@
/**
* 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 React = require('React');
import type {Category} from 'YellowBoxCategory';
import type {Registry, Subscription} from 'YellowBoxRegistry';
type Props = $ReadOnly<{||}>;
type State = {|
registry: ?Registry,
|};
let YellowBox;
/**
* YellowBox displays warnings at the bottom of the screen.
*
* Warnings help guard against subtle yet significant issues that can impact the
* quality of the app. This "in your face" style of warning allows developers to
* notice and correct these issues as quickly as possible.
*
* YellowBox is only enabled in `__DEV__`. Set the following flag to disable it:
*
* console.disableYellowBox = true;
*
* Ignore specific warnings by calling:
*
* YellowBox.ignoreWarnings(['Warning: ...']);
*
* Strings supplied to `YellowBox.ignoreWarnings` only need to be a substring of
* the ignored warning messages.
*/
if (__DEV__) {
const Platform = require('Platform');
const RCTLog = require('RCTLog');
const YellowBoxList = require('YellowBoxList');
const YellowBoxRegistry = require('YellowBoxRegistry');
const {error, warn} = console;
// eslint-disable-next-line no-shadow
YellowBox = class YellowBox extends React.Component<Props, State> {
static ignoreWarnings(patterns: $ReadOnlyArray<string>): void {
YellowBoxRegistry.addIgnorePatterns(patterns);
}
static install(): void {
(console: any).error = function(...args) {
error.call(console, ...args);
// Show YellowBox for the `warning` module.
if (typeof args[0] === 'string' && args[0].startsWith('Warning: ')) {
registerWarning(...args);
}
};
(console: any).warn = function(...args) {
warn.call(console, ...args);
registerWarning(...args);
};
if ((console: any).disableYellowBox === true) {
YellowBoxRegistry.setDisabled(true);
}
(Object.defineProperty: any)(console, 'disableYellowBox', {
configurable: true,
get: () => YellowBoxRegistry.isDisabled(),
set: value => YellowBoxRegistry.setDisabled(value),
});
if (Platform.isTesting) {
(console: any).disableYellowBox = true;
}
RCTLog.setWarningHandler((...args) => {
registerWarning(...args);
});
}
static uninstall(): void {
(console: any).error = error;
(console: any).warn = error;
delete (console: any).disableYellowBox;
}
_subscription: ?Subscription;
state = {
registry: null,
};
render(): React.Node {
// TODO: Ignore warnings that fire when rendering `YellowBox` itself.
return this.state.registry == null ? null : (
<YellowBoxList
onDismiss={this._handleDismiss}
onDismissAll={this._handleDismissAll}
registry={this.state.registry}
/>
);
}
componentDidMount(): void {
this._subscription = YellowBoxRegistry.observe(registry => {
this.setState({registry});
});
}
componentWillUnmount(): void {
if (this._subscription != null) {
this._subscription.unsubscribe();
}
}
_handleDismiss = (category: Category): void => {
YellowBoxRegistry.delete(category);
};
_handleDismissAll(): void {
YellowBoxRegistry.clear();
}
};
const registerWarning = (...args): void => {
YellowBoxRegistry.add({args, framesToPop: 2});
};
} else {
YellowBox = class extends React.Component<Props> {
static ignoreWarnings(patterns: $ReadOnlyArray<string>): void {
// Do nothing.
}
static install(): void {
// Do nothing.
}
static uninstall(): void {
// Do nothing.
}
render(): React.Node {
return null;
}
};
}
module.exports = YellowBox;
@@ -0,0 +1,77 @@
/**
* 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.
*
* @emails oncall+react_native
* @format
* @flow
*/
'use strict';
const YellowBox = require('YellowBox');
const YellowBoxRegistry = require('YellowBoxRegistry');
describe('YellowBox', () => {
const {error, warn} = console;
beforeEach(() => {
jest.resetModules();
(console: any).error = jest.fn();
(console: any).warn = jest.fn();
});
afterEach(() => {
YellowBox.uninstall();
(console: any).error = error;
(console: any).warn = warn;
});
it('can set `disableYellowBox` after installing', () => {
expect((console: any).disableYellowBox).toBe(undefined);
YellowBox.install();
expect((console: any).disableYellowBox).toBe(false);
expect(YellowBoxRegistry.isDisabled()).toBe(false);
(console: any).disableYellowBox = true;
expect((console: any).disableYellowBox).toBe(true);
expect(YellowBoxRegistry.isDisabled()).toBe(true);
});
it('can set `disableYellowBox` before installing', () => {
expect((console: any).disableYellowBox).toBe(undefined);
(console: any).disableYellowBox = true;
YellowBox.install();
expect((console: any).disableYellowBox).toBe(true);
expect(YellowBoxRegistry.isDisabled()).toBe(true);
});
it('registers warnings', () => {
jest.mock('YellowBoxRegistry');
YellowBox.install();
expect(YellowBoxRegistry.add).not.toBeCalled();
(console: any).warn('...');
expect(YellowBoxRegistry.add).toBeCalled();
});
it('registers errors beginning with "Warning: "', () => {
jest.mock('YellowBoxRegistry');
YellowBox.install();
(console: any).error('...');
expect(YellowBoxRegistry.add).not.toBeCalled();
(console: any).error('Warning: ...');
expect(YellowBoxRegistry.add).toBeCalled();
});
});
+3 -3
View File
@@ -84,8 +84,8 @@ def enableSeparateBuildPerCPUArchitecture = false
def enableProguardInReleaseBuilds = false
android {
compileSdkVersion 23
buildToolsVersion "23.0.1"
compileSdkVersion 26
buildToolsVersion "26.0.3"
defaultConfig {
applicationId "com.facebook.react.uiapp"
@@ -137,7 +137,7 @@ android {
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
compile 'com.android.support:appcompat-v7:23.0.1'
compile 'com.android.support:appcompat-v7:26.1.0'
// Build React Native from source
compile project(':ReactAndroid')
+3
View File
@@ -98,6 +98,9 @@ void RCTVerifyAllModulesExported(NSArray *extraModules)
for (unsigned int i = 0; i < classCount; i++) {
Class cls = classes[i];
if (strncmp(class_getName(cls), "RCTCxxModule", strlen("RCTCxxModule")) == 0) {
continue;
}
Class superclass = cls;
while (superclass) {
if (class_conformsToProtocol(superclass, @protocol(RCTBridgeModule))) {
+2 -2
View File
@@ -21,8 +21,8 @@ static void __makeVersion()
{
__rnVersion = @{
RCTVersionMajor: @(0),
RCTVersionMinor: @(0),
RCTVersionPatch: @(0),
RCTVersionMinor: @(56),
RCTVersionPatch: @(1),
RCTVersionPrerelease: [NSNull null],
};
}
+3
View File
@@ -871,6 +871,9 @@ RCT_NOT_IMPLEMENTED(- (instancetype)initWithBundleURL:(__unused NSURL *)bundleUR
- (void)reload
{
if (!_valid) {
RCTLogError(@"Attempting to reload bridge before it's valid: %@. Try restarting the development server if connected.", self);
}
[_parentBridge reload];
}
+5
View File
@@ -53,6 +53,11 @@ using namespace facebook::react;
return self;
}
- (void)dealloc
{
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
- (void)schedulerDidComputeMutationInstructions:(facebook::react::TreeMutationInstructionList)instructions rootTag:(ReactTag)rootTag
{
[_mountingManager mutateComponentViewTreeWithMutationInstructions:instructions
+2
View File
@@ -81,6 +81,8 @@
- (void)dealloc
{
[[NSNotificationCenter defaultCenter] removeObserver:self];
[self _stop];
}
+7 -7
View File
@@ -24,7 +24,7 @@ def thirdPartyNdkDir = new File("$buildDir/third-party-ndk")
// - boost_1_63_0
// - double-conversion-1.1.1
// - folly-deprecate-dynamic-initializer
// - glog-0.3.3
// - glog-0.3.5
// - jsc-headers
def dependenciesPath = System.getenv("REACT_NATIVE_DEPENDENCIES")
@@ -89,10 +89,10 @@ task prepareFolly(dependsOn: dependenciesPath ? [] : [downloadFolly], type: Copy
}
task downloadGlog(dependsOn: createNativeDepsDirectories, type: Download) {
src 'https://github.com/google/glog/archive/v0.3.3.tar.gz'
src 'https://github.com/google/glog/archive/v0.3.5.tar.gz'
onlyIfNewer true
overwrite false
dest new File(downloadsDir, 'glog-0.3.3.tar.gz')
dest new File(downloadsDir, 'glog-0.3.5.tar.gz')
}
// Prepare glog sources to be compiled, this task will perform steps that normally should've been
@@ -100,7 +100,7 @@ task downloadGlog(dependsOn: createNativeDepsDirectories, type: Download) {
task prepareGlog(dependsOn: dependenciesPath ? [] : [downloadGlog], type: Copy) {
from dependenciesPath ?: tarTree(downloadGlog.dest)
from 'src/main/jni/third-party/glog/'
include 'glog-0.3.3/src/**/*', 'Android.mk', 'config.h'
include 'glog-0.3.5/src/**/*', 'Android.mk', 'config.h'
includeEmptyDirs = false
filesMatching('**/*.h.in') {
filter(ReplaceTokens, tokens: [
@@ -245,8 +245,8 @@ task packageReactNdkLibsForBuck(dependsOn: packageReactNdkLibs, type: Copy) {
}
android {
compileSdkVersion 23
buildToolsVersion "23.0.1"
compileSdkVersion 26
buildToolsVersion "26.0.3"
defaultConfig {
minSdkVersion 16
@@ -295,7 +295,7 @@ android {
dependencies {
compile fileTree(dir: 'src/main/third-party/java/infer-annotations/', include: ['*.jar'])
compile 'javax.inject:javax.inject:1'
compile 'com.android.support:appcompat-v7:23.0.1'
compile 'com.android.support:appcompat-v7:26.1.0'
compile 'com.facebook.fbui.textlayoutbuilder:textlayoutbuilder:1.0.0'
compile 'com.facebook.fresco:fresco:1.9.0'
compile 'com.facebook.fresco:imagepipeline-okhttp3:1.9.0'
+1 -1
View File
@@ -1,4 +1,4 @@
VERSION_NAME=1000.0.0-master
VERSION_NAME=0.56.1
GROUP=com.facebook.react
POM_NAME=ReactNative
+2 -2
View File
@@ -6,8 +6,8 @@ android_prebuilt_aar(
remote_file(
name = "appcompat-binary-aar",
sha1 = "7d659f671541394a8bc2b9f909950aa2a5ec87ff",
url = "mvn:com.android.support:appcompat-v7:aar:23.0.1",
sha1 = "da5771a9ac6e8f3a461360eed3c6f921dc7580fd",
url = "mvn:com.android.support:appcompat-v7:aar:26.1.0",
)
android_prebuilt_aar(
@@ -19,9 +19,11 @@ import com.facebook.react.modules.core.PermissionAwareActivity;
import com.facebook.react.modules.core.PermissionListener;
/**
* Base Activity for React Native applications. Like {@link ReactActivity} but extends
* {@link FragmentActivity} instead of {@link android.app.Activity}.
* @deprecated
* ReactFragmentActivity will be removed in 0.57 release.
* Use {@link ReactActivity} instead.
*/
@Deprecated
public abstract class ReactFragmentActivity extends FragmentActivity implements
DefaultHardwareBackBtnHandler, PermissionAwareActivity {
@@ -86,9 +86,9 @@ public class PermissionsModule extends ReactContextBaseJavaModule implements Per
}
/**
* Request the given permission. successCallback is called with true if the permission had been
* granted, false otherwise. For devices before Android M, this instead checks if the user has
* the permission given or not.
* Request the given permission. successCallback is called with GRANTED if the permission had been
* granted, DENIED or NEVER_ASK_AGAIN otherwise. For devices before Android M, this checks if the user has
* the permission given or not and resolves with GRANTED or DENIED.
* See {@link Activity#checkSelfPermission}.
*/
@ReactMethod
@@ -96,7 +96,7 @@ public class PermissionsModule extends ReactContextBaseJavaModule implements Per
Context context = getReactApplicationContext().getBaseContext();
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
promise.resolve(context.checkPermission(permission, Process.myPid(), Process.myUid()) ==
PackageManager.PERMISSION_GRANTED);
PackageManager.PERMISSION_GRANTED ? GRANTED : DENIED);
return;
}
if (context.checkSelfPermission(permission) == PackageManager.PERMISSION_GRANTED) {
@@ -16,7 +16,7 @@ import java.util.Map;
public class ReactNativeVersion {
public static final Map<String, Object> VERSION = MapBuilder.<String, Object>of(
"major", 0,
"minor", 0,
"patch", 0,
"minor", 56,
"patch", 1,
"prerelease", null);
}
@@ -119,7 +119,7 @@ public abstract class ReactBaseTextShadowNode extends LayoutShadowNode {
start, end, new BackgroundColorSpan(textShadowNode.mBackgroundColor)));
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
if (textShadowNode.mLetterSpacing != Float.NaN) {
if (!Float.isNaN(textShadowNode.mLetterSpacing)) {
ops.add(new SetSpanOperation(
start,
end,
@@ -70,8 +70,9 @@ public class ReactTextInputManager extends BaseViewManager<ReactEditText, Layout
private static final int BLUR_TEXT_INPUT = 2;
private static final int INPUT_TYPE_KEYBOARD_NUMBER_PAD = InputType.TYPE_CLASS_NUMBER;
private static final int INPUT_TYPE_KEYBOARD_NUMBERED = INPUT_TYPE_KEYBOARD_NUMBER_PAD |
InputType.TYPE_NUMBER_FLAG_DECIMAL |
private static final int INPUT_TYPE_KEYBOARD_DECIMAL_PAD = INPUT_TYPE_KEYBOARD_NUMBER_PAD |
InputType.TYPE_NUMBER_FLAG_DECIMAL;
private static final int INPUT_TYPE_KEYBOARD_NUMBERED = INPUT_TYPE_KEYBOARD_DECIMAL_PAD |
InputType.TYPE_NUMBER_FLAG_SIGNED;
private static final int PASSWORD_VISIBILITY_FLAG = InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD &
~InputType.TYPE_TEXT_VARIATION_PASSWORD;
@@ -82,6 +83,7 @@ public class ReactTextInputManager extends BaseViewManager<ReactEditText, Layout
private static final String KEYBOARD_TYPE_EMAIL_ADDRESS = "email-address";
private static final String KEYBOARD_TYPE_NUMERIC = "numeric";
private static final String KEYBOARD_TYPE_DECIMAL_PAD = "decimal-pad";
private static final String KEYBOARD_TYPE_NUMBER_PAD = "number-pad";
private static final String KEYBOARD_TYPE_PHONE_PAD = "phone-pad";
private static final String KEYBOARD_TYPE_VISIBLE_PASSWORD = "visible-password";
@@ -567,6 +569,8 @@ public class ReactTextInputManager extends BaseViewManager<ReactEditText, Layout
flagsToSet = INPUT_TYPE_KEYBOARD_NUMBERED;
} else if (KEYBOARD_TYPE_NUMBER_PAD.equalsIgnoreCase(keyboardType)) {
flagsToSet = INPUT_TYPE_KEYBOARD_NUMBER_PAD;
} else if (KEYBOARD_TYPE_DECIMAL_PAD.equalsIgnoreCase(keyboardType)) {
flagsToSet = INPUT_TYPE_KEYBOARD_DECIMAL_PAD;
} else if (KEYBOARD_TYPE_EMAIL_ADDRESS.equalsIgnoreCase(keyboardType)) {
flagsToSet = InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS | InputType.TYPE_CLASS_TEXT;
} else if (KEYBOARD_TYPE_PHONE_PAD.equalsIgnoreCase(keyboardType)) {
+1 -1
View File
@@ -1,7 +1,7 @@
APP_BUILD_SCRIPT := Android.mk
APP_ABI := armeabi-v7a x86
APP_PLATFORM := android-9
APP_PLATFORM := android-16
APP_MK_DIR := $(dir $(lastword $(MAKEFILE_LIST)))
+9 -9
View File
@@ -3,17 +3,17 @@ LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_SRC_FILES := \
glog-0.3.3/src/demangle.cc \
glog-0.3.3/src/logging.cc \
glog-0.3.3/src/raw_logging.cc \
glog-0.3.3/src/signalhandler.cc \
glog-0.3.3/src/symbolize.cc \
glog-0.3.3/src/utilities.cc \
glog-0.3.3/src/vlog_is_on.cc
glog-0.3.5/src/demangle.cc \
glog-0.3.5/src/logging.cc \
glog-0.3.5/src/raw_logging.cc \
glog-0.3.5/src/signalhandler.cc \
glog-0.3.5/src/symbolize.cc \
glog-0.3.5/src/utilities.cc \
glog-0.3.5/src/vlog_is_on.cc
LOCAL_C_INCLUDES += $(LOCAL_PATH) $(LOCAL_PATH)/.. $(LOCAL_PATH)/glog-0.3.3/src/
LOCAL_C_INCLUDES += $(LOCAL_PATH) $(LOCAL_PATH)/.. $(LOCAL_PATH)/glog-0.3.5/src/
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/.. $(LOCAL_PATH)/glog-0.3.3/src/
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/.. $(LOCAL_PATH)/glog-0.3.5/src/
LOCAL_CFLAGS += \
-Wall \
+6 -3
View File
@@ -49,6 +49,9 @@
/* define if the compiler implements namespaces */
#define HAVE_NAMESPACES 1
/* NDK android-16 provides ssize_t pread(int, void*, size_t, off_t) */
#define HAVE_PREAD 1
/* Define if you have POSIX threads libraries and header files. */
#define HAVE_PTHREAD 1
@@ -132,7 +135,7 @@
#define PACKAGE_NAME "glog"
/* Define to the full name and version of this package. */
#define PACKAGE_STRING "glog 0.3.3"
#define PACKAGE_STRING "glog 0.3.5"
/* Define to the one symbol short name of this package. */
#define PACKAGE_TARNAME "glog"
@@ -141,7 +144,7 @@
#define PACKAGE_URL ""
/* Define to the version of this package. */
#define PACKAGE_VERSION "0.3.3"
#define PACKAGE_VERSION "0.3.5"
/* How to access the PC from a struct ucontext */
/* #undef PC_FROM_UCONTEXT */
@@ -163,7 +166,7 @@
#define TEST_SRC_DIR "."
/* Version number of package */
#define VERSION "0.3.3"
#define VERSION "0.3.5"
/* Stops putting the code inside the Google namespace */
#define _END_GOOGLE_NAMESPACE_ }
@@ -6,6 +6,6 @@ prebuilt_jar(
remote_file(
name = "support-annotations-binary-aar",
sha1 = "1fce89a6428c51467090d7f424e4c9c3dbd55f7e",
url = "mvn:com.android.support:support-annotations:jar:23.0.1",
sha1 = "0814258103cf26a15fcc26ecce35f5b7d24b73f8",
url = "mvn:com.android.support:support-annotations:jar:26.1.0",
)
+97 -6
View File
@@ -1,11 +1,102 @@
android_prebuilt_aar(
android_library(
name = "lib-support-v4",
aar = ":lib-support-v4-binary-aar",
exported_deps = [
":lib-support-v4-support-compat",
":lib-support-v4-support-core-utils",
":lib-support-v4-support-core-ui",
":lib-support-v4-support-media-compat",
":lib-support-v4-support-fragment",
":android-lifecycle-runtime",
":android-lifecycle-common.jar",
":android-lifecycle-core.jar"
],
visibility = ["PUBLIC"],
)
remote_file(
name = "lib-support-v4-binary-aar",
sha1 = "9e8da0e4ecf9f63258c7fbd273889252cba2d0c3",
url = "mvn:com.android.support:support-v4:aar:23.0.1",
prebuilt_jar(
name = "android-lifecycle-common.jar",
binary_jar = ":android-lifecycle-common-jar"
)
prebuilt_jar(
name = "android-lifecycle-core.jar",
binary_jar = ":android-lifecycle-core-jar"
)
android_prebuilt_aar(
name = "android-lifecycle-runtime",
aar = ":android-lifecycle-runtime-aar",
)
android_prebuilt_aar(
name = "lib-support-v4-support-compat",
aar = ":lib-support-v4-support-compat-aar",
)
android_prebuilt_aar(
name = "lib-support-v4-support-core-utils",
aar = ":lib-support-v4-support-core-utils-aar",
)
android_prebuilt_aar(
name = "lib-support-v4-support-core-ui",
aar = ":lib-support-v4-support-core-ui-aar",
)
android_prebuilt_aar(
name = "lib-support-v4-support-media-compat",
aar = ":lib-support-v4-support-media-compat-aar",
)
android_prebuilt_aar(
name = "lib-support-v4-support-fragment",
aar = ":lib-support-v4-support-fragment-aar",
)
remote_file(
name = "android-lifecycle-runtime-aar",
sha1 = "30c60a8a357ee1321ffd0c9f08ef54b24045cd10",
url = "mvn:android.arch.lifecycle:runtime:aar:1.0.0"
)
remote_file(
name = "android-lifecycle-common-jar",
sha1 = "e414a4cb28434e25c4f6aa71426eb20cf4874ae9",
url = "mvn:android.arch.lifecycle:common:jar:1.0.0"
)
remote_file(
name = "android-lifecycle-core-jar",
sha1 = "a2d487452376193fc8c103dd2b9bd5f2b1b44563",
url = "mvn:android.arch.core:common:jar:1.0.0"
)
remote_file(
name = "lib-support-v4-support-compat-aar",
sha1 = "1e1c8ffc01d277d8f01dfd11d5d2ce3a2af4b98c",
url = "mvn:com.android.support:support-compat:aar:26.1.0",
)
remote_file(
name = "lib-support-v4-support-core-utils-aar",
sha1 = "1bfaae21c4d5c5532c5e732071e9ce234cd58cff",
url = "mvn:com.android.support:support-core-utils:aar:26.1.0",
)
remote_file(
name = "lib-support-v4-support-core-ui-aar",
sha1 = "e306308d54052a1ded7bf9c2f5c2fdf5152a1f22",
url = "mvn:com.android.support:support-core-ui:aar:26.1.0",
)
remote_file(
name = "lib-support-v4-support-media-compat-aar",
sha1 = "09fb587f27cde19aa8f2e50c5c9ee645d9aec44d",
url = "mvn:com.android.support:support-media-compat:aar:26.1.0",
)
remote_file(
name = "lib-support-v4-support-fragment-aar",
sha1 = "ddacf369bb98dd6558606558de8ddcd53895cf91",
url = "mvn:com.android.support:support-fragment:aar:26.1.0",
)
@@ -56,6 +56,6 @@ python_binary(
remote_file(
name = "appcompat-binary-aar",
sha1 = "7d659f671541394a8bc2b9f909950aa2a5ec87ff",
url = "mvn:com.android.support:appcompat-v7:aar:23.0.1",
sha1 = "da5771a9ac6e8f3a461360eed3c6f921dc7580fd",
url = "mvn:com.android.support:appcompat-v7:aar:26.1.0",
)
@@ -231,6 +231,8 @@ public class ReactTextInputPropertyTest {
@Test
public void testKeyboardType() {
ReactEditText view = mManager.createViewInstance(mThemedContext);
int numberPadTypeFlags = InputType.TYPE_CLASS_NUMBER;
int decimalPadTypeFlags = InputType.TYPE_CLASS_NUMBER | InputType.TYPE_NUMBER_FLAG_DECIMAL;
int numericTypeFlags =
InputType.TYPE_CLASS_NUMBER | InputType.TYPE_NUMBER_FLAG_DECIMAL |
InputType.TYPE_NUMBER_FLAG_SIGNED;
@@ -249,6 +251,12 @@ public class ReactTextInputPropertyTest {
mManager.updateProperties(view, buildStyles("keyboardType", "text"));
assertThat(view.getInputType() & generalKeyboardTypeFlags).isEqualTo(InputType.TYPE_CLASS_TEXT);
mManager.updateProperties(view, buildStyles("keyboardType", "number-pad"));
assertThat(view.getInputType() & generalKeyboardTypeFlags).isEqualTo(numberPadTypeFlags);
mManager.updateProperties(view, buildStyles("keyboardType", "decimal-pad"));
assertThat(view.getInputType() & generalKeyboardTypeFlags).isEqualTo(decimalPadTypeFlags);
mManager.updateProperties(view, buildStyles("keyboardType", "numeric"));
assertThat(view.getInputType() & generalKeyboardTypeFlags).isEqualTo(numericTypeFlags);
+31 -55
View File
@@ -14,14 +14,10 @@ React Native follows a monthly release train. Every month, a new branch created
| 0.40.0 | 1st of December | 1st of January |
| 0.41.0 | 1st of January | 1st of February |
| 0.42.0 | 1st of February | 1st of March |
| 0.43.0 | 1st of March | 1st of April |
| 0.44.0 | 1st of April | 1st of May |
| 0.45.0 | 1st of May | 1st of June |
| 0.46.0 | 1st of June | 1st of July |
| 0.47.0 | 1st of July | 1st of August |
| 0.48.0 | 1st of August | 1st of September |
| 0.49.0 | 1st of September | 1st of October |
| 0.50.0 | 1st of October | 1st of November |
| ... | ... | ... |
| 0.56.0 | 1st of June | 1st of July |
| 0.57.0 | 1st of July | 1st of August |
| 0.58.0 | 1st of August | 1st of October |
| ... | ... | ... |
-------------------
@@ -31,15 +27,16 @@ React Native follows a monthly release train. Every month, a new branch created
### Prerequisites
The following are required for the local test suite to run:
- macOS with [Android dev environment set up](https://github.com/facebook/react-native/blob/master/ReactAndroid/README.md)
- At least 0.2.0 [react-native-cli](https://www.npmjs.com/package/react-native-cli) installed globally
- [react-native-cli](https://www.npmjs.com/package/react-native-cli) installed globally (v0.2.0 or newer)
### Step 1: Check everything works
Before cutting a release branch, make sure [Circle](https://circleci.com/gh/facebook/react-native) CI system is green.
Before executing the following script, make sure you have:
- An Android emulator / Genymotion device running
- No packager running in any of the projects
@@ -57,18 +54,14 @@ Run:
```bash
git checkout -b <version_you_are_releasing>-stable
# e.g. git checkout -b 0.50-stable
# e.g. git checkout -b 0.57-stable
./scripts/bump-oss-version.js <exact-version_you_are_releasing>
# e.g. ./scripts/bump-oss-version.js 0.50.0-rc
# You can use the --remote option to specify a Git remote other than the default "origin"
git push --tags
git push
./scripts/bump-oss-version.js <exact_version_you_are_releasing>
# e.g. ./scripts/bump-oss-version.js 0.57.0-rc.0
# or ./scripts/bump-oss-version.js 0.58.0
```
Circle CI will automatically run the tests and publish to npm with the version you have specified (e.g `0.50.0-rc`) and tag `next` meaning that this version will not be installed for users by default.
Go to [Circle CI](https://circleci.com/gh/facebook/react-native) and look for the build triggered by your push (e.g. _0.50-stable, [0.50.0] Bump version numbers_), then scroll down to the npm publish step to verify the package was published successfully (the build will be red if not).
Circle CI will automatically run the tests and publish to npm with the version you have specified (e.g `0.57.0-rc.0`) and tag `next` meaning that this version will not be installed for users by default.
### Step 3: Write the release notes
@@ -89,7 +82,9 @@ Sometimes commit messages might be really short / confusing - try rewording them
- `Fix logging reported by RUN_JS_BUNDLE` -> `Fix systrace logging of RUN_JS_BUNDLE event`
- `Fixes hot code reloading issue` -> `Fix an edge case in hot module reloading`
Before posting the list of changes, consider asking one of contributors for their opinion. Once everything is ready, post the release notes: https://github.com/facebook/react-native/releases
Open a pull request against CHANGELOG.md at https://github.com/react-native-community/react-native-releases and ask for feedback.
Once everything is ready, create a new release at https://github.com/facebook/react-native/releases and link to the release notes.
**Important**: For release candidate releases, make sure to check "This is a pre-release".
@@ -109,7 +104,7 @@ Now that the release is out in the open, go ahead and create a GitHub issue titl
-------------------
## How to release an RC update (e.g. 0.50.0-rc.1, 0.50.0-rc.2)
## How to release an RC update (e.g. 0.57.0-rc.1, 0.57.0-rc.2)
The release is now in the open, people are finding bugs, and fixes have landed in master. People have been nominating fixes in the issue you created above. Use your best judgment to decide which commits merit an RC update. It's a good idea to do a new RC release when several small and non-risky bugs have been fixed. Having a few RC releases can also help people bisect in case we cherry-pick a bad commit by mistake.
@@ -122,10 +117,10 @@ Follow these steps to check out the release branch:
```bash
git checkout <version_you_are_patching>-stable
# e.g. git checkout 0.50-stable
# e.g. git checkout 0.57-stable
git pull origin <version_you_are_patching>-stable
# e.g. git pull origin 0.50-stable
# e.g. git pull origin 0.57-stable
```
> If you don't have a local checkout of the release branch, you can run the following instead:
@@ -153,40 +148,31 @@ If everything worked, run the following to bump the version number:
```bash
./scripts/bump-oss-version.js <exact_version_you_are_releasing>
# e.g. ./scripts/bump-oss-version.js 0.50.0-rc.1
# e.g. ./scripts/bump-oss-version.js 0.57.0-rc.1
```
### Step 5: Push to GitHub
Again, Circle CI will automatically run the tests and publish to npm with the version you have specified (e.g `0.57.0-rc.1`).
Finally, push the new tags and commits to GitHub:
### Step 5: Update the release notes
```
git push --tags
git push
````
Again, Circle CI will automatically run the tests and publish to npm with the version you have specified (e.g `0.50.0-rc.1`).
### Step 6: Update the release notes
Go to https://github.com/facebook/react-native/releases and find the release notes for this release candidate. Edit them so that they now point to the tag that you've just created. We want single release notes per version. For example, if there is v0.50.0-rc and you just released v0.50.0-rc.1, the release notes should live on the v0.50.0-rc.1 tag at https://github.com/facebook/react-native/tags
Go to https://github.com/facebook/react-native/releases and find the release notes for this release candidate. Edit them so that they now point to the tag that you've just created. We want single release notes per version. For example, if there is v0.57.0-rc and you just released v0.57.0-rc.1, the release notes should live on the v0.57.0-rc.1 tag at https://github.com/facebook/react-native/tags
-------------------
## How to do the final stable release (e.g. 0.50.0, 0.50.1)
## How to do the final stable release (e.g. 0.57.0, 0.57.1)
A stable release is promoted roughly a month after the release branch is cut (refer to the schedule above). The release may be delayed for several reasons, including major issues in the release candidate. Make sure that all bug fixes that have been nominated in your tracking issue have been addressed as needed. Avoid cherry-picking commits that have not been vetted in the release candidate phase at this point.
Once you are sure that the release is solid, perform the following steps. Note that they're similar to the steps you may have followed earlier when patching the release candidate, but we're not cherry-picking any additional commits at this point.
Once you are sure that the release is solid, perform the following steps. Note that they're similar to the steps you may have followed earlier when patching the release candidate, but we're not cherry-picking any additional commits at this point.
### Step 1: Check out the release branch
```bash
git checkout <version_you_are_patching>-stable
# e.g. git checkout 0.50-stable
# e.g. git checkout 0.57-stable
git pull origin <version_you_are_patching>-stable
# e.g. git pull origin 0.50-stable
# e.g. git pull origin 0.57-stable
```
> If you don't have a local checkout of the release branch, you can run the following instead:
@@ -206,28 +192,18 @@ If everything worked:
```bash
./scripts/bump-oss-version.js <exact_version_you_are_releasing>
# e.g. ./scripts/bump-oss-version.js 0.50.0
# e.g. ./scripts/bump-oss-version.js 0.57.0
```
### Step 4: Push to GitHub
As with the release candidate, Circle CI will automatically run the tests and publish to npm with the version you have specified (e.g `0.57.0`).
Finally, push the new tags and commits to GitHub:
```
git push --tags
git push
```
As with the release candidate, Circle CI will automatically run the tests and publish to npm with the version you have specified (e.g `0.50.0`).
Go to [Circle CI](https://circleci.com/gh/facebook/react-native) and look for the build triggered by your push (e.g. _0.50-stable, [0.50.0] Bump version numbers_), then scroll down to the npm publish step to verify the package was published successfully (the build will be red if not).
Go to [Circle CI](https://circleci.com/gh/facebook/react-native) and look for the build triggered by your push (e.g. _0.57-stable, [0.57.0] Bump version numbers_), then scroll down to the npm publish step to verify the package was published successfully (the build will be red if not).
This will now become the latest release, and will be installed by users by default. At this point, the website will be updated and the docs for this release will be displayed by default.
### Step 5: Update the release notes
### Step 4: Update the release notes
Once you see that the website is displaying the version that you have just created, you will need to update the release notes. Move the release notes from the release candidate, to the tag that you've just created. We want single release notes per version. For example, if there is v0.50.0-rc and later we release v0.50.0, the release notes should live on v0.50.0:
https://github.com/facebook/react-native/tags
Go to https://github.com/facebook/react-native/releases and find the release notes for this release candidate. Edit them so that they now point to the tag that you've just created. We want single release notes per version. For example, if there is v0.57.0 and you just released v0.57.1, the release notes should live on the v0.57.1 tag at https://github.com/facebook/react-native/tags
For non-RC releases: Uncheck the box "This is a pre-release" and publish the notes.
+2 -2
View File
@@ -13,8 +13,8 @@ buildscript {
}
}
dependencies {
classpath 'com.android.tools.build:gradle:2.2.2'
classpath 'de.undercouch:gradle-download-task:3.1.2'
classpath 'com.android.tools.build:gradle:2.3.3'
classpath 'de.undercouch:gradle-download-task:3.4.3'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
+529 -65
View File
@@ -4,30 +4,124 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* Modified from https://raw.githubusercontent.com/flowtype/flow-typed/e3b0f3034929e0f0fb85c790450a201b380ac2fd/definitions/npm/jest_v17.x.x/flow_v0.33.x-/jest_v17.x.x.js
* Modified from https://raw.githubusercontent.com/flowtype/flow-typed/b43dff3e0ed5ccf7033839045f4819e8db40faa9/definitions/npm/jest_v20.x.x/flow_v0.22.x-/jest_v20.x.x.js
* Duplicated from www/flow/shared/jest.js
* List of modifications:
* - added function fail
* - added jest.requireActual
* - added jest.requireMock
* - added JestMockFn.mockName
* - added JestMockFn.mockRejectedValue
* - added JestMockFn.mockRejectedValueOnce
* - added JestMockFn.mockResolvedValue
* - added JestMockFn.mockResolvedValueOnce
* - added JestMockFn.mock.thrownErrors
* - added JestMockFn.mock.returnValues
* - added jest.setTimeout
* @flow
* @format
*/
'use strict';
/* eslint-disable lint/no-unclear-flowtypes */
type JestMockFn = {
(...args: Array<any>): any,
type JestMockFn<TArguments: $ReadOnlyArray<*>, TReturn> = {
(...args: TArguments): TReturn,
/**
* An object for introspecting mock calls
*/
mock: {
calls: Array<Array<any>>,
instances: mixed,
/**
* An array that represents all calls that have been made into this mock
* function. Each call is represented by an array of arguments that were
* passed during the call.
*/
calls: Array<TArguments>,
/**
* An array that contains all the object instances that have been
* instantiated from this mock function.
*/
instances: Array<TReturn>,
/**
* An array containing the results of a method, and whether they were
* returned or thrown.
*/
results: Array<{isThrown: boolean}>,
},
mockClear(): Function,
mockReset(): Function,
mockImplementation(fn: Function): JestMockFn,
mockImplementationOnce(fn: Function): JestMockFn,
/**
* Resets all information stored in the mockFn.mock.calls and
* mockFn.mock.instances arrays. Often this is useful when you want to clean
* up a mock's usage data between two assertions.
*/
mockClear(): void,
/**
* Resets all information stored in the mock. This is useful when you want to
* completely restore a mock back to its initial state.
*/
mockReset(): void,
/**
* Removes the mock and restores the initial implementation. This is useful
* when you want to mock functions in certain test cases and restore the
* original implementation in others. Beware that mockFn.mockRestore only
* works when mock was created with jest.spyOn. Thus you have to take care of
* restoration yourself when manually assigning jest.fn().
*/
mockRestore(): void,
/**
* Accepts a function that should be used as the implementation of the mock.
* The mock itself will still record all calls that go into and instances
* that come from itself -- the only difference is that the implementation
* will also be executed when the mock is called.
*/
mockImplementation(
fn: (...args: TArguments) => TReturn,
): JestMockFn<TArguments, TReturn>,
/**
* Accepts a function that will be used as an implementation of the mock for
* one call to the mocked function. Can be chained so that multiple function
* calls produce different results.
*/
mockImplementationOnce(
fn: (...args: TArguments) => TReturn,
): JestMockFn<TArguments, TReturn>,
/**
* Accepts a string to use in test result output in place of "jest.fn()" to
* indicate which mock function is being referenced.
*/
mockName(name: string): JestMockFn<TArguments, TReturn>,
/**
* Sugar for: jest.fn().mockReturnValue(Promise.reject(value));
*/
mockRejectedValue(value: TReturn): JestMockFn<TArguments, TReturn>,
/**
* Sugar for: jest.fn().mockReturnValueOnce(Promise.reject(value));
*/
mockRejectedValueOnce(value: TReturn): JestMockFn<TArguments, TReturn>,
/**
* Sugar for: jest.fn().mockReturnValue(Promise.resolve(value));
*/
mockResolvedValue(value: TReturn): JestMockFn<TArguments, TReturn>,
/**
* Sugar for: jest.fn().mockReturnValueOnce(Promise.resolve(value));
*/
mockResolvedValueOnce(value: TReturn): JestMockFn<TArguments, TReturn>,
/**
* Just a simple sugar function for returning `this`
*/
mockReturnThis(): void,
mockReturnValue(value: any): JestMockFn,
mockReturnValueOnce(value: any): JestMockFn,
/**
* Deprecated: use jest.fn(() => value) instead
*/
mockReturnValue(value: TReturn): JestMockFn<TArguments, TReturn>,
/**
* Sugar for only returning a value once inside your mock
*/
mockReturnValueOnce(value: TReturn): JestMockFn<TArguments, TReturn>,
};
type JestAsymmetricEqualityType = {
/**
* A custom Jasmine equality tester
*/
asymmetricMatch(value: mixed): boolean,
};
@@ -44,7 +138,7 @@ type JestCallsType = {
type JestClockType = {
install(): void,
mockDate(date: Date): void,
tick(): void,
tick(milliseconds?: number): void,
uninstall(): void,
};
@@ -68,105 +162,471 @@ type JestPromiseType = {
resolves: JestExpectType,
};
/**
* Plugin: jest-enzyme
*/
type EnzymeMatchersType = {
toBeChecked(): void,
toBeDisabled(): void,
toBeEmpty(): void,
toBePresent(): void,
toContainReact(element: React$Element<any>): void,
toHaveClassName(className: string): void,
toHaveHTML(html: string): void,
toHaveProp(propKey: string, propValue?: any): void,
toHaveRef(refName: string): void,
toHaveState(stateKey: string, stateValue?: any): void,
toHaveStyle(styleKey: string, styleValue?: any): void,
toHaveTagName(tagName: string): void,
toHaveText(text: string): void,
toIncludeText(text: string): void,
toHaveValue(value: any): void,
toMatchElement(element: React$Element<any>): void,
toMatchSelector(selector: string): void,
};
type JestExpectType = {
not: JestExpectType,
not: JestExpectType & EnzymeMatchersType,
/**
* If you have a mock function, you can use .lastCalledWith to test what
* arguments it was last called with.
*/
lastCalledWith(...args: Array<any>): void,
/**
* toBe just checks that a value is what you expect. It uses === to check
* strict equality.
*/
toBe(value: any): void,
/**
* Use .toHaveBeenCalled to ensure that a mock function got called.
*/
toBeCalled(): void,
/**
* Use .toBeCalledWith to ensure that a mock function was called with
* specific arguments.
*/
toBeCalledWith(...args: Array<any>): void,
/**
* Using exact equality with floating point numbers is a bad idea. Rounding
* means that intuitive things fail.
*/
toBeCloseTo(num: number, delta: any): void,
/**
* Use .toBeDefined to check that a variable is not undefined.
*/
toBeDefined(): void,
/**
* Use .toBeFalsy when you don't care what a value is, you just want to
* ensure a value is false in a boolean context.
*/
toBeFalsy(): void,
/**
* To compare floating point numbers, you can use toBeGreaterThan.
*/
toBeGreaterThan(number: number): void,
/**
* To compare floating point numbers, you can use toBeGreaterThanOrEqual.
*/
toBeGreaterThanOrEqual(number: number): void,
/**
* To compare floating point numbers, you can use toBeLessThan.
*/
toBeLessThan(number: number): void,
/**
* To compare floating point numbers, you can use toBeLessThanOrEqual.
*/
toBeLessThanOrEqual(number: number): void,
/**
* Use .toBeInstanceOf(Class) to check that an object is an instance of a
* class.
*/
toBeInstanceOf(cls: Class<*>): void,
/**
* .toBeNull() is the same as .toBe(null) but the error messages are a bit
* nicer.
*/
toBeNull(): void,
/**
* Use .toBeTruthy when you don't care what a value is, you just want to
* ensure a value is true in a boolean context.
*/
toBeTruthy(): void,
/**
* Use .toBeUndefined to check that a variable is undefined.
*/
toBeUndefined(): void,
/**
* Use .toContain when you want to check that an item is in a list. For
* testing the items in the list, this uses ===, a strict equality check.
*/
toContain(item: any): void,
/**
* Use .toContainEqual when you want to check that an item is in a list. For
* testing the items in the list, this matcher recursively checks the
* equality of all fields, rather than checking for object identity.
*/
toContainEqual(item: any): void,
/**
* Use .toEqual when you want to check that two objects have the same value.
* This matcher recursively checks the equality of all fields, rather than
* checking for object identity.
*/
toEqual(value: any): void,
/**
* Use .toHaveBeenCalled to ensure that a mock function got called.
*/
toHaveBeenCalled(): void,
/**
* Use .toHaveBeenCalledTimes to ensure that a mock function got called exact
* number of times.
*/
toHaveBeenCalledTimes(number: number): void,
/**
* Use .toHaveBeenCalledWith to ensure that a mock function was called with
* specific arguments.
*/
toHaveBeenCalledWith(...args: Array<any>): void,
toHaveProperty(path: string, value?: any): void,
toMatch(regexp: RegExp): void,
/**
* Use .toHaveBeenLastCalledWith to ensure that a mock function was last called
* with specific arguments.
*/
toHaveBeenLastCalledWith(...args: Array<any>): void,
/**
* Check that an object has a .length property and it is set to a certain
* numeric value.
*/
toHaveLength(number: number): void,
/**
*
*/
toHaveProperty(propPath: string, value?: any): void,
/**
* Use .toMatch to check that a string matches a regular expression or string.
*/
toMatch(regexpOrString: RegExp | string): void,
/**
* Use .toMatchObject to check that a javascript object matches a subset of the properties of an object.
*/
toMatchObject(object: Object): void,
toMatchSnapshot(): void,
toThrow(message?: string | Error | Class<Error>): void,
toThrowError(message?: string | Error | Class<Error> | RegExp): void,
/**
* This ensures that a React component matches the most recent snapshot.
*/
toMatchSnapshot(name?: string): void,
/**
* Use .toThrow to test that a function throws when it is called.
* If you want to test that a specific error gets thrown, you can provide an
* argument to toThrow. The argument can be a string for the error message,
* a class for the error, or a regex that should match the error.
*
* Alias: .toThrowError
*/
toThrow(message?: string | Error | RegExp): void,
toThrowError(message?: string | Error | RegExp): void,
/**
* Use .toThrowErrorMatchingSnapshot to test that a function throws a error
* matching the most recent snapshot when it is called.
*/
toThrowErrorMatchingSnapshot(): void,
};
type JestObjectType = {
/**
* Disables automatic mocking in the module loader.
*
* After this method is called, all `require()`s will return the real
* versions of each module (rather than a mocked version).
*/
disableAutomock(): JestObjectType,
/**
* An un-hoisted version of disableAutomock
*/
autoMockOff(): JestObjectType,
/**
* Enables automatic mocking in the module loader.
*/
enableAutomock(): JestObjectType,
/**
* An un-hoisted version of enableAutomock
*/
autoMockOn(): JestObjectType,
/**
* Clears the mock.calls and mock.instances properties of all mocks.
* Equivalent to calling .mockClear() on every mocked function.
*/
clearAllMocks(): JestObjectType,
/**
* Resets the state of all mocks. Equivalent to calling .mockReset() on every
* mocked function.
*/
resetAllMocks(): JestObjectType,
/**
* Restores all mocks back to their original value.
*/
restoreAllMocks(): JestObjectType,
/**
* Removes any pending timers from the timer system.
*/
clearAllTimers(): void,
/**
* The same as `mock` but not moved to the top of the expectation by
* babel-jest.
*/
doMock(moduleName: string, moduleFactory?: any): JestObjectType,
/**
* The same as `unmock` but not moved to the top of the expectation by
* babel-jest.
*/
dontMock(moduleName: string): JestObjectType,
/**
* Returns a new, unused mock function. Optionally takes a mock
* implementation.
*/
fn<TArguments: $ReadOnlyArray<*>, TReturn>(
implementation?: (...args: TArguments) => TReturn,
): JestMockFn<TArguments, TReturn>,
/**
* Determines if the given function is a mocked function.
*/
isMockFunction(fn: Function): boolean,
/**
* Given the name of a module, use the automatic mocking system to generate a
* mocked version of the module for you.
*/
genMockFromModule(moduleName: string): any,
/**
* Mocks a module with an auto-mocked version when it is being required.
*
* The second argument can be used to specify an explicit module factory that
* is being run instead of using Jest's automocking feature.
*
* The third argument can be used to create virtual mocks -- mocks of modules
* that don't exist anywhere in the system.
*/
mock(
moduleName: string,
moduleFactory?: any,
options?: Object,
): JestObjectType,
/**
* Resets the module registry - the cache of all required modules. This is
* useful to isolate modules where local state might conflict between tests.
*/
resetModules(): JestObjectType,
/**
* Exhausts the micro-task queue (usually interfaced in node via
* process.nextTick).
*/
runAllTicks(): void,
/**
* Exhausts the macro-task queue (i.e., all tasks queued by setTimeout(),
* setInterval(), and setImmediate()).
*/
runAllTimers(): void,
/**
* Exhausts all tasks queued by setImmediate().
*/
runAllImmediates(): void,
/**
* Executes only the macro task queue (i.e. all tasks queued by setTimeout()
* or setInterval() and setImmediate()).
*/
advanceTimersByTime(msToRun: number): void,
/**
* Executes only the macro task queue (i.e. all tasks queued by setTimeout()
* or setInterval() and setImmediate()).
*
* Renamed to `advanceTimersByTime`.
*/
runTimersToTime(msToRun: number): void,
/**
* Executes only the macro-tasks that are currently pending (i.e., only the
* tasks that have been queued by setTimeout() or setInterval() up to this
* point)
*/
runOnlyPendingTimers(): void,
/**
* Explicitly supplies the mock object that the module system should return
* for the specified module. Note: It is recommended to use jest.mock()
* instead.
*/
setMock(moduleName: string, moduleExports: any): JestObjectType,
/**
* Indicates that the module system should never return a mocked version of
* the specified module from require() (e.g. that it should always return the
* real module).
*/
unmock(moduleName: string): JestObjectType,
/**
* Instructs Jest to use fake versions of the standard timer functions
* (setTimeout, setInterval, clearTimeout, clearInterval, nextTick,
* setImmediate and clearImmediate).
*/
useFakeTimers(): JestObjectType,
/**
* Instructs Jest to use the real versions of the standard timer functions.
*/
useRealTimers(): JestObjectType,
/**
* Creates a mock function similar to jest.fn but also tracks calls to
* object[methodName].
*/
spyOn(object: Object, methodName: string): JestMockFn<any, any>,
/**
* Set the default timeout interval for tests and before/after hooks in milliseconds.
* Note: The default timeout interval is 5 seconds if this method is not called.
*/
setTimeout(timeout: number): JestObjectType,
// These methods are added separately and not a part of flow-typed OSS
// version of this file. They were added in jest@21.0.0.alpha-2 which is not
// yet publicly released yet.
// TODO T21262347 Add them to OSS version of flow-typed
requireActual(module: string): any,
requireMock(module: string): any,
};
type JestSpyType = {
calls: JestCallsType,
};
declare function afterEach(fn: Function): void;
declare function beforeEach(fn: Function): void;
declare function afterAll(fn: Function): void;
declare function beforeAll(fn: Function): void;
declare function describe(name: string, fn: Function): void;
declare var it: {
(name: string, fn: Function): ?Promise<void>,
only(name: string, fn: Function): ?Promise<void>,
skip(name: string, fn: Function): ?Promise<void>,
/** Runs this function after every test inside this context */
declare function afterEach(
fn: (done: () => void) => ?Promise<mixed>,
timeout?: number,
): void;
/** Runs this function before every test inside this context */
declare function beforeEach(
fn: (done: () => void) => ?Promise<mixed>,
timeout?: number,
): void;
/** Runs this function after all tests have finished inside this context */
declare function afterAll(
fn: (done: () => void) => ?Promise<mixed>,
timeout?: number,
): void;
/** Runs this function before any tests have started inside this context */
declare function beforeAll(
fn: (done: () => void) => ?Promise<mixed>,
timeout?: number,
): void;
/** A context for grouping tests together */
declare var describe: {
/**
* Creates a block that groups together several related tests in one "test suite"
*/
(name: string, fn: () => void): void,
/**
* Only run this describe block
*/
only(name: string, fn: () => void): void,
/**
* Skip running this describe block
*/
skip(name: string, fn: () => void): void,
};
declare function fit(name: string, fn: Function): ?Promise<void>;
declare function pit(name: string, fn: () => Promise<any>): Promise<void>;
/** An individual test unit */
declare var it: {
/**
* An individual test unit
*
* @param {string} Name of Test
* @param {Function} Test
* @param {number} Timeout for the test, in milliseconds.
*/
(
name: string,
fn?: (done: () => void) => ?Promise<mixed>,
timeout?: number,
): void,
/**
* Only run this test
*
* @param {string} Name of Test
* @param {Function} Test
* @param {number} Timeout for the test, in milliseconds.
*/
only(
name: string,
fn?: (done: () => void) => ?Promise<mixed>,
timeout?: number,
): void,
/**
* Skip running this test
*
* @param {string} Name of Test
* @param {Function} Test
* @param {number} Timeout for the test, in milliseconds.
*/
skip(
name: string,
fn?: (done: () => void) => ?Promise<mixed>,
timeout?: number,
): void,
/**
* Run the test concurrently
*
* @param {string} Name of Test
* @param {Function} Test
* @param {number} Timeout for the test, in milliseconds.
*/
concurrent(
name: string,
fn?: (done: () => void) => ?Promise<mixed>,
timeout?: number,
): void,
};
declare function fit(
name: string,
fn: (done: () => void) => ?Promise<mixed>,
timeout?: number,
): void;
/** An individual test unit */
declare var test: typeof it;
/** A disabled group of tests */
declare var xdescribe: typeof describe;
/** A focused group of tests */
declare var fdescribe: typeof describe;
/** A disabled individual test */
declare var xit: typeof it;
/** A disabled individual test */
declare var xtest: typeof it;
/** The expect function is used every time you want to test a value */
declare var expect: {
(value: any): JestExpectType & JestPromiseType,
any: any,
/** The object that you want to make assertions against */
(value: any): JestExpectType & JestPromiseType & EnzymeMatchersType,
/** Add additional Jasmine matchers to Jest's roster */
extend(matchers: {[name: string]: JestMatcher}): void,
objectContaining(any): void,
/** Add a module that formats application-specific data structures. */
addSnapshotSerializer(serializer: (input: Object) => string): void,
assertions(expectedAssertions: number): void,
hasAssertions(): void,
any(value: mixed): JestAsymmetricEqualityType,
anything(): void,
arrayContaining(value: Array<mixed>): void,
objectContaining(value: Object): void,
/** Matches any received string that contains the exact expected string. */
stringContaining(value: string): void,
stringMatching(value: string | RegExp): void,
};
declare function fail(message?: string): void;
// TODO handle return type
// http://jasmine.github.io/2.4/introduction.html#section-Spies
declare function spyOn(value: mixed, method: string): Object;
type Jest = {
autoMockOff(): Jest,
autoMockOn(): Jest,
resetAllMocks(): Jest,
clearAllTimers(): void,
currentTestPath(): void,
disableAutomock(): Jest,
doMock(moduleName: string, moduleFactory?: any): void,
dontMock(moduleName: string): Jest,
enableAutomock(): Jest,
fn(implementation?: Function): JestMockFn,
genMockFromModule(moduleName: string): any,
isMockFunction(fn: Function): boolean,
mock(
moduleName: string,
moduleFactory?: any,
options?: {virtual?: boolean},
): Jest,
resetModuleRegistry(): Jest, // undocumented alias for resetModuleRegistry
resetModules(): Jest,
restoreAllMocks(): Jest,
runAllTicks(): Jest,
runAllTimers(): Jest,
runTimersToTime(msToRun: number): Jest,
runOnlyPendingTimers(): Jest,
setMock(moduleName: string, moduleExports: any): Jest,
unmock(moduleName: string): Jest,
useFakeTimers(): Jest,
useRealTimers(): Jest,
};
declare var jest: Jest;
/** Holds all functions related to manipulating test runner */
declare var jest: JestObjectType;
/**
* The global Jamine object, this is generally not exposed as the public API,
* using features inside here could break in later versions of Jest.
*/
declare var jasmine: {
DEFAULT_TIMEOUT_INTERVAL: number,
any(value: mixed): JestAsymmetricEqualityType,
@@ -174,6 +634,10 @@ declare var jasmine: {
arrayContaining(value: Array<mixed>): void,
clock(): JestClockType,
createSpy(name: string): JestSpyType,
createSpyObj(
baseName: string,
methodNames: Array<string>,
): {[methodName: string]: JestSpyType},
objectContaining(value: Object): void,
stringMatching(value: string): void,
};
+1 -1
View File
@@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-2.14.1-all.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-3.5.1-all.zip
+8 -4
View File
@@ -12,7 +12,10 @@
const path = require('path');
const ROOT = path.join(__dirname, '..');
const ROOTS = [
path.resolve(__dirname, '..') + path.sep,
path.resolve(__dirname, '../../react-native-windows') + path.sep,
];
const BLACKLISTED_PATTERNS /*: Array<RegExp> */ = [
/.*\/__(mocks|tests)__\/.*/,
@@ -33,7 +36,7 @@ const NAME_REDUCERS /*: Array<[RegExp, string]> */ = [
// strip .js/.js.flow suffix
[/^(.*)\.js(\.flow)?$/, '$1'],
// strip .android/.ios/.native/.web suffix
[/^(.*)\.(android|ios|native|web)$/, '$1'],
[/^(.*)\.(android|ios|native|web|windows)$/, '$1'],
];
const haste = {
@@ -63,11 +66,12 @@ function isHastePath(filePath /*: string */) /*: boolean */ {
return false;
}
if (!filePath.startsWith(ROOT)) {
const root = ROOTS.find(r => filePath.startsWith(r));
if (!root) {
return false;
}
filePath = filePath.substr(ROOT.length + 1);
filePath = filePath.substr(root.length);
if (BLACKLISTED_PATTERNS.some(pattern => pattern.test(filePath))) {
return false;
}
+8
View File
@@ -72,6 +72,14 @@ const pluginPlatforms = plugins.platforms.reduce((acc, pathToPlatforms) => {
const defaultRNConfig = {
hasteImplModulePath: require.resolve('../../jest/hasteImpl'),
getPlatforms(): Array<string> {
return ['ios', 'android', 'windows', 'web'];
},
getProvidesModuleNodeModules(): Array<string> {
return ['react-native', 'react-native-windows'];
},
getProjectCommands(): Array<CommandT> {
const commands = plugins.commands.map(pathToCommands => {
const name = pathToCommands.split(path.sep)[0];
@@ -1,5 +1,5 @@
dependencies {
compile fileTree(dir: "libs", include: ["*.jar"])
compile "com.android.support:appcompat-v7:23.0.1"
compile "com.facebook.react:react-native:0.18.+"
compile "com.android.support:appcompat-v7:26.1.0"
compile "com.facebook.react:react-native:+"
}
@@ -4,6 +4,6 @@ dependencies {
exclude(group: 'org.unwanted', module: 'test10')
}
compile fileTree(dir: "libs", include: ["*.jar"])
compile "com.android.support:appcompat-v7:23.0.1"
compile "com.facebook.react:react-native:0.18.+"
compile "com.android.support:appcompat-v7:26.1.0"
compile "com.facebook.react:react-native:+"
}
+4 -1
View File
@@ -160,8 +160,11 @@ function runOnSimulator(xcodeProject, args, scheme) {
* it will not boot the "default" device, but the one we set. If the app is already running,
* this flag has no effect.
*/
const activeDeveloperDir = child_process
.execFileSync('xcode-select', ['-p'], {encoding: 'utf8'})
.trim();
child_process.execFileSync('open', [
'/Applications/Xcode.app/Contents/Developer/Applications/Simulator.app',
`${activeDeveloperDir}/Applications/Simulator.app`,
'--args',
'-CurrentDeviceUDID',
selectedSimulator.udid,
+14 -1
View File
@@ -30,6 +30,19 @@ node_modules/react-native/flow-github/
emoji=true
module.system=haste
module.system.haste.use_name_reducers=true
# 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 .ios suffix
module.system.haste.name_reducers='^\(.*\)\.ios$' -> '\1'
module.system.haste.name_reducers='^\(.*\)\.android$' -> '\1'
module.system.haste.name_reducers='^\(.*\)\.native$' -> '\1'
module.system.haste.paths.blacklist=.*/__tests__/.*
module.system.haste.paths.blacklist=.*/__mocks__/.*
module.system.haste.paths.blacklist=<PROJECT_ROOT>/node_modules/react-native/Libraries/Animated/src/polyfills/.*
module.system.haste.paths.whitelist=<PROJECT_ROOT>/node_modules/react-native/Libraries/.*
munge_underscores=true
@@ -51,4 +64,4 @@ suppress_comment=\\(.\\|\n\\)*\\$FlowFixedInNextDeploy
suppress_comment=\\(.\\|\n\\)*\\$FlowExpectedError
[version]
^0.74.0
^0.75.0
@@ -94,13 +94,13 @@ def enableSeparateBuildPerCPUArchitecture = false
def enableProguardInReleaseBuilds = false
android {
compileSdkVersion 23
buildToolsVersion "23.0.1"
compileSdkVersion rootProject.ext.compileSdkVersion
buildToolsVersion rootProject.ext.buildToolsVersion
defaultConfig {
applicationId "com.helloworld"
minSdkVersion 16
targetSdkVersion 22
minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion
versionCode 1
versionName "1.0"
ndk {
@@ -138,7 +138,7 @@ android {
dependencies {
compile fileTree(dir: "libs", include: ["*.jar"])
compile "com.android.support:appcompat-v7:23.0.1"
compile "com.android.support:appcompat-v7:${rootProject.ext.supportLibVersion}"
compile "com.facebook.react:react-native:+" // From node_modules
}
@@ -3,9 +3,13 @@
buildscript {
repositories {
jcenter()
maven {
url 'https://maven.google.com/'
name 'Google'
}
}
dependencies {
classpath 'com.android.tools.build:gradle:2.2.3'
classpath 'com.android.tools.build:gradle:2.3.3'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
@@ -20,5 +24,17 @@ allprojects {
// All of React Native (JS, Obj-C sources, Android binaries) is installed from npm
url "$rootDir/../node_modules/react-native/android"
}
maven {
url 'https://maven.google.com/'
name 'Google'
}
}
}
ext {
buildToolsVersion = "26.0.3"
minSdkVersion = 16
compileSdkVersion = 26
targetSdkVersion = 26
supportLibVersion = "26.1.0"
}
@@ -2,4 +2,4 @@ distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-2.14.1-all.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-3.5.1-all.zip
+9 -9
View File
@@ -1,6 +1,6 @@
{
"name": "react-native",
"version": "1000.0.0",
"version": "0.56.1",
"description": "A framework for building native apps using React",
"license": "MIT",
"repository": {
@@ -143,7 +143,7 @@
"react-native": "local-cli/wrong-react-native.js"
},
"peerDependencies": {
"react": "16.3.2"
"react": "16.4.1"
},
"dependencies": {
"absolute-path": "^0.0.0",
@@ -212,13 +212,13 @@
"eslint-plugin-prettier": "2.6.0",
"eslint-plugin-react": "7.8.2",
"eslint-plugin-react-native": "^3.2.1",
"flow-bin": "^0.74.0",
"jest": "23.1.0",
"jest-junit": "4.0.0",
"prettier": "1.13.4",
"react": "16.3.2",
"react-test-renderer": "16.3.2",
"flow-bin": "^0.75.0",
"jest": "23.2.0",
"jest-junit": "5.1.0",
"prettier": "1.13.6",
"react": "16.4.1",
"react-test-renderer": "16.4.1",
"shelljs": "^0.7.8",
"sinon": "^2.2.0"
}
}
}
+2 -2
View File
@@ -4,9 +4,9 @@
## ANDROID ##
# Android SDK Build Tools revision
export ANDROID_SDK_BUILD_TOOLS_REVISION=23.0.1
export ANDROID_SDK_BUILD_TOOLS_REVISION=26.0.3
# Android API Level we build with
export ANDROID_SDK_BUILD_API_LEVEL="23"
export ANDROID_SDK_BUILD_API_LEVEL="26"
# Google APIs for Android level
export ANDROID_GOOGLE_API_LEVEL="23"
# Minimum Android API Level we target
+12 -1
View File
@@ -2,7 +2,18 @@
set -e
PLATFORM_NAME="${PLATFORM_NAME:-iphoneos}"
CURRENT_ARCH="${CURRENT_ARCH:-armv7}"
CURRENT_ARCH="${CURRENT_ARCH}"
if [ -z "$CURRENT_ARCH" ] || [ "$CURRENT_ARCH" == "undefined_arch" ]; then
# Xcode 10 beta sets CURRENT_ARCH to "undefined_arch", this leads to incorrect linker arg.
# it's better to rely on platform name as fallback because architecture differs between simulator and device
if [[ "$PLATFORM_NAME" == *"simulator"* ]]; then
CURRENT_ARCH="x86_64"
else
CURRENT_ARCH="armv7"
fi
fi
export CC="$(xcrun -find -sdk $PLATFORM_NAME cc) -arch $CURRENT_ARCH -isysroot $(xcrun -sdk $PLATFORM_NAME --show-sdk-path)"
export CXX="$CC"